sw/Library_sw.mk                    |    1 
 sw/source/core/txtnode/fntcache.cxx |   67 ++------------------------
 sw/source/core/txtnode/justify.cxx  |   90 ++++++++++++++++++++++++++++++++++++
 sw/source/core/txtnode/justify.hxx  |   31 ++++++++++++
 4 files changed, 128 insertions(+), 61 deletions(-)

New commits:
commit f8560e09006cec5cc6ef26ccbf4f21aa28c22ac3
Author:     Mark Hung <mark...@gmail.com>
AuthorDate: Fri May 13 00:06:49 2022 +0800
Commit:     Mark Hung <mark...@gmail.com>
CommitDate: Wed May 18 14:32:06 2022 +0200

    tdf#149017 fix space distribution in SwFntObj::DrawText()
    
    - Fix logic problem for the last element.
    - Some glyphs may be made of many sal_Unicode ( ex. Unicode IVS ),
      take care ( fix ) of the following case
    a) 1 as the second glyph
    b) n-1 as the previous glyph.
    c) nCnt-1 as the last glyph.
    - Move the code to justify.cxx and its own namespace.
    
    Change-Id: Ice2236a54e8290a489fb2d887a326ccc4768213e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134243
    Tested-by: Jenkins
    Reviewed-by: Mark Hung <mark...@gmail.com>

diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index 9ce3a482b766..eec16fd5612c 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -437,6 +437,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
     sw/source/core/txtnode/atrtox \
     sw/source/core/txtnode/attrlinebreak \
     sw/source/core/txtnode/chrfmt \
+    sw/source/core/txtnode/justify \
     sw/source/core/txtnode/fmtatr2 \
     sw/source/core/txtnode/fntcache \
     sw/source/core/txtnode/fntcap \
diff --git a/sw/source/core/txtnode/fntcache.cxx 
b/sw/source/core/txtnode/fntcache.cxx
index 838547282770..acac99fb4701 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -56,6 +56,7 @@
 #include <o3tl/hash_combine.hxx>
 #include <cstdint>
 #include <memory>
+#include "justify.hxx"
 
 using namespace ::com::sun::star;
 
@@ -1553,7 +1554,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
         else
             nCnt = nCnt - rInf.GetIdx();
         nCnt = std::min(nCnt, rInf.GetLen());
-        tools::Long nKernSum = rInf.GetKern();
         sal_Unicode cChPrev = rInf.GetText()[sal_Int32(rInf.GetIdx())];
 
         // In case of a single underlined space in justified text,
