summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Hung <marklm9@gmail.com>2022-05-21 21:11:24 +0800
committerMark Hung <marklh9@gmail.com>2022-05-25 16:10:16 +0200
commit7f77a180dd22e7d07b1840660dc9a6e66463b84f (patch)
treebee51cfd6cbab308e7b0d157bd07d66db32b1e7e
parenta68629fdf97f181d4c6975f91e66fe52f83247e9 (diff)
sw: refactor and create Justify::SnapToGrid()
Move snapt to grid code from SwFntObj::DrawText() to Justify::SnapToGrid() and create a simple unit test case testSnapToGrid. Note that SnapToGrid() is for "Snap to char is on" case. Change-Id: Ib9b3a08c744216e37dd260434700cbf3f079a0fe Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134707 Tested-by: Jenkins Reviewed-by: Mark Hung <marklh9@gmail.com>
-rw-r--r--sw/qa/core/txtnode/justify.cxx15
-rw-r--r--sw/source/core/txtnode/fntcache.cxx100
-rw-r--r--sw/source/core/txtnode/justify.cxx118
-rw-r--r--sw/source/core/txtnode/justify.hxx18
4 files changed, 156 insertions, 95 deletions
diff --git a/sw/qa/core/txtnode/justify.cxx b/sw/qa/core/txtnode/justify.cxx
index 46a52f851efc..88ae8bef3865 100644
--- a/sw/qa/core/txtnode/justify.cxx
+++ b/sw/qa/core/txtnode/justify.cxx
@@ -109,4 +109,19 @@ CPPUNIT_TEST_FIXTURE(SwCoreJustifyTest, testSpaceDistributionUnicodeIVS)
CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
}
+CPPUNIT_TEST_FIXTURE(SwCoreJustifyTest, testSnapToGrid)
+{
+ tools::Long nDelta = 0;
+ // "曰〈道高一尺化太平〉云云"
+ static const OUStringLiteral aText
+ = u"\u66f0\u3008\u9053\u9ad8\u4e00\u5c3a\u5316\u592a\u5e73\u3009\u4e91\u4e91";
+ CharWidthArray aActual{ 880, 880, 880, 880, 880, 880, 880, 880, 880, 880, 880, 880 };
+ CharWidthArray aExpected{
+ 1360, 1040, 1200, 1200, 1200, 1200, 1200, 1200, 1040, 1360, 1200, 1040
+ };
+ aActual.InvokeWithKernArray(
+ [&] { nDelta = Justify::SnapToGrid(aActual.maArray, aText, 0, 12, 400, 14400); });
+ CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
+ CPPUNIT_ASSERT_EQUAL(tools::Long(160), nDelta);
+}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx
index acac99fb4701..8036af0e56c5 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -604,27 +604,6 @@ void SwFntObj::SetDevFont( const SwViewShell *pSh, OutputDevice& rOut )
* on printer, !Kerning => DrawText
* on printer + Kerning => DrawStretchText
*/
-static sal_uInt8 lcl_WhichPunctuation( sal_Unicode cChar )
-{
- if ( ( cChar < 0x3001 || cChar > 0x3002 ) &&
- ( cChar < 0x3008 || cChar > 0x3011 ) &&
- ( cChar < 0x3014 || cChar > 0x301F ) &&
- 0xFF62 != cChar && 0xFF63 != cChar )
- // no punctuation
- return SwScriptInfo::NONE;
- else if ( 0x3001 == cChar || 0x3002 == cChar ||
- 0x3009 == cChar || 0x300B == cChar ||
- 0x300D == cChar || 0x300F == cChar ||
- 0x3011 == cChar || 0x3015 == cChar ||
- 0x3017 == cChar || 0x3019 == cChar ||
- 0x301B == cChar || 0x301E == cChar ||
- 0x301F == cChar || 0xFF63 == cChar )
- // right punctuation
- return SwScriptInfo::SPECIAL_RIGHT;
-
- return SwScriptInfo::SPECIAL_LEFT;
-}
-
static bool lcl_IsMonoSpaceFont( const vcl::RenderContext& rOut )
{
const tools::Long nWidth1 = rOut.GetTextWidth( OUString( u'\x3008' ) );
@@ -970,81 +949,12 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
else
GetTextArray(rInf.GetOut(), rInf, aKernArray);
- // Change the average width per character to an appropriate grid width
- // basically get the ratio of the avg width to the grid unit width, then
- // multiple this ratio to give the new avg width - which in this case
- // gives a new grid width unit size
-
- tools::Long nAvgWidthPerChar = aKernArray[sal_Int32(rInf.GetLen()) - 1] / sal_Int32(rInf.GetLen());
-
- const sal_uLong nRatioAvgWidthCharToGridWidth = nAvgWidthPerChar ?
- ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
- 1;
-
- nAvgWidthPerChar = nRatioAvgWidthCharToGridWidth * nGridWidth;
-
- // the absolute end position of the first character is also its width
- tools::Long nCharWidth = aKernArray[ 0 ];
- sal_uLong nHalfWidth = nAvgWidthPerChar / 2;
-
- tools::Long nNextFix=0;
-
- // we work out the start position (origin) of the first character,
- // and we set the next "fix" offset to half the width of the char.
- // The exceptions are for punctuation characters that are not centered
- // so in these cases we just add half a regular "average" character width
- // to the first characters actual width to allow the next character to
- // be centered automatically
- // If the character is "special right", then the offset is correct already
- // so the fix offset is as normal - half the average character width
-
- sal_Unicode cChar = rInf.GetText()[ sal_Int32(rInf.GetIdx()) ];
- sal_uInt8 nType = lcl_WhichPunctuation( cChar );
- switch ( nType )
- {
- // centre character
- case SwScriptInfo::NONE :
- aTextOriginPos.AdjustX(( nAvgWidthPerChar - nCharWidth ) / 2 );
- nNextFix = nCharWidth / 2;
- break;
- case SwScriptInfo::SPECIAL_RIGHT :
- nNextFix = nHalfWidth;
- break;
- // punctuation
- default:
- aTextOriginPos.AdjustX(nAvgWidthPerChar - nCharWidth );
- nNextFix = nCharWidth - nHalfWidth;
- }
-
- // calculate offsets
- for (sal_Int32 j = 1; j < sal_Int32(rInf.GetLen()); ++j)
- {
- tools::Long nCurrentCharWidth = aKernArray[ j ] - aKernArray[ j - 1 ];
- nNextFix += nAvgWidthPerChar;
-
- // almost the same as getting the offset for the first character:
- // punctuation characters are not centered, so just add half an
- // average character width minus the characters actual char width
- // to get the offset into the centre of the next character
-
- cChar = rInf.GetText()[ sal_Int32(rInf.GetIdx()) + j ];
- nType = lcl_WhichPunctuation( cChar );
- switch ( nType )
- {
- case SwScriptInfo::NONE :
- aKernArray[ j - 1 ] = nNextFix - ( nCurrentCharWidth / 2 );
- break;
- case SwScriptInfo::SPECIAL_RIGHT :
- aKernArray[ j - 1 ] = nNextFix - nHalfWidth;
- break;
- default:
- aKernArray[ j - 1 ] = nNextFix + nHalfWidth - nCurrentCharWidth;
- }
- }
+ tools::Long nDelta
+ = Justify::SnapToGrid(aKernArray, rInf.GetText(), sal_Int32(rInf.GetIdx()),
+ sal_Int32(rInf.GetLen()), nGridWidth, rInf.GetWidth());
- // the layout engine requires the total width of the output
- aKernArray[sal_Int32(rInf.GetLen()) - 1] = rInf.GetWidth() -
- aTextOriginPos.X() + rInf.GetPos().X() ;
+ if (nDelta)
+ aTextOriginPos.AdjustX(nDelta);
if ( bSwitchH2V )
rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
diff --git a/sw/source/core/txtnode/justify.cxx b/sw/source/core/txtnode/justify.cxx
index f465d3bd5e9a..0d97ed470f96 100644
--- a/sw/source/core/txtnode/justify.cxx
+++ b/sw/source/core/txtnode/justify.cxx
@@ -12,6 +12,33 @@
#include <swfont.hxx>
#include "justify.hxx"
+namespace
+{
+enum class IdeographicPunctuationClass
+{
+ NONE,
+ OPEN_BRACKET,
+ CLOSE_BRACKET,
+ COMMA_OR_FULLSTOP
+};
+
+IdeographicPunctuationClass lcl_WhichPunctuationClass(sal_Unicode cChar)
+{
+ if ((cChar < 0x3001 || cChar > 0x3002) && (cChar < 0x3008 || cChar > 0x3011)
+ && (cChar < 0x3014 || cChar > 0x301F) && 0xFF62 != cChar && 0xFF63 != cChar)
+ return IdeographicPunctuationClass::NONE;
+ else if (0x3001 == cChar || 0x3002 == cChar)
+ return IdeographicPunctuationClass::COMMA_OR_FULLSTOP;
+ else if (0x3009 == cChar || 0x300B == cChar || 0x300D == cChar || 0x300F == cChar
+ || 0x3011 == cChar || 0x3015 == cChar || 0x3017 == cChar || 0x3019 == cChar
+ || 0x301B == cChar || 0x301E == cChar || 0x301F == cChar || 0xFF63 == cChar)
+ // right punctuation
+ return IdeographicPunctuationClass::CLOSE_BRACKET;
+
+ return IdeographicPunctuationClass::OPEN_BRACKET;
+}
+}
+
namespace Justify
{
void SpaceDistribution(std::vector<sal_Int32>& rKernArray, const OUString& rText, sal_Int32 nStt,
@@ -85,6 +112,97 @@ void SpaceDistribution(std::vector<sal_Int32>& rKernArray, const OUString& rText
while (nPrevIdx < nLen)
rKernArray[nPrevIdx++] += nKernSum + nSpaceSum;
}
+
+tools::Long SnapToGrid(std::vector<sal_Int32>& rKernArray, const OUString& rText, sal_Int32 nStt,
+ sal_Int32 nLen, tools::Long nGridWidth, tools::Long nWidth)
+{
+ assert(nStt + nLen <= rText.getLength());
+ assert(nLen <= sal_Int32(rKernArray.size()));
+
+ tools::Long nDelta = 0; // delta offset to text origin
+
+ // Change the average width per character to an appropriate grid width
+ // basically get the ratio of the avg width to the grid unit width, then
+ // multiple this ratio to give the new avg width - which in this case
+ // gives a new grid width unit size
+
+ tools::Long nAvgWidthPerChar = rKernArray[nLen - 1] / nLen;
+
+ const sal_uLong nRatioAvgWidthCharToGridWidth
+ = nAvgWidthPerChar ? (nAvgWidthPerChar - 1) / nGridWidth + 1 : 1;
+
+ nAvgWidthPerChar = nRatioAvgWidthCharToGridWidth * nGridWidth;
+
+ // the absolute end position of the first character is also its width
+ tools::Long nCharWidth = rKernArray[0];
+ sal_uLong nHalfWidth = nAvgWidthPerChar / 2;
+
+ tools::Long nNextFix = 0;
+
+ // we work out the start position (origin) of the first character,
+ // and we set the next "fix" offset to half the width of the char.
+ // The exceptions are for punctuation characters that are not centered
+ // so in these cases we just add half a regular "average" character width
+ // to the first characters actual width to allow the next character to
+ // be centered automatically
+ // If the character is "special right", then the offset is correct already
+ // so the fix offset is as normal - half the average character width
+
+ sal_Unicode cChar = rText[nStt];
+ IdeographicPunctuationClass eClass = lcl_WhichPunctuationClass(cChar);
+ switch (eClass)
+ {
+ case IdeographicPunctuationClass::NONE:
+ // Centered
+ nDelta = (nAvgWidthPerChar - nCharWidth) / 2;
+ nNextFix = nCharWidth / 2;
+ break;
+ case IdeographicPunctuationClass::CLOSE_BRACKET:
+ case IdeographicPunctuationClass::COMMA_OR_FULLSTOP:
+ // Closer to previous ideograph
+ nNextFix = nHalfWidth;
+ break;
+ default:
+ // case IdeographicPunctuationClass::OPEN_BRACKET: closer to next ideograph.
+ nDelta = nAvgWidthPerChar - nCharWidth;
+ nNextFix = nCharWidth - nHalfWidth;
+ }
+
+ // calculate offsets
+ for (sal_Int32 j = 1; j < nLen; ++j)
+ {
+ tools::Long nCurrentCharWidth = rKernArray[j] - rKernArray[j - 1];
+ nNextFix += nAvgWidthPerChar;
+
+ // almost the same as getting the offset for the first character:
+ // punctuation characters are not centered, so just add half an
+ // average character width minus the characters actual char width
+ // to get the offset into the centre of the next character
+
+ cChar = rText[nStt + j];
+ eClass = lcl_WhichPunctuationClass(cChar);
+ switch (eClass)
+ {
+ case IdeographicPunctuationClass::NONE:
+ // Centered
+ rKernArray[j - 1] = nNextFix - (nCurrentCharWidth / 2);
+ break;
+ case IdeographicPunctuationClass::CLOSE_BRACKET:
+ case IdeographicPunctuationClass::COMMA_OR_FULLSTOP:
+ // Closer to previous ideograph
+ rKernArray[j - 1] = nNextFix - nHalfWidth;
+ break;
+ default:
+ // case IdeographicPunctuationClass::OPEN_BRACKET: closer to next ideograph.
+ rKernArray[j - 1] = nNextFix + nHalfWidth - nCurrentCharWidth;
+ }
+ }
+
+ // the layout engine requires the total width of the output
+ rKernArray[nLen - 1] = nWidth - nDelta;
+
+ return nDelta;
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/justify.hxx b/sw/source/core/txtnode/justify.hxx
index e98ecb5216c2..5a4c08b3da28 100644
--- a/sw/source/core/txtnode/justify.hxx
+++ b/sw/source/core/txtnode/justify.hxx
@@ -25,6 +25,24 @@ namespace Justify
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);
+
+/// Snap ideographs to text grids:
+/// a) Ideographic open brackets are aligned to the rightmost edge of spanned grids so that
+// they can be closer to the next ideograph.
+/// b) Ideographic close brackets, ideogrpahic comma, and idographic fullstop are aligned
+/// to the leftmost edge of spanned grids so that they can be closer to the previous
+/// ideograph.
+/// c) Other ideographs are aligned to the center of the spnaned grids.
+/// @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 nGirdWidth width of a text gird
+/// @param nWidth width of the whole portion.
+/// @return the delta offset of first glyph so text origin can be updated accordingly.
+SW_DLLPUBLIC tools::Long SnapToGrid(std::vector<sal_Int32>& rKernArray, const OUString& rText,
+ sal_Int32 nStt, sal_Int32 nLen, tools::Long nGridWidth,
+ tools::Long nWidth);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */