From 976b16b1c6ad6e6eaded7a9fb24388c4512e21e2 Mon Sep 17 00:00:00 2001 From: Jonathan Clark Date: Fri, 7 Jun 2024 02:36:22 -0600 Subject: tdf#152024 Diacritics cut off at top and bottom of paragraph This change fixes issues causing Writer to clip paragraphs at the ascent of the top line, and descent of the last line, of a paragraph. This issue caused certain diacritics to render incompletely, or not at all. Change-Id: I99a3a25335f8b1d798fc8a55ff42d5c78749fca4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168557 Tested-by: Jenkins Reviewed-by: Jonathan Clark --- drawinglayer/source/processor2d/vclprocessor2d.cxx | 2 +- editeng/source/items/svxfont.cxx | 6 ++- filter/source/svg/svgwriter.cxx | 3 +- include/vcl/outdev.hxx | 25 ++++++--- sw/source/core/inc/drawfont.hxx | 36 +++++++++++++ sw/source/core/text/frmform.cxx | 21 +++++--- sw/source/core/text/guess.cxx | 45 ++++++++++------ sw/source/core/text/inftxt.cxx | 19 +++---- sw/source/core/text/inftxt.hxx | 12 +++-- sw/source/core/text/itrform2.cxx | 2 - sw/source/core/text/itrpaint.cxx | 6 +-- sw/source/core/text/porfld.cxx | 4 -- sw/source/core/text/porlay.cxx | 3 +- sw/source/core/text/porlay.hxx | 11 ++-- sw/source/core/text/txtpaint.cxx | 7 --- sw/source/core/text/txtpaint.hxx | 15 +++--- sw/source/core/txtnode/fntcache.cxx | 41 +++++++++++---- toolkit/source/awt/vclxfont.cxx | 2 +- vcl/qa/cppunit/complextext.cxx | 60 ++++++++++++++-------- vcl/qa/cppunit/text.cxx | 15 ++++-- vcl/source/filter/wmf/emfwr.cxx | 2 +- vcl/source/filter/wmf/wmfwr.cxx | 3 +- vcl/source/outdev/text.cxx | 47 ++++++++++------- vcl/source/text/textlayout.cxx | 7 ++- 24 files changed, 263 insertions(+), 131 deletions(-) diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx index e0a090cf9ecd..45825a2a477b 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -337,7 +337,7 @@ void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D( tools::Long nWidthToFill = rTextCandidate.getWidthToFill(); tools::Long nWidth = basegfx::fround( - mpOutputDevice->GetTextArray(rTextCandidate.getText(), &aDXArray, 0, 1)); + mpOutputDevice->GetTextArray(rTextCandidate.getText(), &aDXArray, 0, 1).nWidth); sal_Int32 nChars = 2; if (nWidth) nChars = nWidthToFill / nWidth; diff --git a/editeng/source/items/svxfont.cxx b/editeng/source/items/svxfont.cxx index 253c78f8dea4..2df18feb449f 100644 --- a/editeng/source/items/svxfont.cxx +++ b/editeng/source/items/svxfont.cxx @@ -38,7 +38,8 @@ static tools::Long GetTextArray( const OutputDevice* pOut, const OUString& rStr, { const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(pOut, rStr, nIndex, nLen); - return basegfx::fround(pOut->GetTextArray( rStr, pDXAry, nIndex, nLen, true, nullptr, layoutGlyphs)); + return basegfx::fround( + pOut->GetTextArray(rStr, pDXAry, nIndex, nLen, true, nullptr, layoutGlyphs).nWidth); } SvxFont::SvxFont() @@ -719,7 +720,8 @@ void SvxDoGetCapitalSize::Do( const OUString &_rTxt, const sal_Int32 _nIdx, if (pDXAry) { KernArray aKernArray; - aPartSize.setWidth(basegfx::fround(pOut->GetTextArray(_rTxt, &aKernArray, _nIdx, _nLen))); + aPartSize.setWidth(basegfx::fround( + pOut->GetTextArray(_rTxt, &aKernArray, _nIdx, _nLen).nWidth)); assert(pDXAry->get_factor() == aKernArray.get_factor()); auto& dest = pDXAry->get_subunit_array(); sal_Int32 nStart = dest.empty() ? 0 : dest.back(); diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx index e4c885cd6ca4..57a039f32a18 100644 --- a/filter/source/svg/svgwriter.cxx +++ b/filter/source/svg/svgwriter.cxx @@ -2679,7 +2679,8 @@ void SVGActionWriter::ImplWriteText( const Point& rPos, const OUString& rText, } else { - aNormSize = Size(basegfx::fround(mpVDev->GetTextArray(rText, &aTmpArray)), 0); + aNormSize + = Size(basegfx::fround(mpVDev->GetTextArray(rText, &aTmpArray).nWidth), 0); } // if text is rotated, set transform matrix at new g element diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index 347d5bb82226..2fddb3c3f24a 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -160,6 +160,12 @@ class OutputDevice; namespace vcl { typedef OutputDevice RenderContext; + + struct TextArrayMetrics + { + std::optional aBounds; + double nWidth = 0.0; + }; } VCL_DLLPUBLIC void InvertFocusRect(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); @@ -1059,20 +1065,23 @@ public: sal_Int32 nLen, SalLayoutFlags flags = SalLayoutFlags::NONE, const SalLayoutGlyphs* pLayoutCache = nullptr); - double GetTextArray( const OUString& rStr, KernArray* pDXAry, - sal_Int32 nIndex = 0, sal_Int32 nLen = -1, bool bCaret = false, - vcl::text::TextLayoutCache const* = nullptr, - SalLayoutGlyphs const*const pLayoutCache = nullptr) const; + vcl::TextArrayMetrics GetTextArray(const OUString& rStr, KernArray* pDXAry, + sal_Int32 nIndex = 0, sal_Int32 nLen = -1, + bool bCaret = false, + vcl::text::TextLayoutCache const* = nullptr, + SalLayoutGlyphs const* const pLayoutCache = nullptr) const; void DrawPartialTextArray(const Point& rStartPt, const OUString& rStr, KernArraySpan aKernArray, std::span pKashidaAry, sal_Int32 nIndex, sal_Int32 nLen, sal_Int32 nPartIndex, sal_Int32 nPartLen, SalLayoutFlags flags = SalLayoutFlags::NONE, const SalLayoutGlyphs* pLayoutCache = nullptr); - double GetPartialTextArray(const OUString& rStr, KernArray* pDXAry, sal_Int32 nIndex, - sal_Int32 nLen, sal_Int32 nPartIndex, sal_Int32 nPartLen, - bool bCaret = false, const vcl::text::TextLayoutCache* = nullptr, - const SalLayoutGlyphs* pLayoutCache = nullptr) const; + vcl::TextArrayMetrics GetPartialTextArray(const OUString& rStr, KernArray* pDXAry, + sal_Int32 nIndex, sal_Int32 nLen, + sal_Int32 nPartIndex, sal_Int32 nPartLen, + bool bCaret = false, + const vcl::text::TextLayoutCache* = nullptr, + const SalLayoutGlyphs* pLayoutCache = nullptr) const; SAL_DLLPRIVATE void GetCaretPositions( const OUString&, KernArray& rCaretXArray, sal_Int32 nIndex, sal_Int32 nLen, diff --git a/sw/source/core/inc/drawfont.hxx b/sw/source/core/inc/drawfont.hxx index 646ab21c60b7..c262cb931581 100644 --- a/sw/source/core/inc/drawfont.hxx +++ b/sw/source/core/inc/drawfont.hxx @@ -60,6 +60,8 @@ class SW_DLLPUBLIC SwDrawTextInfo SwUnderlineFont* m_pUnderFnt = nullptr; TextFrameIndex* m_pHyphPos = nullptr; tools::Long m_nKanaDiff = 0; + SwTwips m_nExtraAscent = 0; + SwTwips m_nExtraDescent = 0; TextFrameIndex m_nIdx; TextFrameIndex m_nLen; TextFrameIndex m_nMeasureLen = TextFrameIndex{ COMPLETE_STRING }; @@ -105,6 +107,8 @@ class SW_DLLPUBLIC SwDrawTextInfo bool m_bNumberOfBlanks : 1 = false; bool m_bUppr : 1 = false; bool m_bDrawSp : 1 = false; + bool m_bExtraAscent : 1 = false; + bool m_bExtraDescent : 1 = false; #endif public: @@ -271,6 +275,22 @@ public: return m_nKanaDiff; } + SwTwips GetExtraAscent() const + { +#ifdef DBG_UTIL + OSL_ENSURE(m_bExtraAscent, "DrawTextInfo: Undefined extra ascent"); +#endif + return m_nExtraAscent; + } + + SwTwips GetExtraDescent() const + { +#ifdef DBG_UTIL + OSL_ENSURE(m_bExtraDescent, "DrawTextInfo: Undefined extra descent"); +#endif + return m_nExtraDescent; + } + sal_uInt16 GetWidth() const { return m_nWidth; @@ -490,6 +510,22 @@ public: #endif } + void SetExtraAscent(SwTwips nNew) + { + m_nExtraAscent = nNew; +#ifdef DBG_UTIL + m_bExtraAscent = true; +#endif + } + + void SetExtraDescent(SwTwips nNew) + { + m_nExtraDescent = nNew; +#ifdef DBG_UTIL + m_bExtraDescent = true; +#endif + } + void SetWidth( sal_uInt16 nNew ) { m_nWidth = nNew; diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx index 4e2caf27b276..0d9a8c7ae9ff 100644 --- a/sw/source/core/text/frmform.cxx +++ b/sw/source/core/text/frmform.cxx @@ -1465,13 +1465,20 @@ bool SwTextFrame::FormatLine( SwTextFormatter &rLine, const bool bPrev ) rRepaint.SetRightOfst( nRght ); // Finally we enlarge the repaint rectangle if we found an underscore - // within our line. 40 Twips should be enough - const bool bHasUnderscore = - ( rLine.GetInfo().GetUnderScorePos() < nNewStart ); - if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() ) - rRepaint.Bottom( rRepaint.Bottom() + 40 ); - - const_cast(rLine.GetCurr())->SetUnderscore( bHasUnderscore ); + // or another glyph extending beyond the line height within the line. + auto nBaseAscent = pNew->GetAscent(); + auto nMaxExtraAscent + = std::max({ SwTwips{ 0 }, rLine.GetInfo().GetExtraAscent() - nBaseAscent, + rLine.GetCurr()->GetExtraAscent() }); + rRepaint.Top(rRepaint.Top() - nMaxExtraAscent); + const_cast(rLine.GetCurr())->SetExtraAscent(nMaxExtraAscent); + + auto nBaseDescent = pNew->Height() - pNew->GetAscent(); + auto nMaxExtraDescent + = std::max({ SwTwips{ 0 }, rLine.GetInfo().GetExtraDescent() - nBaseDescent, + rLine.GetCurr()->GetExtraDescent() }); + rRepaint.Bottom(rRepaint.Bottom() + nMaxExtraDescent); + const_cast(rLine.GetCurr())->SetExtraDescent(nMaxExtraDescent); } // Calculating the good ol' nDelta diff --git a/sw/source/core/text/guess.cxx b/sw/source/core/text/guess.cxx index c476de7110cc..f49f6fccd3d2 100644 --- a/sw/source/core/text/guess.cxx +++ b/sw/source/core/text/guess.cxx @@ -79,6 +79,7 @@ bool hasBlanksInLine(const SwTextFormatInfo& rInf, TextFrameIndex end) bool maybeAdjustPositionsForBlockAdjust(TextFrameIndex& rCutPos, TextFrameIndex& rBreakPos, TextFrameIndex& rBreakStart, SwTwips& rBreakWidth, SwTwips& rExtraBlankWidth, tools::Long& rMaxSizeDiff, + SwTwips& rExtraAscent, SwTwips& rExtraDescent, const SwTextFormatInfo& rInf, const SwScriptInfo& rSI, sal_uInt16 maxComp, std::optional nLayoutContext) @@ -141,9 +142,11 @@ bool maybeAdjustPositionsForBlockAdjust(TextFrameIndex& rCutPos, TextFrameIndex& rBreakPos = breakPos; rInf.GetTextSize(&rSI, rInf.GetIdx(), breakPos - rInf.GetIdx(), nLayoutContext, maxComp, - rBreakWidth, rMaxSizeDiff, rInf.GetCachedVclData().get()); + rBreakWidth, rMaxSizeDiff, rExtraAscent, rExtraDescent, + rInf.GetCachedVclData().get()); rInf.GetTextSize(&rSI, breakPos, rBreakStart - breakPos, nLayoutContext, maxComp, - rExtraBlankWidth, rMaxSizeDiff, rInf.GetCachedVclData().get()); + rExtraBlankWidth, rMaxSizeDiff, rExtraAscent, rExtraDescent, + rInf.GetCachedVclData().get()); return false; // require SwHolePortion creation } @@ -168,6 +171,8 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf, OSL_ENSURE( nPorHeight, "+SwTextGuess::Guess: no height" ); tools::Long nMaxSizeDiff; + SwTwips nExtraAscent = 0; + SwTwips nExtraDescent = 0; const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo(); @@ -249,17 +254,17 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf, { // call GetTextSize with maximum compression (for kanas) rInf.GetTextSize(&rSI, rInf.GetIdx(), nMaxLen, rInf.GetLayoutContext(), nMaxComp, - m_nBreakWidth, nMaxSizeDiff); + m_nBreakWidth, nMaxSizeDiff, nExtraAscent, nExtraDescent); if ( ( m_nBreakWidth <= nLineWidth ) || ( bUnbreakableNumberings && rPor.IsNumberPortion() ) ) { // portion fits to line m_nCutPos = rInf.GetIdx() + nMaxLen; bool bRet = rPor.InFieldGrp() - || maybeAdjustPositionsForBlockAdjust(m_nCutPos, m_nBreakPos, m_nBreakStart, - m_nBreakWidth, m_nExtraBlankWidth, - nMaxSizeDiff, rInf, rSI, nMaxComp, - rInf.GetLayoutContext()); + || maybeAdjustPositionsForBlockAdjust( + m_nCutPos, m_nBreakPos, m_nBreakStart, m_nBreakWidth, + m_nExtraBlankWidth, nMaxSizeDiff, nExtraAscent, nExtraDescent, rInf, + rSI, nMaxComp, rInf.GetLayoutContext()); if( nItalic && (m_nCutPos >= TextFrameIndex(rInf.GetText().getLength()) || // #i48035# Needed for CalcFitToContent @@ -271,6 +276,9 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf, if ( nMaxSizeDiff ) rInf.SetMaxWidthDiff( &rPor, nMaxSizeDiff ); + rInf.SetExtraAscent(nExtraAscent); + rInf.SetExtraDescent(nExtraDescent); + m_nBreakWidth += nLeftRightBorderSpace; return bRet; @@ -422,7 +430,7 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf, { SwTwips nMinSize; rInf.GetTextSize(&rSI, rInf.GetIdx(), m_nCutPos - rInf.GetIdx(), std::nullopt, nMaxComp, - nMinSize, nMaxSizeDiff); + nMinSize, nMaxSizeDiff, nExtraAscent, nExtraDescent); OSL_ENSURE( nMinSize <= nLineWidth, "What a Guess!!!" ); } #endif @@ -433,17 +441,17 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf, // second check if everything fits to line m_nCutPos = m_nBreakPos = rInf.GetIdx() + nMaxLen - TextFrameIndex(1); rInf.GetTextSize(&rSI, rInf.GetIdx(), nMaxLen, rInf.GetLayoutContext(), nMaxComp, - m_nBreakWidth, nMaxSizeDiff); + m_nBreakWidth, nMaxSizeDiff, nExtraAscent, nExtraDescent); // The following comparison should always give true, otherwise // there likely has been a pixel rounding error in GetTextBreak if ( m_nBreakWidth <= nLineWidth ) { bool bRet = rPor.InFieldGrp() - || maybeAdjustPositionsForBlockAdjust(m_nCutPos, m_nBreakPos, m_nBreakStart, - m_nBreakWidth, m_nExtraBlankWidth, - nMaxSizeDiff, rInf, rSI, nMaxComp, - rInf.GetLayoutContext()); + || maybeAdjustPositionsForBlockAdjust( + m_nCutPos, m_nBreakPos, m_nBreakStart, m_nBreakWidth, + m_nExtraBlankWidth, nMaxSizeDiff, nExtraAscent, nExtraDescent, rInf, + rSI, nMaxComp, rInf.GetLayoutContext()); if (nItalic && (m_nBreakPos + TextFrameIndex(1)) >= TextFrameIndex(rInf.GetText().getLength())) m_nBreakWidth += nItalic; @@ -452,6 +460,9 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf, if ( nMaxSizeDiff ) rInf.SetMaxWidthDiff( &rPor, nMaxSizeDiff ); + rInf.SetExtraAscent(nExtraAscent); + rInf.SetExtraDescent(nExtraDescent); + m_nBreakWidth += nLeftRightBorderSpace; return bRet; @@ -736,12 +747,15 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf, if( nPorLen ) { rInf.GetTextSize(&rSI, rInf.GetIdx(), nPorLen, std::nullopt, nMaxComp, m_nBreakWidth, - nMaxSizeDiff, rInf.GetCachedVclData().get()); + nMaxSizeDiff, nExtraAscent, nExtraDescent, rInf.GetCachedVclData().get()); // save maximum width for later use if ( nMaxSizeDiff ) rInf.SetMaxWidthDiff( &rPor, nMaxSizeDiff ); + rInf.SetExtraAscent(nExtraAscent); + rInf.SetExtraDescent(nExtraDescent); + m_nBreakWidth += nItalic + nLeftRightBorderSpace; } else @@ -751,7 +765,8 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf, { rInf.GetTextSize(&rSI, rInf.GetIdx() + nPorLen, m_nBreakStart - rInf.GetIdx() - nPorLen - m_nFieldDiff, std::nullopt, - nMaxComp, m_nExtraBlankWidth, nMaxSizeDiff, rInf.GetCachedVclData().get()); + nMaxComp, m_nExtraBlankWidth, nMaxSizeDiff, nExtraAscent, nExtraDescent, + rInf.GetCachedVclData().get()); } if( m_pHanging ) diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx index 40b113fa41da..25bd4578e025 100644 --- a/sw/source/core/text/inftxt.cxx +++ b/sw/source/core/text/inftxt.cxx @@ -86,7 +86,6 @@ using namespace ::com::sun::star::linguistic2; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::beans; -#define CHAR_UNDERSCORE u'_' #define CHAR_LEFT_ARROW u'\x25C0' #define CHAR_RIGHT_ARROW u'\x25B6' #define CHAR_TAB u'\x2192' @@ -438,7 +437,8 @@ void SwTextSizeInfo::GetTextSize(const SwScriptInfo* pSI, const TextFrameIndex n const TextFrameIndex nLength, std::optional nLayoutContext, const sal_uInt16 nComp, SwTwips& nMinSize, - tools::Long& nMaxSizeDiff, + tools::Long& nMaxSizeDiff, SwTwips& nExtraAscent, + SwTwips& nExtraDescent, vcl::text::TextLayoutCache const* const pCache) const { SwDrawTextInfo aDrawInf(m_pVsh, *m_pOut, pSI, *m_pText, nIndex, nLength, nLayoutContext, 0, @@ -449,6 +449,8 @@ void SwTextSizeInfo::GetTextSize(const SwScriptInfo* pSI, const TextFrameIndex n aDrawInf.SetKanaComp( nComp ); SwPosSize aSize( m_pFnt->GetTextSize_( aDrawInf ) ); nMaxSizeDiff = aDrawInf.GetKanaDiff(); + nExtraAscent = aDrawInf.GetExtraAscent(); + nExtraDescent = aDrawInf.GetExtraDescent(); nMinSize = aSize.Width(); } @@ -1624,6 +1626,8 @@ void SwTextFormatInfo::CtorInitTextFormatInfo( OutputDevice* pRenderContext, SwT m_nFirst = 0; m_nRealWidth = 0; m_nForcedLeftMargin = 0; + m_nExtraAscent = 0; + m_nExtraDescent = 0; m_pRest = nullptr; m_nLineHeight = 0; m_nLineNetHeight = 0; @@ -1722,8 +1726,9 @@ void SwTextFormatInfo::Init() m_cTabDecimal = 0; m_nWidth = m_nRealWidth; m_nForcedLeftMargin = 0; + m_nExtraAscent = 0; + m_nExtraDescent = 0; m_nSoftHyphPos = TextFrameIndex(0); - m_nUnderScorePos = TextFrameIndex(COMPLETE_STRING); m_nLastBookmarkPos = TextFrameIndex(-1); m_cHookChar = 0; SetIdx(TextFrameIndex(0)); @@ -1756,7 +1761,6 @@ SwTextFormatInfo::SwTextFormatInfo( const SwTextFormatInfo& rInf, m_pLastTab(nullptr), m_nSoftHyphPos(TextFrameIndex(0)), m_nLineStart(rInf.GetIdx()), - m_nUnderScorePos(TextFrameIndex(COMPLETE_STRING)), m_nLeft(rInf.m_nLeft), m_nRight(rInf.m_nRight), m_nFirst(rInf.m_nLeft), @@ -1765,6 +1769,8 @@ SwTextFormatInfo::SwTextFormatInfo( const SwTextFormatInfo& rInf, m_nLineHeight(0), m_nLineNetHeight(0), m_nForcedLeftMargin(0), + m_nExtraAscent(0), + m_nExtraDescent(0), m_bFull(false), m_bFootnoteDone(true), m_bErgoDone(true), @@ -1875,11 +1881,6 @@ TextFrameIndex SwTextFormatInfo::ScanPortionEnd(TextFrameIndex const nStart, m_cHookChar = cPos; return i; - case CHAR_UNDERSCORE: - if (TextFrameIndex(COMPLETE_STRING) == m_nUnderScorePos) - m_nUnderScorePos = i; - break; - default: if ( cTabDec ) { diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx index 4cc49a0e3e57..4a79177366c9 100644 --- a/sw/source/core/text/inftxt.hxx +++ b/sw/source/core/text/inftxt.hxx @@ -254,6 +254,7 @@ public: void GetTextSize(const SwScriptInfo* pSI, TextFrameIndex nIdx, TextFrameIndex nLen, std::optional nLayoutContext, const sal_uInt16 nComp, SwTwips& nMinSize, tools::Long& nMaxSizeDiff, + SwTwips& nExtraAscent, SwTwips& nExtraDescent, vcl::text::TextLayoutCache const* = nullptr) const; inline SwPosSize GetTextSize(const SwScriptInfo* pSI, TextFrameIndex nIdx, TextFrameIndex nLen) const; @@ -493,7 +494,6 @@ class SwTextFormatInfo : public SwTextPaintInfo TextFrameIndex m_nSoftHyphPos; ///< SoftHyphPos for Hyphenation TextFrameIndex m_nLineStart; ///< Current line start in rText - TextFrameIndex m_nUnderScorePos; ///< enlarge repaint if underscore has been found TextFrameIndex m_nLastBookmarkPos; ///< need to check for bookmarks at every portion // #i34348# Changed type from sal_uInt16 to SwTwips SwTwips m_nLeft; // Left margin @@ -506,6 +506,8 @@ class SwTextFormatInfo : public SwTextPaintInfo SwTwips m_nLineHeight; // Final height after CalcLine SwTwips m_nLineNetHeight; // line height without spacing SwTwips m_nForcedLeftMargin; // Shift of left margin due to frame + SwTwips m_nExtraAscent = 0; // Enlarge clipping area for glyphs above the line height + SwTwips m_nExtraDescent = 0; // Enlarge clipping area for glyphs below the line height bool m_bFull : 1; // Line is full bool m_bFootnoteDone : 1; // Footnote already formatted @@ -678,8 +680,12 @@ public: // Should the hyphenate helper be discarded? bool IsHyphenate() const; - TextFrameIndex GetUnderScorePos() const { return m_nUnderScorePos; } - void SetUnderScorePos(TextFrameIndex const nNew) { m_nUnderScorePos = nNew; } + + SwTwips GetExtraAscent() const { return m_nExtraAscent; } + void SetExtraAscent(SwTwips nNew) { m_nExtraAscent = std::max(m_nExtraAscent, nNew); } + + SwTwips GetExtraDescent() const { return m_nExtraDescent; } + void SetExtraDescent(SwTwips nNew) { m_nExtraDescent = std::max(m_nExtraDescent, nNew); } // Calls HyphenateWord() of Hyphenator css::uno::Reference< css::linguistic2::XHyphenatedWord > diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 9d8e9ae0b77a..430e8d9aa778 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -177,7 +177,6 @@ SwLinePortion *SwTextFormatter::Underflow( SwTextFormatInfo &rInf ) // Can be seen in 8081.sdw, if you enter text in the first line TextFrameIndex const nSoftHyphPos = rInf.GetSoftHyphPos(); - TextFrameIndex const nUnderScorePos = rInf.GetUnderScorePos(); // Save flys and set to 0, or else segmentation fault // Not ClearFly(rInf) ! @@ -190,7 +189,6 @@ SwLinePortion *SwTextFormatter::Underflow( SwTextFormatInfo &rInf ) // Truncate() rInf.SetUnderflow(nullptr); rInf.SetSoftHyphPos( nSoftHyphPos ); - rInf.SetUnderScorePos( nUnderScorePos ); rInf.SetPaintOfst( GetLeftMargin() ); // We look for the portion with the under-flow position diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx index f02beed8ce5b..2a19650acb92 100644 --- a/sw/source/core/text/itrpaint.cxx +++ b/sw/source/core/text/itrpaint.cxx @@ -222,7 +222,7 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip, GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() ) { bClip = false; - rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() ); + rClip.ChgClip(rPaint, m_pFrame, m_pCurr->GetExtraAscent(), m_pCurr->GetExtraDescent()); } #if OSL_DEBUG_LEVEL > 1 static bool bClipAlways = false; @@ -255,7 +255,7 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip, // tdf#117448 at small fixed line height, enlarge clipping area in table cells // to show previously clipped text content on the area of paragraph margins if ( rFrame.IsInTab() ) - rClip.ChgClip( aLineRect, m_pFrame, false, rFrame.GetTopMargin(), rFrame.GetBottomMargin() ); + rClip.ChgClip(aLineRect, m_pFrame, rFrame.GetTopMargin(), rFrame.GetBottomMargin()); else rClip.ChgClip( aLineRect, m_pFrame ); bClip = false; @@ -377,7 +377,7 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip, GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight ) { bClip = false; - rClip.ChgClip( rPaint, m_pFrame, m_pCurr->HasUnderscore() ); + rClip.ChgClip(rPaint, m_pFrame, m_pCurr->GetExtraAscent(), m_pCurr->GetExtraDescent()); } // Portions, which lay "below" the text like post-its diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx index 6e8cfa4a3770..459486b99ba5 100644 --- a/sw/source/core/text/porfld.cxx +++ b/sw/source/core/text/porfld.cxx @@ -337,10 +337,6 @@ bool SwFieldPortion::Format( SwTextFormatInfo &rInf ) } rInf.SetLen( nFullLen ); - if (TextFrameIndex(COMPLETE_STRING) != rInf.GetUnderScorePos() && - rInf.GetUnderScorePos() > rInf.GetIdx() ) - rInf.SetUnderScorePos( rInf.GetIdx() ); - if( m_pFont ) m_pFont->AllocFontCacheId( rInf.GetVsh(), m_pFont->GetActual() ); diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 44f709eec1f1..bb33c11bf8b4 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -844,8 +844,7 @@ void SwLineLayout::ResetFlags() SwLineLayout::SwLineLayout() : m_pNext( nullptr ), m_nRealHeight( 0 ), - m_nTextHeight( 0 ), - m_bUnderscore( false ) + m_nTextHeight( 0 ) { ResetFlags(); SetWhichPor( PortionType::Lay ); diff --git a/sw/source/core/text/porlay.hxx b/sw/source/core/text/porlay.hxx index fe8aeb861e50..3d0ce27e3884 100644 --- a/sw/source/core/text/porlay.hxx +++ b/sw/source/core/text/porlay.hxx @@ -83,6 +83,8 @@ private: std::unique_ptr> m_pKanaComp; // Used for Kana compression SwTwips m_nRealHeight; // The height resulting from line spacing and register SwTwips m_nTextHeight; // The max height of all non-FlyCnt portions in this Line + SwTwips m_nExtraAscent = 0; + SwTwips m_nExtraDescent = 0; bool m_bFormatAdj : 1; bool m_bDummy : 1; bool m_bEndHyph : 1; @@ -97,7 +99,6 @@ private: bool m_bRedlineEnd: 1; // Redlining for paragraph mark: tracked change at the end bool m_bForcedLeftMargin : 1; // Left adjustment moved by the Fly bool m_bHanging : 1; // Contains a hanging portion in the margin - bool m_bUnderscore : 1; enum RedlineType m_eRedlineEnd; // redline type of pilcrow and line break symbols @@ -146,8 +147,6 @@ public: bool HasForcedLeftMargin() const { return m_bForcedLeftMargin; } void SetHanging( const bool bNew ) { m_bHanging = bNew; } bool IsHanging() const { return m_bHanging; } - void SetUnderscore( const bool bNew ) { m_bUnderscore = bNew; } - bool HasUnderscore() const { return m_bUnderscore; } // Respecting empty dummy lines void SetDummy( const bool bNew ) { m_bDummy = bNew; } @@ -173,6 +172,12 @@ public: SwTwips GetTextHeight() const { return m_nTextHeight; } + void SetExtraAscent(SwTwips nNew) { m_nExtraAscent = nNew; } + SwTwips GetExtraAscent() const { return m_nExtraAscent; } + + void SetExtraDescent(SwTwips nNew) { m_nExtraDescent = nNew; } + SwTwips GetExtraDescent() const { return m_nExtraDescent; } + // Creates the glue chain for short lines SwMarginPortion *CalcLeftMargin(); diff --git a/sw/source/core/text/txtpaint.cxx b/sw/source/core/text/txtpaint.cxx index ccd9647bd99c..5b05b413fab9 100644 --- a/sw/source/core/text/txtpaint.cxx +++ b/sw/source/core/text/txtpaint.cxx @@ -41,7 +41,6 @@ SwSaveClip::~SwSaveClip() } void SwSaveClip::ChgClip_( const SwRect &rRect, const SwTextFrame* pFrame, - bool bEnlargeRect, sal_Int32 nEnlargeTop, sal_Int32 nEnlargeBottom ) { @@ -74,12 +73,6 @@ void SwSaveClip::ChgClip_( const SwRect &rRect, const SwTextFrame* pFrame, { tools::Rectangle aRect( rRect.SVRect() ); - // Having underscores in our line, we enlarged the repaint area - // (see frmform.cxx) because for some fonts it could be too small. - // Consequently, we have to enlarge the clipping rectangle as well. - if ( bEnlargeRect && ! bVertical ) - aRect.AdjustBottom(40 ); - // enlarge clip for paragraph margins at small fixed line height if ( nEnlargeTop > 0 ) aRect.AdjustTop( -nEnlargeTop ); diff --git a/sw/source/core/text/txtpaint.hxx b/sw/source/core/text/txtpaint.hxx index 1f9700af4c96..3554a2421415 100644 --- a/sw/source/core/text/txtpaint.hxx +++ b/sw/source/core/text/txtpaint.hxx @@ -32,7 +32,6 @@ class SwSaveClip final VclPtr m_pOut; void ChgClip_( const SwRect &rRect, const SwTextFrame* pFrame, - bool bEnlargeRect, sal_Int32 nEnlargeTop, sal_Int32 nEnlargeBottom ); public: @@ -44,12 +43,14 @@ public: } ~SwSaveClip(); - void ChgClip( const SwRect &rRect, const SwTextFrame* pFrame = nullptr, - bool bEnlargeRect = false, - sal_Int32 nEnlargeTop = 0, - sal_Int32 nEnlargeBottom = 0) - { if( m_pOut ) ChgClip_( rRect, pFrame, - bEnlargeRect, nEnlargeTop, nEnlargeBottom ); } + void ChgClip(const SwRect& rRect, const SwTextFrame* pFrame = nullptr, + sal_Int32 nEnlargeTop = 0, sal_Int32 nEnlargeBottom = 0) + { + if (m_pOut) + { + ChgClip_(rRect, pFrame, nEnlargeTop, nEnlargeBottom); + } + } bool IsOn() const { return m_bOn; } bool IsChg() const { return m_bChg; } }; diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx index fd42378b1bdc..52a9e71dff1d 100644 --- a/sw/source/core/txtnode/fntcache.cxx +++ b/sw/source/core/txtnode/fntcache.cxx @@ -745,9 +745,12 @@ static void lcl_DrawLineForWrongListData( static void GetTextArray(const OutputDevice& rDevice, const OUString& rStr, KernArray& rDXAry, sal_Int32 nIndex, sal_Int32 nLen, std::optional nLayoutContext, + SwTwips* nMaxAscent = nullptr, SwTwips* nMaxDescent = nullptr, bool bCaret = false, const vcl::text::TextLayoutCache* layoutCache = nullptr) { + vcl::TextArrayMetrics stMetrics; + if (nLayoutContext.has_value()) { auto nStrEnd = nIndex + nLen; @@ -757,14 +760,28 @@ static void GetTextArray(const OutputDevice& rDevice, const OUString& rStr, Kern const SalLayoutGlyphs* pLayoutCache = SalLayoutGlyphsCache::self()->GetLayoutGlyphs( &rDevice, rStr, nContextBegin, nContextLen, nIndex, nIndex + nLen, 0, layoutCache); - rDevice.GetPartialTextArray(rStr, &rDXAry, nContextBegin, nContextLen, nIndex, nLen, bCaret, - layoutCache, pLayoutCache); + stMetrics = rDevice.GetPartialTextArray(rStr, &rDXAry, nContextBegin, nContextLen, nIndex, + nLen, bCaret, layoutCache, pLayoutCache); } else { const SalLayoutGlyphs* pLayoutCache = SalLayoutGlyphsCache::self()->GetLayoutGlyphs( &rDevice, rStr, nIndex, nLen, 0, layoutCache); - rDevice.GetTextArray(rStr, &rDXAry, nIndex, nLen, bCaret, layoutCache, pLayoutCache); + stMetrics + = rDevice.GetTextArray(rStr, &rDXAry, nIndex, nLen, bCaret, layoutCache, pLayoutCache); + } + + if (stMetrics.aBounds.has_value()) + { + if (nMaxAscent) + { + *nMaxAscent = static_cast(std::ceil(-stMetrics.aBounds->Top())); + } + + if (nMaxDescent) + { + *nMaxDescent = static_cast(std::ceil(stMetrics.aBounds->Bottom())); + } } } @@ -772,16 +789,16 @@ static void GetTextArray(const OutputDevice& rOutputDevice, const SwDrawTextInfo KernArray& rDXAry, bool bCaret = false) { GetTextArray(rOutputDevice, rInf.GetText(), rDXAry, rInf.GetIdx().get(), rInf.GetLen().get(), - rInf.GetLayoutContext(), bCaret, rInf.GetVclCache()); + rInf.GetLayoutContext(), nullptr, nullptr, bCaret, rInf.GetVclCache()); } static void GetTextArray(const OutputDevice& rOutputDevice, const SwDrawTextInfo& rInf, - KernArray& rDXAry, sal_Int32 nLen, bool bCaret = false) + KernArray& rDXAry, sal_Int32 nLen, SwTwips *nMaxAscent = nullptr, SwTwips *nMaxDescent = nullptr, bool bCaret = false) { // Substring is fine. assert(nLen <= rInf.GetLen().get()); GetTextArray(rOutputDevice, rInf.GetText(), rDXAry, rInf.GetIdx().get(), nLen, - rInf.GetLayoutContext(), bCaret, rInf.GetVclCache()); + rInf.GetLayoutContext(), nMaxAscent, nMaxDescent, bCaret, rInf.GetVclCache()); } static void DrawTextArray(OutputDevice& rOutputDevice, const Point& rStartPt, const OUString& rStr, @@ -1581,6 +1598,8 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) { Size aTextSize; + SwTwips nMaxAscent = 0; + SwTwips nMaxDescent = 0; const TextFrameIndex nLn = (TextFrameIndex(COMPLETE_STRING) != rInf.GetLen()) ? rInf.GetLen() : TextFrameIndex(rInf.GetText().getLength()); @@ -1631,7 +1650,8 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) GetFontLeading( rInf.GetShell(), rInf.GetOut() ) ); KernArray aKernArray; - GetTextArray(*pOutDev, rInf, aKernArray, sal_Int32(nLn), bCaret); + GetTextArray(*pOutDev, rInf, aKernArray, sal_Int32(nLn), &nMaxAscent, &nMaxDescent, + bCaret); if (pGrid->IsSnapToChars()) { sw::Justify::SnapToGrid(aKernArray, rInf.GetText(), sal_Int32(rInf.GetIdx()), @@ -1674,7 +1694,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) rInf.GetOut().SetFont( *m_pScrFont ); GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray, sal_Int32(rInf.GetIdx()), - sal_Int32(nLn), rInf.GetLayoutContext(), bCaret); + sal_Int32(nLn), rInf.GetLayoutContext(), &nMaxAscent, &nMaxDescent, bCaret); } else { @@ -1682,9 +1702,12 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) rInf.GetOut().SetFont( *m_pPrtFont ); aTextSize.setHeight( rInf.GetOut().GetTextHeight() ); - GetTextArray(rInf.GetOut(), rInf, aKernArray, nLn.get(), bCaret); + GetTextArray(rInf.GetOut(), rInf, aKernArray, nLn.get(), &nMaxAscent, &nMaxDescent, bCaret); } + rInf.SetExtraAscent(std::max(SwTwips{ 0 }, nMaxAscent)); + rInf.SetExtraDescent(std::max(SwTwips{ 0 }, nMaxDescent)); + if (bCompress) { rInf.SetKanaDiff(rInf.GetScriptInfo()->Compress(aKernArray, rInf.GetIdx(), nLn, rInf.GetKanaComp(), diff --git a/toolkit/source/awt/vclxfont.cxx b/toolkit/source/awt/vclxfont.cxx index 47fad780d73b..32a42dec7579 100644 --- a/toolkit/source/awt/vclxfont.cxx +++ b/toolkit/source/awt/vclxfont.cxx @@ -153,7 +153,7 @@ sal_Int32 VCLXFont::getStringWidthArray( const OUString& str, css::uno::Sequence vcl::Font aOldFont = pOutDev->GetFont(); pOutDev->SetFont( maFont ); KernArray aDXA; - nRet = basegfx::fround(pOutDev->GetTextArray(str, &aDXA)); + nRet = basegfx::fround(pOutDev->GetTextArray(str, &aDXA).nWidth); rDXArray.realloc(aDXA.size()); sal_Int32* pArray = rDXArray.getArray(); for (size_t i = 0, nLen = aDXA.size(); i < nLen; ++i) diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx index 24958c0b0637..b7a04d98ad80 100644 --- a/vcl/qa/cppunit/complextext.cxx +++ b/vcl/qa/cppunit/complextext.cxx @@ -86,7 +86,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testArabic) 3899, 4550, 5119, 5689, 5689, 6307, 6925, 8484, 9135, 9705, 10927, 10927, 11497, 12595, 12595 }; KernArray aCharWidths; - tools::Long nTextWidth = basegfx::fround(pOutDev->GetTextArray(aOneTwoThree, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround(pOutDev->GetTextArray(aOneTwoThree, &aCharWidths).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); // this sporadically returns 75 or 74 on some of the windows tinderboxes eg. tb73 @@ -267,7 +268,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testCaret) // and the next ones are all zero width. nRefTextWidth = 3611; aRefCharWidths = { 1168, 1168, 1819, 2389, 3611, 3611 }; - nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/false)); + nTextWidth = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ false).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back()); @@ -275,7 +277,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testCaret) // 2) Caret placement DX array, ligature width is distributed over its // components. aRefCharWidths = { 584, 1168, 1819, 2389, 3000, 3611 }; - nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ true).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back()); @@ -284,7 +287,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testCaret) // component count. aText = u"لَاَ بلَاَ"_ustr; aRefCharWidths = { 584, 584, 1168, 1168, 1819, 2389, 3000, 3000, 3611, 3611 }; - nTextWidth2 = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth2 = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ true).nWidth); CPPUNIT_ASSERT_EQUAL(aCharWidths[0], aCharWidths[1]); CPPUNIT_ASSERT_EQUAL(aCharWidths[2], aCharWidths[3]); CPPUNIT_ASSERT_EQUAL(aCharWidths[6], aCharWidths[7]); @@ -301,7 +305,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testCaret) // and the next ones are all zero width. nRefTextWidth = 8493; aRefCharWidths = { 1290, 1290, 1941, 3231, 3231, 3882, 5862, 5862, 5862, 6513, 8493, 8493, 8493 }; - nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/false)); + nTextWidth = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ false).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back()); @@ -309,7 +314,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testCaret) // 2) Caret placement DX array, ligature width is distributed over its // components. aRefCharWidths = { 645, 1290, 1941, 2586, 3231, 3882, 4542, 5202, 5862, 6513, 7173, 7833, 8493 }; - nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ true).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back()); @@ -340,7 +346,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testGdefCaret) // and the next ones are all zero width. nRefTextWidth = 1710; aRefCharWidths= { 582, 582, 842, 1111, 1710, 1710 }; - nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/false)); + nTextWidth = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ false).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back()); @@ -348,7 +355,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testGdefCaret) // 2) Caret placement DX array, ligature width is distributed over its // components. aRefCharWidths = { 291, 582, 842, 1111, 1410, 1710 }; - nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ true).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back()); @@ -357,7 +365,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testGdefCaret) // component count. aText = u"لَاَ بلَاَ"_ustr; aRefCharWidths = { 291, 291, 582, 582, 842, 1111, 1410, 1410, 1710, 1710 }; - nTextWidth2 = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth2 = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ true).nWidth); CPPUNIT_ASSERT_EQUAL(aCharWidths[0], aCharWidths[1]); CPPUNIT_ASSERT_EQUAL(aCharWidths[2], aCharWidths[3]); CPPUNIT_ASSERT_EQUAL(aCharWidths[6], aCharWidths[7]); @@ -379,7 +388,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testGdefCaret) nRefTextWidth = 5996; aRefCharWidths = { 519, 519, 811, 1606, 1606, 1606, 1898, 2439, 2439, 2731, 3544, 3544, 3544, 3836, 4634, 4634, 4926, 5996, 5996, 5996 }; - nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/false)); + nTextWidth = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ false).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back()); @@ -388,7 +398,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testGdefCaret) // components. aRefCharWidths = { 269, 519, 811, 1080, 1348, 1606, 1898, 2171, 2439, 2731, 3004, 3278, 3544, 3836, 4138, 4634, 4926, 5199, 5494, 5996 }; - nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth = basegfx::fround( + pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/ true).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back()); @@ -410,7 +421,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testTdf152048) tools::Long nRefTextWidth(5495); KernArray aCharWidths; - tools::Long nTextWidth = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround(pOutDev->GetTextArray(aText, &aCharWidths).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); @@ -443,7 +455,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testTdf152048_2) // get an compare the default text array KernArray aCharWidths; - auto nTextWidth = basegfx::fround(pOutDev->GetTextArray(u"ع a ع"_ustr, &aCharWidths)); + auto nTextWidth + = basegfx::fround(pOutDev->GetTextArray(u"ع a ع"_ustr, &aCharWidths).nWidth); // Text width should always be equal to the width of the last glyph in the // kern array. @@ -514,7 +527,8 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testMixedCJKLatinScript_glyph_advanceme tools::Long nRefTextWidth = 704; std::vector aRefCharWidths = { 72, 144, 190, 236, 259, 305, 333, 379, 425, 474, 523, 551, 567, 612, 658, 704 }; KernArray aCharWidths; - tools::Long nTextWidth = basegfx::fround(pOutDev->GetTextArray(aTestScript, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround(pOutDev->GetTextArray(aTestScript, &aCharWidths).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths.get_subunit_array()); CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth); @@ -621,7 +635,7 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testPartialKoreanJamoComposition) // Absolute character widths for the complete array. KernArray aCompleteWidths; - auto nCompleteWidth = pOutDev->GetTextArray(aStr, &aCompleteWidths); + auto nCompleteWidth = pOutDev->GetTextArray(aStr, &aCompleteWidths).nWidth; CPPUNIT_ASSERT_EQUAL(size_t{ 3 }, aCompleteWidths.size()); @@ -632,8 +646,11 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testPartialKoreanJamoComposition) for (sal_Int32 i = 0; i < 3; ++i) { KernArray aFragmentWidths; - auto nFragmentWidth = pOutDev->GetPartialTextArray( - aStr, &aFragmentWidths, /*nIndex*/ 0, /*nLen*/ 3, /*nPartIndex*/ i, /*nPartLen*/ 1); + auto nFragmentWidth + = pOutDev + ->GetPartialTextArray(aStr, &aFragmentWidths, /*nIndex*/ 0, /*nLen*/ 3, + /*nPartIndex*/ i, /*nPartLen*/ 1) + .nWidth; nPartialWidth += nFragmentWidth; CPPUNIT_ASSERT_EQUAL(size_t{ 1 }, aFragmentWidths.size()); @@ -654,7 +671,7 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testPartialArabicComposition) // Absolute character widths for the complete array. KernArray aCompleteWidths; - auto nCompleteWidth = pOutDev->GetTextArray(aStr, &aCompleteWidths); + auto nCompleteWidth = pOutDev->GetTextArray(aStr, &aCompleteWidths).nWidth; CPPUNIT_ASSERT_EQUAL(size_t{ 7 }, aCompleteWidths.size()); @@ -665,8 +682,11 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testPartialArabicComposition) for (sal_Int32 i = 0; i < 7; ++i) { KernArray aFragmentWidths; - auto nFragmentWidth = pOutDev->GetPartialTextArray( - aStr, &aFragmentWidths, /*nIndex*/ 0, /*nLen*/ 7, /*nPartIndex*/ i, /*nPartLen*/ 1); + auto nFragmentWidth + = pOutDev + ->GetPartialTextArray(aStr, &aFragmentWidths, /*nIndex*/ 0, /*nLen*/ 7, + /*nPartIndex*/ i, /*nPartLen*/ 1) + .nWidth; nPartialWidth += nFragmentWidth; CPPUNIT_ASSERT_EQUAL(size_t{ 1 }, aFragmentWidths.size()); diff --git a/vcl/qa/cppunit/text.cxx b/vcl/qa/cppunit/text.cxx index b8847f5c6247..3cf88138eb29 100644 --- a/vcl/qa/cppunit/text.cxx +++ b/vcl/qa/cppunit/text.cxx @@ -242,7 +242,8 @@ CPPUNIT_TEST_FIXTURE(VclTextTest, testSimpleTextFontSpecificKerning) tools::Long nRefTextWidth = 2671; std::vector aRefCharWidths = { 1270, 2671 }; KernArray aCharWidths; - tools::Long nTextWidth = basegfx::fround(pOutDev->GetTextArray(aAV, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround(pOutDev->GetTextArray(aAV, &aCharWidths).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths[0], aCharWidths.get_subunit_array()[0]); CPPUNIT_ASSERT_EQUAL(aRefCharWidths[1], aCharWidths.get_subunit_array()[1]); @@ -291,7 +292,8 @@ CPPUNIT_TEST_FIXTURE(VclTextTest, testSimpleTextNoKerning) tools::Long nRefTextWidth = 2802; std::vector aRefCharWidths = { 1401, 2802 }; KernArray aCharWidths; - tools::Long nTextWidth = basegfx::fround(pOutDev->GetTextArray(aAV, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround(pOutDev->GetTextArray(aAV, &aCharWidths).nWidth); CPPUNIT_ASSERT_EQUAL(aRefCharWidths[0], aCharWidths.get_subunit_array()[0]); CPPUNIT_ASSERT_EQUAL(aRefCharWidths[1], aCharWidths.get_subunit_array()[1]); @@ -1029,7 +1031,7 @@ CPPUNIT_TEST_FIXTURE(VclTextTest, testPartialTextArraySizeMatch) // Absolute character widths for the complete array. KernArray aCompleteWidths; - auto nCompleteWidth = pOutDev->GetTextArray(aWater, &aCompleteWidths); + auto nCompleteWidth = pOutDev->GetTextArray(aWater, &aCompleteWidths).nWidth; CPPUNIT_ASSERT_EQUAL(size_t{ 5 }, aCompleteWidths.size()); @@ -1040,8 +1042,11 @@ CPPUNIT_TEST_FIXTURE(VclTextTest, testPartialTextArraySizeMatch) for (sal_Int32 i = 0; i < 5; ++i) { KernArray aFragmentWidths; - auto nFragmentWidth = pOutDev->GetPartialTextArray( - aWater, &aFragmentWidths, /*nIndex*/ 0, /*nLen*/ 5, /*nPartIndex*/ i, /*nPartLen*/ 1); + auto nFragmentWidth + = pOutDev + ->GetPartialTextArray(aWater, &aFragmentWidths, /*nIndex*/ 0, /*nLen*/ 5, + /*nPartIndex*/ i, /*nPartLen*/ 1) + .nWidth; nPartialWidth += nFragmentWidth; CPPUNIT_ASSERT_EQUAL(size_t{ 1 }, aFragmentWidths.size()); diff --git a/vcl/source/filter/wmf/emfwr.cxx b/vcl/source/filter/wmf/emfwr.cxx index 3b349b9f70ac..92a2320369c1 100644 --- a/vcl/source/filter/wmf/emfwr.cxx +++ b/vcl/source/filter/wmf/emfwr.cxx @@ -882,7 +882,7 @@ void EMFWriter::ImplWriteTextRecord( const Point& rPos, const OUString& rText, K } else { - nNormWidth = basegfx::fround(maVDev->GetTextArray(rText, &aOwnArray)); + nNormWidth = basegfx::fround(maVDev->GetTextArray(rText, &aOwnArray).nWidth); pDX = aOwnArray; } diff --git a/vcl/source/filter/wmf/wmfwr.cxx b/vcl/source/filter/wmf/wmfwr.cxx index 3f975ec5e659..70b00a895720 100644 --- a/vcl/source/filter/wmf/wmfwr.cxx +++ b/vcl/source/filter/wmf/wmfwr.cxx @@ -1198,7 +1198,8 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) pVirDev->SetFont( aSrcFont ); const sal_Int32 nLen = aTemp.getLength(); KernArray aDXAry; - const sal_Int32 nNormSize = basegfx::fround(pVirDev->GetTextArray( aTemp, nLen ? &aDXAry : nullptr )); + const sal_Int32 nNormSize = basegfx::fround( + pVirDev->GetTextArray(aTemp, nLen ? &aDXAry : nullptr).nWidth); if (nLen && nNormSize == 0) { OSL_FAIL("Impossible div by 0 action: MetaStretchTextAction!"); diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx index 5c5edd3b0612..d0bdd7ccf68f 100644 --- a/vcl/source/outdev/text.cxx +++ b/vcl/source/outdev/text.cxx @@ -650,7 +650,7 @@ double OutputDevice::GetTextWidthDouble(const OUString& rStr, sal_Int32 nIndex, vcl::text::TextLayoutCache const* const pLayoutCache, SalLayoutGlyphs const* const pSalLayoutCache) const { - return GetTextArray(rStr, nullptr, nIndex, nLen, false, pLayoutCache, pSalLayoutCache); + return GetTextArray(rStr, nullptr, nIndex, nLen, false, pLayoutCache, pSalLayoutCache).nWidth; } tools::Long OutputDevice::GetTextHeight() const @@ -781,27 +781,26 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr, mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen, flags ); } -double OutputDevice::GetTextArray( const OUString& rStr, KernArray* pKernArray, - sal_Int32 nIndex, sal_Int32 nLen, bool bCaret, - vcl::text::TextLayoutCache const*const pLayoutCache, - SalLayoutGlyphs const*const pSalLayoutCache) const +vcl::TextArrayMetrics +OutputDevice::GetTextArray(const OUString& rStr, KernArray* pKernArray, sal_Int32 nIndex, + sal_Int32 nLen, bool bCaret, + vcl::text::TextLayoutCache const* const pLayoutCache, + SalLayoutGlyphs const* const pSalLayoutCache) const { return GetPartialTextArray(rStr, pKernArray, nIndex, nLen, nIndex, nLen, bCaret, pLayoutCache, pSalLayoutCache); } -double OutputDevice::GetPartialTextArray(const OUString &rStr, - KernArray* pKernArray, - sal_Int32 nIndex, - sal_Int32 nLen, - sal_Int32 nPartIndex, - sal_Int32 nPartLen, - bool bCaret, - const vcl::text::TextLayoutCache* pLayoutCache, - const SalLayoutGlyphs* pSalLayoutCache) const +vcl::TextArrayMetrics +OutputDevice::GetPartialTextArray(const OUString& rStr, KernArray* pKernArray, sal_Int32 nIndex, + sal_Int32 nLen, sal_Int32 nPartIndex, sal_Int32 nPartLen, + bool bCaret, const vcl::text::TextLayoutCache* pLayoutCache, + const SalLayoutGlyphs* pSalLayoutCache) const { - if( nIndex >= rStr.getLength() ) - return 0; // TODO: this looks like a buggy caller? + if (nIndex >= rStr.getLength()) + { + return {}; // TODO: this looks like a buggy caller? + } if( nLen < 0 || nIndex + nLen >= rStr.getLength() ) { @@ -844,7 +843,8 @@ double OutputDevice::GetPartialTextArray(const OUString &rStr, pDXAry->resize(nPartLen); std::fill(pDXAry->begin(), pDXAry->end(), 0); } - return 0; + + return {}; } std::unique_ptr> xDXPixelArray; @@ -902,7 +902,18 @@ double OutputDevice::GetPartialTextArray(const OUString &rStr, (*pDXAry)[i] = basegfx::fround((*pDXPixelArray)[i]); } - return ImplDevicePixelToLogicWidthDouble(nWidth); + vcl::TextArrayMetrics stReturnValue; + + basegfx::B2DRectangle stRect; + if (pSalLayout->GetBoundRect(stRect)) + { + auto stRect2 = SalLayout::BoundRect2Rectangle(stRect); + stReturnValue.aBounds = ImplDevicePixelToLogic(stRect2); + } + + stReturnValue.nWidth = ImplDevicePixelToLogicWidthDouble(nWidth); + + return stReturnValue; } void OutputDevice::GetCaretPositions( const OUString& rStr, KernArray& rCaretXArray, diff --git a/vcl/source/text/textlayout.cxx b/vcl/source/text/textlayout.cxx index d43549a589d3..5621a9d4c1f6 100644 --- a/vcl/source/text/textlayout.cxx +++ b/vcl/source/text/textlayout.cxx @@ -486,7 +486,8 @@ namespace vcl tools::Long DefaultTextLayout::GetTextArray( const OUString& _rText, KernArray* _pDXArray, sal_Int32 _nStartIndex, sal_Int32 _nLength, bool bCaret ) const { - return basegfx::fround(m_rTargetDevice.GetTextArray( _rText, _pDXArray, _nStartIndex, _nLength, bCaret )); + return basegfx::fround( + m_rTargetDevice.GetTextArray(_rText, _pDXArray, _nStartIndex, _nLength, bCaret).nWidth); } sal_Int32 DefaultTextLayout::GetTextBreak( const OUString& _rText, tools::Long _nMaxTextWidth, sal_Int32 _nStartIndex, sal_Int32 _nLength ) const @@ -594,7 +595,9 @@ namespace vcl return 0; // retrieve the character widths from the reference device - tools::Long nTextWidth = basegfx::fround(m_rReferenceDevice.GetTextArray( _rText, _pDXAry, _nStartIndex, _nLength, bCaret )); + tools::Long nTextWidth = basegfx::fround( + m_rReferenceDevice.GetTextArray(_rText, _pDXAry, _nStartIndex, _nLength, bCaret) + .nWidth); #if OSL_DEBUG_LEVEL > 1 if ( _pDXAry ) { -- cgit