summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorMark Hung <marklm9@gmail.com>2022-05-13 00:06:49 +0800
committerMark Hung <marklh9@gmail.com>2022-05-18 14:32:06 +0200
commitf8560e09006cec5cc6ef26ccbf4f21aa28c22ac3 (patch)
tree7efdff3730ba7f3797d2770b3da5f57baea2bd61 /sw
parent343eed477ee7b55aa450bbc2aee6786dc0d9a071 (diff)
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 <marklh9@gmail.com>
Diffstat (limited to 'sw')
-rw-r--r--sw/Library_sw.mk1
-rw-r--r--sw/source/core/txtnode/fntcache.cxx67
-rw-r--r--sw/source/core/txtnode/justify.cxx90
-rw-r--r--sw/source/core/txtnode/justify.hxx31
4 files changed, 128 insertions, 61 deletions
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: */