diff options
author | Mark Hung <marklm9@gmail.com> | 2022-05-21 21:11:24 +0800 |
---|---|---|
committer | Mark Hung <marklh9@gmail.com> | 2022-05-25 16:10:16 +0200 |
commit | 7f77a180dd22e7d07b1840660dc9a6e66463b84f (patch) | |
tree | bee51cfd6cbab308e7b0d157bd07d66db32b1e7e | |
parent | a68629fdf97f181d4c6975f91e66fe52f83247e9 (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.cxx | 15 | ||||
-rw-r--r-- | sw/source/core/txtnode/fntcache.cxx | 100 | ||||
-rw-r--r-- | sw/source/core/txtnode/justify.cxx | 118 | ||||
-rw-r--r-- | sw/source/core/txtnode/justify.hxx | 18 |
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: */ |