vcl/inc/sallayout.hxx              |    4 +++-
 vcl/qa/cppunit/complextext.cxx     |   33 +++++++++++++++++++++++++++++++++
 vcl/source/gdi/CommonSalLayout.cxx |   15 +++++++++++++++
 3 files changed, 51 insertions(+), 1 deletion(-)

New commits:
commit 0f67027dbf3774687a558127427ff26796f00328
Author:     Khaled Hosny <kha...@libreoffice.org>
AuthorDate: Sun Jul 30 07:12:53 2023 +0300
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Mon Jul 31 22:15:10 2023 +0200

    tdf#107612: Include NNBSP and Mongolian characters in the same fallback run
    
    When a Mongolian character is preceded by a Narrow No Break Space
    (NNBSP), it is used to trigger special letter forms, but when we do font
    fallback NNBSP is always taken from the main font (HarfBuzz synthesises
    it when missing from the font, so we almost never use font fallback for
    it).
    
    We now check if the start of the fallback run is a Mongolian character
    and the previous is NNBSP and extend the fallback run to include it.
    
    Change-Id: I7607dba37ee51ff62bc9e86c3dbc555cd77e8d5d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155060
    Tested-by: Jenkins
    Reviewed-by: خالد حسني <kha...@libreoffice.org>
    (cherry picked from commit 3aac74005230500e2d0cb72b3a1198d07e985e84)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155037
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index d48edaaf67f2..e54a73b62894 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -57,7 +57,7 @@ namespace vcl::text {
     class TextLayoutCache;
 }
 
-class MultiSalLayout final : public SalLayout
+class VCL_DLLPUBLIC MultiSalLayout final : public SalLayout
 {
 public:
     void            DrawText(SalGraphics&) const override;
@@ -86,6 +86,8 @@ public:
                                           vcl::text::ImplLayoutArgs& 
rMultiArgs,
                                           const double* pMultiDXArray);
 
+    SAL_DLLPRIVATE ImplLayoutRuns* GetFallbackRuns() { return maFallbackRuns; }
+
     virtual         ~MultiSalLayout() override;
 
 private:
diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx
index bcf96cb4f99b..5c6297ec108e 100644
--- a/vcl/qa/cppunit/complextext.cxx
+++ b/vcl/qa/cppunit/complextext.cxx
@@ -531,4 +531,37 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testTdf107718)
 #endif
 }
 
+CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testTdf107612)
+{
+#if HAVE_MORE_FONTS
+    vcl::Font aFont(u"DejaVu Sans", u"Book", Size(0, 72));
+
+    ScopedVclPtrInstance<VirtualDevice> pOutDev;
+    pOutDev->SetFont(aFont);
+
+    auto pLayout = pOutDev->ImplLayout(u"a\u202F\u1823", 0, -1, Point(0, 0), 
0, {}, {});
+
+    // If font fallback happened, then the returned layout must be a
+    // MultiSalLayout instance.
+    auto pMultiLayout = dynamic_cast<MultiSalLayout*>(pLayout.get());
+    CPPUNIT_ASSERT(pMultiLayout);
+
+    auto pFallbackRuns = pMultiLayout->GetFallbackRuns();
+    CPPUNIT_ASSERT(!pFallbackRuns->IsEmpty());
+
+    bool bRTL;
+    int nCharPos = -1;
+    std::vector<sal_Int32> aFallbacks;
+    while (pFallbackRuns->GetNextPos(&nCharPos, &bRTL))
+        aFallbacks.push_back(nCharPos);
+
+    // Assert that U+202F is included in the fallback run.
+    // Without the fix this fails with:
+    // - Expected: { 2 }
+    // - Actual  : { 1, 2 }
+    std::vector<sal_Int32> aExpctedFallbacks = { 1, 2 };
+    CPPUNIT_ASSERT_EQUAL(aFallbacks, aExpctedFallbacks);
+#endif
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 7ea3ba687485..944587f17c8c 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -170,6 +170,21 @@ void 
GenericSalLayout::SetNeedFallback(vcl::text::ImplLayoutArgs& rArgs, sal_Int
         mxBreak->previousCharacters(rArgs.mrStr, nCharPos, aLocale,
             i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
 
+    // tdf#107612
+    // If the start of the fallback run is Mongolian character and the previous
+    // character is NNBSP, we want to include the NNBSP in the fallback since
+    // it has special uses in Mongolian and have to be in the same text run to
+    // work.
+    sal_Int32 nTempPos = nGraphemeStartPos;
+    if (nGraphemeStartPos > 0)
+    {
+        auto nCurrChar = rArgs.mrStr.iterateCodePoints(&nTempPos, 0);
+        auto nPrevChar = rArgs.mrStr.iterateCodePoints(&nTempPos, -1);
+        if (nPrevChar == 0x202F
+            && u_getIntPropertyValue(nCurrChar, UCHAR_SCRIPT) == 
USCRIPT_MONGOLIAN)
+            nGraphemeStartPos = nTempPos;
+    }
+
     //stay inside the Layout range (e.g. with tdf124116-1.odt)
     nGraphemeStartPos = std::max(rArgs.mnMinCharPos, nGraphemeStartPos);
     nGraphemeEndPos = std::min(rArgs.mnEndCharPos, nGraphemeEndPos);

Reply via email to