include/vcl/vcllayout.hxx          |    6 +++---
 vcl/source/gdi/CommonSalLayout.cxx |   15 ++++++++-------
 vcl/source/gdi/pdfwriter_impl.cxx  |    6 ++++--
 vcl/source/gdi/sallayout.cxx       |    8 +++-----
 vcl/source/outdev/text.cxx         |   11 +++++++----
 5 files changed, 25 insertions(+), 21 deletions(-)

New commits:
commit 560e5406f3c6e8e6ed0f1c251b6910465266ed8d
Author:     Jonathan Clark <jonat...@libreoffice.org>
AuthorDate: Wed Aug 21 16:54:44 2024 -0600
Commit:     Jonathan Clark <jonat...@libreoffice.org>
CommitDate: Thu Aug 22 02:57:52 2024 +0200

    tdf#153966 vcl: Fix precision loss laying out right-aligned text
    
    Previously, characters would appear to 'fidget' while typing
    right-aligned right-to-left text.
    
    This fix contains the following changes:
    
    - Removed a floating point truncate during right-align positioning.
    - Removed unnecessary repeated multiply-add from the main layout loop.
    
    Change-Id: I2f070efb6a1387db1595b41023bd0f076064afda
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172230
    Tested-by: Jenkins
    Reviewed-by: Jonathan Clark <jonat...@libreoffice.org>

diff --git a/include/vcl/vcllayout.hxx b/include/vcl/vcllayout.hxx
index aa80e815a843..b36341ccc7a7 100644
--- a/include/vcl/vcllayout.hxx
+++ b/include/vcl/vcllayout.hxx
@@ -72,8 +72,8 @@ public:
     // used by upper layers
     basegfx::B2DPoint& DrawBase()                           { return 
maDrawBase; }
     const basegfx::B2DPoint& DrawBase() const               { return 
maDrawBase; }
-    Point&          DrawOffset()                            { return 
maDrawOffset; }
-    const Point&    DrawOffset() const                      { return 
maDrawOffset; }
+    basegfx::B2DPoint& DrawOffset() { return maDrawOffset; }
+    const basegfx::B2DPoint& DrawOffset() const { return maDrawOffset; }
     basegfx::B2DPoint GetDrawPosition( const basegfx::B2DPoint& rRelative = 
basegfx::B2DPoint(0,0) ) const;
 
     virtual bool    LayoutText( vcl::text::ImplLayoutArgs&, const 
SalLayoutGlyphsImpl* ) = 0;  // first step of layouting
@@ -136,7 +136,7 @@ protected:
 
     Degree10        mnOrientation;
 
-    mutable Point   maDrawOffset;
+    basegfx::B2DPoint maDrawOffset;
     basegfx::B2DPoint maDrawBase;
 
     bool            mbSubpixelPositioning;
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 0425b5794bca..769929f76058 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -436,7 +436,7 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
     double nYScale = 0;
     GetFont().GetScale(&nXScale, &nYScale);
 
