diff options
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<tools::Long>( - 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<tools::Long>(pOut->GetTextArray( rStr, pDXAry, nIndex, nLen, true, nullptr, layoutGlyphs)); + return basegfx::fround<tools::Long>( + 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<tools::Long>(pOut->GetTextArray(_rTxt, &aKernArray, _nIdx, _nLen))); + aPartSize.setWidth(basegfx::fround<tools::Long>( + 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<tools::Long>(mpVDev->GetTextArray(rText, &aTmpArray)), 0); + aNormSize + = Size(basegfx::fround<tools::Long>(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<tools::Rectangle> 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<const sal_Bool> 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<SwLineLayout*>(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<SwLineLayout*>(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<SwLineLayout*>(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<SwLinePortionLayoutContext> 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<SwLinePortionLayoutContext> 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<SwLinePortionLayoutContext> 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<std::deque<sal_uInt16>> 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<OutputDevice> 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<SwLinePortionLayoutContext> 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<SwTwips>(std::ceil(-stMetrics.aBounds->Top())); + } + + if (nMaxDescent) + { + *nMaxDescent = static_cast<SwTwips>(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<tools::Long>(pOutDev->GetTextArray(aOneTwoThree, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround<tools::Long>(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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/false)); + nTextWidth = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth2 = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/false)); + nTextWidth = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/false)); + nTextWidth = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth2 = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/false)); + nTextWidth = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, /*bCaret*/true)); + nTextWidth = basegfx::fround<tools::Long>( + 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<tools::Long>(pOutDev->GetTextArray(aText, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround<tools::Long>(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<tools::Long>(pOutDev->GetTextArray(u"ع a ع"_ustr, &aCharWidths)); + auto nTextWidth + = basegfx::fround<tools::Long>(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<sal_Int32> aRefCharWidths = { 72, 144, 190, 236, 259, 305, 333, 379, 425, 474, 523, 551, 567, 612, 658, 704 }; KernArray aCharWidths; - tools::Long nTextWidth = basegfx::fround<tools::Long>(pOutDev->GetTextArray(aTestScript, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround<tools::Long>(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<sal_Int32> aRefCharWidths = { 1270, 2671 }; KernArray aCharWidths; - tools::Long nTextWidth = basegfx::fround<tools::Long>(pOutDev->GetTextArray(aAV, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround<tools::Long>(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<sal_Int32> aRefCharWidths = { 1401, 2802 }; KernArray aCharWidths; - tools::Long nTextWidth = basegfx::fround<tools::Long>(pOutDev->GetTextArray(aAV, &aCharWidths)); + tools::Long nTextWidth + = basegfx::fround<tools::Long>(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<sal_uInt32>(maVDev->GetTextArray(rText, &aOwnArray)); + nNormWidth = basegfx::fround<sal_uInt32>(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<std::vector<double>> 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<tools::Long>(m_rTargetDevice.GetTextArray( _rText, _pDXArray, _nStartIndex, _nLength, bCaret )); + return basegfx::fround<tools::Long>( + 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<tools::Long>(m_rReferenceDevice.GetTextArray( _rText, _pDXAry, _nStartIndex, _nLength, bCaret )); + tools::Long nTextWidth = basegfx::fround<tools::Long>( + m_rReferenceDevice.GetTextArray(_rText, _pDXAry, _nStartIndex, _nLength, bCaret) + .nWidth); #if OSL_DEBUG_LEVEL > 1 if ( _pDXAry ) { |