@@ -1578,67 +1578,11 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
         }
         else
         {
-            // nSpaceSum contains the sum of the intermediate space distributed
-            // among Spaces by the Justification.
-            // The Spaces themselves will be positioned in the middle of the
-            // intermediate space, hence the nSpace/2.
-            // In case of word-by-word underlining they have to be positioned
-            // at the beginning of the intermediate space, so that the space
-            // is not underlined.
-            // A Space at the beginning or end of the text must be positioned
-            // before (resp. after) the whole intermediate space, otherwise
-            // the underline/strike-through would have gaps.
-            tools::Long nSpaceSum = 0;
-            // in word line mode and for Arabic, we disable the half space 
trick:
-            const tools::Long nHalfSpace = m_pPrtFont->IsWordLineMode() || 
bNoHalfSpace ? 0 : nSpaceAdd / 2;
-            const tools::Long nOtherHalf = nSpaceAdd - nHalfSpace;
-            if ( nSpaceAdd && ( cChPrev == CH_BLANK ) )
-                nSpaceSum = nHalfSpace;
-            for (sal_Int32 i = 1; i < sal_Int32(nCnt); ++i, nKernSum += 
rInf.GetKern())
-            {
-                sal_Unicode nCh = rInf.GetText()[sal_Int32(rInf.GetIdx()) + i];
-
-                // Apply SpaceSum
-                if (cChPrev == CH_BLANK)
-                {
-                    // no Pixel is lost:
-                    nSpaceSum += nOtherHalf;
-                }
-
-                if (nCh == CH_BLANK)
-                {
-                    if (i + 1 == sal_Int32(nCnt))
-                        nSpaceSum += nSpaceAdd;
-                    else
-                        nSpaceSum += nHalfSpace;
-                }
-
-                tools::Long nOldValue = aKernArray[i-1];
-
-                cChPrev = nCh;
-                aKernArray[i-1] += nKernSum + nSpaceSum;
-                // In word line mode and for Arabic, we disabled the half 
space trick. If a portion
-                // ends with a blank, the full nSpaceAdd value has been added 
to the character in
-                // front of the blank. This leads to painting artifacts, 
therefore we remove the
-                // nSpaceAdd value again:
-                if ((bNoHalfSpace || m_pPrtFont->IsWordLineMode()) && i+1 == 
sal_Int32(nCnt) && nCh == CH_BLANK)
-                    aKernArray[i-1] = aKernArray[i-1] - nSpaceAdd;
-
-                // Some glyph items use more than one sal_Unicode, eg. CJK 
ideograph extensions
-                // or unicode IVS. Don't assign space multiple times in case 
the original text array
-                // have the same values.
-                while(i < sal_Int32(nCnt) && aKernArray[i] == nOldValue)
-                {
-                    aKernArray[i] = aKernArray[i-1];
-                    ++i;
-                }
-            }
-
-            // the layout engine requires the total width of the output
-            tools::Long nOldValue = aKernArray[sal_Int32(rInf.GetLen()) - 1];
-            for(sal_Int32 i = sal_Int32(rInf.GetLen()) - 1; i >= 0 && 
aKernArray[i] == nOldValue; --i)
-                aKernArray[i] += nKernSum + nSpaceSum;
+            if (m_pPrtFont->IsWordLineMode())
+                bNoHalfSpace = true;
 
+            Justify::SpaceDistribution(aKernArray, rInf.GetText(), 
sal_Int32(rInf.GetIdx()),
+                    sal_Int32(nCnt), nSpaceAdd, rInf.GetKern(), bNoHalfSpace);
 
             if( rInf.GetGreyWave() )
             {
@@ -1714,6 +1658,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                 // anything to do?
                 if (rInf.GetWrong() || rInf.GetGrammarCheck() || 
rInf.GetSmartTags())
                 {
+                    const tools::Long nHalfSpace = bNoHalfSpace ? 0 : 
nSpaceAdd / 2;
                     CalcLinePosData aCalcLinePosData(rInf, GetFont(), nCnt, 
bSwitchH2V,
                                                      bSwitchH2VLRBT, 
bSwitchL2R, nHalfSpace,
                                                      aKernArray.data(), 
bBidiPor);
diff --git a/sw/source/core/txtnode/justify.cxx 
b/sw/source/core/txtnode/justify.cxx
new file mode 100644
index 000000000000..f465d3bd5e9a
--- /dev/null
+++ b/sw/source/core/txtnode/justify.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <vector>
+#include <sal/types.h>
+#include <swfont.hxx>
+#include "justify.hxx"
+
+namespace Justify
+{
+void SpaceDistribution(std::vector<sal_Int32>& rKernArray, const OUString& 
rText, sal_Int32 nStt,
+                       sal_Int32 nLen, tools::Long nSpaceAdd, tools::Long 
nKern, bool bNoHalfSpace)
+{
+    assert(nStt + nLen <= rText.getLength());
+    assert(nLen <= sal_Int32(rKernArray.size()));
+    // nSpaceSum contains the sum of the intermediate space distributed
+    // among Spaces by the Justification.
+    // The Spaces themselves will be positioned in the middle of the
+    // intermediate space, hence the nSpace/2.
+    // In case of word-by-word underlining they have to be positioned
+    // at the beginning of the intermediate space, so that the space
+    // is not underlined.
+    // A Space at the beginning or end of the text must be positioned
+    // before (resp. after) the whole intermediate space, otherwise
+    // the underline/strike-through would have gaps.
+    tools::Long nSpaceSum = 0;
+    // in word line mode and for Arabic, we disable the half space trick:
+    const tools::Long nHalfSpace = bNoHalfSpace ? 0 : nSpaceAdd / 2;
+    const tools::Long nOtherHalf = nSpaceAdd - nHalfSpace;
+    tools::Long nKernSum = nKern;
+    sal_Unicode cChPrev = rText[nStt];
+
+    if (nSpaceAdd && (cChPrev == CH_BLANK))
+        nSpaceSum = nHalfSpace;
+
+    sal_Int32 nPrevIdx = 0;
+
+    for (sal_Int32 i = 1; i < nLen; ++i, nKernSum += nKern)
+    {
+        // Find the beginning of the next cluster that has a different kern 
value.
+        while (i < nLen && rKernArray[i] == rKernArray[nPrevIdx])
+            ++i;
+
+        if (i == nLen)
+            break;
+
+        sal_Unicode nCh = rText[nStt + i];
+
+        // Apply SpaceSum
+        if (cChPrev == CH_BLANK)
+        {
+            // no Pixel is lost:
+            nSpaceSum += nOtherHalf;
+        }
+
+        if (nCh == CH_BLANK)
+        {
+            if (i + 1 == nLen)
+                nSpaceSum += nSpaceAdd;
+            else
+                nSpaceSum += nHalfSpace;
+        }
+
+        cChPrev = nCh;
+        rKernArray[nPrevIdx] += nKernSum + nSpaceSum;
+        // In word line mode and for Arabic, we disabled the half space trick. 
If a portion
+        // ends with a blank, the full nSpaceAdd value has been added to the 
character in
+        // front of the blank. This leads to painting artifacts, therefore we 
remove the
+        // nSpaceAdd value again:
+        if (bNoHalfSpace && i + 1 == nLen && nCh == CH_BLANK)
+            rKernArray[nPrevIdx] = rKernArray[nPrevIdx] - nSpaceAdd;
+
+        // Advance nPrevIdx and assign kern values to previous cluster.
+        for (tools::Long nValue = rKernArray[nPrevIdx++]; nPrevIdx < i; 
++nPrevIdx)
+            rKernArray[nPrevIdx] = nValue;
+    }
+
+    // the layout engine requires the total width of the output
+    while (nPrevIdx < nLen)
+        rKernArray[nPrevIdx++] += nKernSum + nSpaceSum;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/justify.hxx 
b/sw/source/core/txtnode/justify.hxx
new file mode 100644
index 000000000000..5c36a8f5fd5e
--- /dev/null
+++ b/sw/source/core/txtnode/justify.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+#include <sal/types.h>
+
+using namespace ::com::sun::star;
+namespace Justify
+{
+/// Distribute space between words and letters.
+/// @param[in,out] rKernArray text positions from OutDev::GetTextArray().
+/// @param rText string used to determine where space and kern are inserted.
+/// @param nStt starting index of rText.
+/// @param nLen number of elements to process in rKernArray and rText.
+/// @param nSpaceAdd amount of space to insert for each CH_BLANK.
+/// @param nKern amount of space to insert between letters.
+/// @param bNoHalfSpace whether to split the space into two halves.
+///        Splitted spaces are inserted before and after CH_BLANK.
+///        Set to true in word line mode and for Arabic text to avoid 
splitting.
+SW_DLLPUBLIC void SpaceDistribution(std::vector<sal_Int32>& rKernArray, const 
OUString& rText,
+                                    sal_Int32 nStt, sal_Int32 nLen, 
tools::Long nSpaceAdd,
+                                    tools::Long nKern, bool bNoHalfSpace);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to