-    basegfx::B2DPoint aCurrPos(0, 0);
+    hb_position_t nCurrX = 0;
     while (true)
     {
         int nBidiMinRunPos, nBidiEndRunPos;
@@ -683,7 +683,8 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
                 if (hb_glyph_info_get_glyph_flags(&pHbGlyphInfos[i]) & 
HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
                     nGlyphFlags |= GlyphItemFlags::IS_SAFE_TO_INSERT_KASHIDA;
 
-                double nAdvance, nXOffset, nYOffset;
+                hb_position_t nAdvance;
+                double nXOffset, nYOffset;
                 if (aSubRun.maDirection == HB_DIRECTION_TTB)
                 {
                     nGlyphFlags |= GlyphItemFlags::IS_VERTICAL;
@@ -712,19 +713,19 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
                     nYOffset = -pHbPositions[i].y_offset;
                 }
 
-                nAdvance = nAdvance * nXScale;
+                double nScaledAdvance = nAdvance * nXScale;
                 nXOffset = nXOffset * nXScale;
                 nYOffset = nYOffset * nYScale;
                 if (!GetSubpixelPositioning())
                 {
-                    nAdvance = std::round(nAdvance);
+                    nScaledAdvance = std::round(nScaledAdvance);
                     nXOffset = std::round(nXOffset);
                     nYOffset = std::round(nYOffset);
                 }
 
-                basegfx::B2DPoint aNewPos(aCurrPos.getX() + nXOffset, 
aCurrPos.getY() + nYOffset);
+                basegfx::B2DPoint aNewPos(nCurrX * nXScale + nXOffset, 
nYOffset);
                 const GlyphItem aGI(nCharPos, nCharCount, nGlyphIndex, 
aNewPos, nGlyphFlags,
-                                    nAdvance, nXOffset, nYOffset, 
nOrigCharPos);
+                                    nScaledAdvance, nXOffset, nYOffset, 
nOrigCharPos);
 
                 if (aGI.origCharPos() >= rArgs.mnDrawMinCharPos
                     && aGI.origCharPos() < rArgs.mnDrawEndCharPos)
@@ -735,7 +736,7 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
                 if (aGI.origCharPos() >= rArgs.mnDrawOriginCluster
                     && aGI.origCharPos() < rArgs.mnDrawEndCharPos)
                 {
-                    aCurrPos.adjustX(nAdvance);
+                    nCurrX += nAdvance;
                 }
             }
         }
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index d46cbf0da80e..434156491703 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6520,11 +6520,13 @@ void PDFWriterImpl::drawRelief( SalLayout& rLayout, 
const OUString& rText, bool
     if( eRelief == FontRelief::Engraved )
         nOff = -nOff;
 
-    rLayout.DrawOffset() += Point( nOff, nOff );
+    auto aPrevOffset = rLayout.DrawOffset();
+    rLayout.DrawOffset()
+        += basegfx::B2DPoint{ static_cast<double>(nOff), 
static_cast<double>(nOff) };
     updateGraphicsState();
     drawLayout( rLayout, rText, bTextLines );
 
-    rLayout.DrawOffset() -= Point( nOff, nOff );
+    rLayout.DrawOffset() = aPrevOffset;
     setTextLineColor( aTextLineColor );
     setOverlineColor( aOverlineColor );
     aSetFont.SetColor( aTextColor );
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index 1a63504ecc88..4d2d4fe68475 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -143,9 +143,8 @@ void SalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& 
rArgs )
 
 basegfx::B2DPoint SalLayout::GetDrawPosition(const basegfx::B2DPoint& 
rRelative) const
 {
-    basegfx::B2DPoint aPos(maDrawBase);
-    basegfx::B2DPoint aOfs(rRelative.getX() + maDrawOffset.X(),
-                     rRelative.getY() + maDrawOffset.Y());
+    basegfx::B2DPoint aPos{maDrawBase};
+    basegfx::B2DPoint aOfs = rRelative + maDrawOffset;
 
     if( mnOrientation == 0_deg10 )
         aPos += aOfs;
@@ -1220,8 +1219,7 @@ bool MultiSalLayout::GetNextGlyph(const GlyphItem** 
pGlyph,
         {
             int nFontTag = nLevel << GF_FONTSHIFT;
             nStart |= nFontTag;
-            rPos.adjustX(maDrawBase.getX() + maDrawOffset.X());
-            rPos.adjustY(maDrawBase.getY() + maDrawOffset.Y());
+            rPos += maDrawBase + maDrawOffset;
             return true;
         }
     }
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index d1528fb68101..f327f56c9024 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -214,7 +214,7 @@ bool OutputDevice::ImplDrawRotateText( SalLayout& 
rSalLayout )
 
     tools::Rectangle aBoundRect;
     rSalLayout.DrawBase() = basegfx::B2DPoint( 0, 0 );
-    rSalLayout.DrawOffset() = Point( 0, 0 );
+    rSalLayout.DrawOffset() = basegfx::B2DPoint{ 0, 0 };
     if (basegfx::B2DRectangle r; rSalLayout.GetBoundRect(r))
     {
         aBoundRect = SalLayout::BoundRect2Rectangle(r);
@@ -368,9 +368,12 @@ void OutputDevice::ImplDrawSpecialText( SalLayout& 
rSalLayout )
 
         if ( eRelief == FontRelief::Engraved )
             nOff = -nOff;
-        rSalLayout.DrawOffset() += Point( nOff, nOff);
-        ImplDrawTextDirect( rSalLayout, mbTextLines );
-        rSalLayout.DrawOffset() -= Point( nOff, nOff);
+
+        auto aPrevOffset = rSalLayout.DrawOffset();
+        rSalLayout.DrawOffset()
+            += basegfx::B2DPoint{ static_cast<double>(nOff), 
static_cast<double>(nOff) };
+        ImplDrawTextDirect(rSalLayout, mbTextLines);
+        rSalLayout.DrawOffset() = aPrevOffset;
 
         SetTextLineColor( aTextLineColor );
         SetOverlineColor( aOverlineColor );

Reply via email to