include/vcl/outdev.hxx | 1 vcl/inc/ImplLayoutArgs.hxx | 4 ++- vcl/inc/sallayout.hxx | 3 +- vcl/source/gdi/CommonSalLayout.cxx | 14 ++++++----- vcl/source/outdev/map.cxx | 8 ++++++ vcl/source/outdev/text.cxx | 47 ++++++++++++++++++++++++++----------- vcl/source/text/ImplLayoutArgs.cxx | 6 ++++ 7 files changed, 62 insertions(+), 21 deletions(-)
New commits: commit bb830461f0c22f7efe10de799a6a39b56cc5b4a5 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Thu Jan 13 12:12:51 2022 +0000 Commit: Caolán McNamara <caol...@redhat.com> CommitDate: Thu Jan 13 18:32:28 2022 +0100 keep scaled ResolutionIndependentLayout glyph positions as floating point When rendering in ResolutionIndependentLayout mode keep the scaled glyph positions as floating point all the way down to the renderer Change-Id: I02415f18c26737a886751972f472b499a25c776b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128379 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index ddeafe9f8599..0282ea8458b5 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -1699,6 +1699,7 @@ public: SAL_DLLPRIVATE tools::Long ImplLogicWidthToDevicePixel( tools::Long nWidth ) const; SAL_DLLPRIVATE DeviceCoordinate LogicWidthToDeviceCoordinate( tools::Long nWidth ) const; + SAL_DLLPRIVATE double LogicWidthToDeviceFontCoordinate( tools::Long nWidth ) const; /** Convert a logical X coordinate to a device pixel's X coordinate. diff --git a/vcl/inc/ImplLayoutArgs.hxx b/vcl/inc/ImplLayoutArgs.hxx index 865470b7897a..fa5e8005ba00 100644 --- a/vcl/inc/ImplLayoutArgs.hxx +++ b/vcl/inc/ImplLayoutArgs.hxx @@ -35,7 +35,8 @@ public: vcl::text::TextLayoutCache const* m_pTextLayoutCache; // positioning related inputs - const DeviceCoordinate* mpDXArray; // in pixel units + const DeviceCoordinate* mpDXArray; // in integer pixel units + const double* mpAltNaturalDXArray; // in floating point pixel units DeviceCoordinate mnLayoutWidth; // in pixel units Degree10 mnOrientation; // in 0-3600 system @@ -48,6 +49,7 @@ public: void SetLayoutWidth(DeviceCoordinate nWidth); void SetDXArray(const DeviceCoordinate* pDXArray); + void SetAltNaturalDXArray(const double* pDXArray); void SetOrientation(Degree10 nOrientation); void ResetPos(); diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx index acd49edfda30..f5ffd0f2e587 100644 --- a/vcl/inc/sallayout.hxx +++ b/vcl/inc/sallayout.hxx @@ -136,7 +136,8 @@ private: GenericSalLayout( const GenericSalLayout& ) = delete; GenericSalLayout& operator=( const GenericSalLayout& ) = delete; - void ApplyDXArray(const DeviceCoordinate*, SalLayoutFlags nLayoutFlags); + template<typename DC> + void ApplyDXArray(const DC*, SalLayoutFlags nLayoutFlags); void Justify(DeviceCoordinate nNewWidth); void ApplyAsianKerning(const OUString& rStr); diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index f1cbb149dd33..811849309d67 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -197,7 +197,9 @@ void GenericSalLayout::AdjustLayout(vcl::text::ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); - if (rArgs.mpDXArray) + if (rArgs.mpAltNaturalDXArray) // Used when "TextRenderModeForResolutionIndependentLayout" is set + ApplyDXArray(rArgs.mpAltNaturalDXArray, rArgs.mnFlags); + else if (rArgs.mpDXArray) // Normal case ApplyDXArray(rArgs.mpDXArray, rArgs.mnFlags); else if (rArgs.mnLayoutWidth) Justify(rArgs.mnLayoutWidth); @@ -635,12 +637,12 @@ void GenericSalLayout::GetCharWidths(std::vector<DeviceCoordinate>& rCharWidths) // * Check the above flag to decide whether to insert Kashidas or not. // * For any RTL glyph that has DX adjustment, insert enough Kashidas to // fill in the added space. - -void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutFlags nLayoutFlags) +template<typename DC> +void GenericSalLayout::ApplyDXArray(const DC* pDXArray, SalLayoutFlags nLayoutFlags) { int nCharCount = mnEndCharPos - mnMinCharPos; std::vector<DeviceCoordinate> aOldCharWidths; - std::unique_ptr<DeviceCoordinate[]> const pNewCharWidths(new DeviceCoordinate[nCharCount]); + std::unique_ptr<DC[]> const pNewCharWidths(new DC[nCharCount]); // Get the natural character widths (i.e. before applying DX adjustments). GetCharWidths(aOldCharWidths); @@ -671,7 +673,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF std::map<size_t, DeviceCoordinate> pKashidas; // The accumulated difference in X position. - DeviceCoordinate nDelta = 0; + DC nDelta = 0; // Apply the DX adjustments to glyph positions and widths. size_t i = 0; @@ -680,7 +682,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF // Accumulate the width difference for all characters corresponding to // this glyph. int nCharPos = m_GlyphItems[i].charPos() - mnMinCharPos; - DeviceCoordinate nDiff = 0; + DC nDiff = 0; for (int j = 0; j < m_GlyphItems[i].charCount(); j++) nDiff += pNewCharWidths[nCharPos + j] - aOldCharWidths[nCharPos + j]; diff --git a/vcl/source/outdev/map.cxx b/vcl/source/outdev/map.cxx index 73badc74bcfc..f98ff3057b6f 100644 --- a/vcl/source/outdev/map.cxx +++ b/vcl/source/outdev/map.cxx @@ -1830,4 +1830,12 @@ DeviceCoordinate OutputDevice::LogicWidthToDeviceCoordinate( tools::Long nWidth #endif } +double OutputDevice::LogicWidthToDeviceFontCoordinate(tools::Long nWidth) const +{ + if (!mbMap) + return nWidth; + + return ImplLogicToPixel(static_cast<double>(nWidth), mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx index 916bff7cab2d..de196499a81f 100644 --- a/vcl/source/outdev/text.cxx +++ b/vcl/source/outdev/text.cxx @@ -1341,21 +1341,41 @@ std::unique_ptr<SalLayout> OutputDevice::ImplLayout(const OUString& rOrigStr, vcl::text::ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, flags, pLayoutCache); + DeviceCoordinate nEndGlyphCoord(0); std::unique_ptr<DeviceCoordinate[]> xDXPixelArray; - DeviceCoordinate* pDXPixelArray(nullptr); + std::unique_ptr<double[]> xNaturalDXPixelArray; if( !pDXArray.empty() ) { - if(mbMap) + DeviceCoordinate* pDXPixelArray(nullptr); + if (mbMap) { - // convert from logical units to font units using a temporary array - xDXPixelArray.reset(new DeviceCoordinate[nLen]); - pDXPixelArray = xDXPixelArray.get(); - // using base position for better rounding a.k.a. "dancing characters" - DeviceCoordinate nPixelXOfs2 = LogicWidthToDeviceCoordinate(rLogicalPos.X() * 2); - for( int i = 0; i < nLen; ++i ) + if (GetTextRenderModeForResolutionIndependentLayout()) { - pDXPixelArray[i] = (LogicWidthToDeviceCoordinate((rLogicalPos.X() + pDXArray[i]) * 2) - nPixelXOfs2) / 2; + // convert from logical units to font units using a temporary array + xNaturalDXPixelArray.reset(new double[nLen]); + + for (int i = 0; i < nLen; ++i) + xNaturalDXPixelArray[i] = LogicWidthToDeviceFontCoordinate(pDXArray[i]); + + aLayoutArgs.SetAltNaturalDXArray(xNaturalDXPixelArray.get()); + nEndGlyphCoord = std::lround(xNaturalDXPixelArray[nLen - 1]); } + else + { + // convert from logical units to font units using a temporary array + xDXPixelArray.reset(new DeviceCoordinate[nLen]); + pDXPixelArray = xDXPixelArray.get(); + // using base position for better rounding a.k.a. "dancing characters" + DeviceCoordinate nPixelXOfs2 = LogicWidthToDeviceCoordinate(rLogicalPos.X() * 2); + for( int i = 0; i < nLen; ++i ) + { + pDXPixelArray[i] = (LogicWidthToDeviceCoordinate((rLogicalPos.X() + pDXArray[i]) * 2) - nPixelXOfs2) / 2; + } + + aLayoutArgs.SetDXArray(pDXPixelArray); + nEndGlyphCoord = pDXPixelArray[nLen - 1]; + } + } else { @@ -1369,11 +1389,12 @@ std::unique_ptr<SalLayout> OutputDevice::ImplLayout(const OUString& rOrigStr, #else /* !VCL_FLOAT_DEVICE_PIXEL */ pDXPixelArray = const_cast<DeviceCoordinate*>(pDXArray.data()); #endif /* !VCL_FLOAT_DEVICE_PIXEL */ + + aLayoutArgs.SetDXArray(pDXPixelArray); + nEndGlyphCoord = pDXPixelArray[nLen - 1]; } } - aLayoutArgs.SetDXArray(pDXPixelArray); - // get matching layout object for base font std::unique_ptr<SalLayout> pSalLayout = mpGraphics->GetTextLayout(0); @@ -1403,8 +1424,8 @@ std::unique_ptr<SalLayout> OutputDevice::ImplLayout(const OUString& rOrigStr, if( aLayoutArgs.mnFlags & SalLayoutFlags::RightAlign ) { DeviceCoordinate nRTLOffset; - if( pDXPixelArray ) - nRTLOffset = pDXPixelArray[ nLen - 1 ]; + if (!pDXArray.empty()) + nRTLOffset = nEndGlyphCoord; else if( nPixelWidth ) nRTLOffset = nPixelWidth; else diff --git a/vcl/source/text/ImplLayoutArgs.cxx b/vcl/source/text/ImplLayoutArgs.cxx index 7957d1ace824..a5b0ebb0a39f 100644 --- a/vcl/source/text/ImplLayoutArgs.cxx +++ b/vcl/source/text/ImplLayoutArgs.cxx @@ -37,6 +37,7 @@ ImplLayoutArgs::ImplLayoutArgs(const OUString& rStr, int nMinCharPos, int nEndCh , mnEndCharPos(nEndCharPos) , m_pTextLayoutCache(pLayoutCache) , mpDXArray(nullptr) + , mpAltNaturalDXArray(nullptr) , mnLayoutWidth(0) , mnOrientation(0) { @@ -101,6 +102,11 @@ void ImplLayoutArgs::SetLayoutWidth(DeviceCoordinate nWidth) { mnLayoutWidth = n void ImplLayoutArgs::SetDXArray(DeviceCoordinate const* pDXArray) { mpDXArray = pDXArray; } +void ImplLayoutArgs::SetAltNaturalDXArray(double const* pDXArray) +{ + mpAltNaturalDXArray = pDXArray; +} + void ImplLayoutArgs::SetOrientation(Degree10 nOrientation) { mnOrientation = nOrientation; } void ImplLayoutArgs::ResetPos() { maRuns.ResetPos(); }