vcl/qa/cppunit/complextext.cxx |   39 +++++++++++++++++++++++++++++++++++++++
 vcl/source/gdi/sallayout.cxx   |    8 ++++++++
 2 files changed, 47 insertions(+)

New commits:
commit d03b1f695965fa195fbae9415c05bc93036ff61c
Author:     Jonathan Clark <jonat...@libreoffice.org>
AuthorDate: Tue Mar 25 07:17:48 2025 -0600
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Fri Apr 11 10:12:45 2025 +0200

    tdf#165510 vcl: Fix incorrect adjustment of bidi MultiSalLayouts
    
    The final step in laying out text with font substitutions is to drop
    invalid glyphs from the base layout and position glyphs from
    substitution layouts in their place. This change fixes a logic error in
    this algorithm which was causing tofu and overlapping characters in the
    frequent case of an all-LTR base layout and an all-RTL substitution
    layout containing multiple fallback runs.
    
    Change-Id: I0d8b03671a77c7d4c41c9ea0f32b526ed44477fe
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183340
    Tested-by: Jenkins
    Reviewed-by: Jonathan Clark <jonat...@libreoffice.org>
    (cherry picked from commit 98057a0e54f39160121f7c88b19250e6085d5343)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183991
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx
index 693cde25b206..c8a9e6e7c3cd 100644
--- a/vcl/qa/cppunit/complextext.cxx
+++ b/vcl/qa/cppunit/complextext.cxx
@@ -758,4 +758,43 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testTdf163215)
     CPPUNIT_ASSERT(aFoundPositions2.at(4));
 }
 
+CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testTdf165510)
+{
+    ScopedVclPtrInstance<VirtualDevice> pOutDev;
+
+    vcl::Font aBaseFont{ u"Liberation Sans"_ustr, u"Regular"_ustr, Size{ 0, 72 
} };
+    pOutDev->SetFont(aBaseFont);
+
+    vcl::Font aFallbackFont{ u"Noto Sans"_ustr, u"Regular"_ustr, Size{ 0, 72 } 
};
+    pOutDev->ForceFallbackFont(aFallbackFont);
+
+    auto aText = u"ab(ح)cd(د)ef"_ustr;
+    auto pLayout = pOutDev->ImplLayout(aText, /*nIndex*/ 0, /*nLen*/ 
aText.getLength());
+
+    // Fallback must have happened for this test to be meaningful
+    auto pMultiLayout = dynamic_cast<MultiSalLayout*>(pLayout.get());
+    CPPUNIT_ASSERT(pMultiLayout);
+
+    std::vector<int> aCharIndices;
+
+    const GlyphItem* pGlyph = nullptr;
+    basegfx::B2DPoint stPos;
+    int nCurrPos = 0;
+    while (pLayout->GetNextGlyph(&pGlyph, stPos, nCurrPos))
+    {
+        aCharIndices.push_back(pGlyph->charPos());
+    }
+
+    // tdf#165510 caused failure to remove dropped glyphs from the base layout.
+    // Without the fix, the base layout will contain an errant copy of char 8.
+    //                              { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 3, 8 
};
+    std::vector<int> aRefCharIndices{ 0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 3, 8 };
+
+    CPPUNIT_ASSERT_EQUAL(aRefCharIndices.size(), aCharIndices.size());
+    for (size_t i = 0; i < aRefCharIndices.size(); ++i)
+    {
+        CPPUNIT_ASSERT_EQUAL(aRefCharIndices.at(i), aCharIndices.at(i));
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index e8dc3999e216..04f98e22c8e6 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -1024,6 +1024,14 @@ void 
MultiSalLayout::ImplAdjustMultiLayout(vcl::text::ImplLayoutArgs& rArgs,
         {
             if (maFallbackRuns[i].GetRun(&nRunStart, &nRunEnd, &bRtl))
             {
+                // tdf#165510: Need to use the direction of the current 
character,
+                // not the direction of the fallback run.
+                nActiveCharIndex = nActiveCharPos - mnMinCharPos;
+                if (nActiveCharIndex >= 0)
+                {
+                    bRtl = vRtl[nActiveCharIndex];
+                }
+
                 if (bRtl)
                 {
                     if (nRunStart > nActiveCharPos)

Reply via email to