summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Clark <jonathan@libreoffice.org>2024-06-07 02:36:22 -0600
committerJonathan Clark <jonathan@libreoffice.org>2024-06-10 17:11:32 +0200
commit976b16b1c6ad6e6eaded7a9fb24388c4512e21e2 (patch)
tree7d2e8793f6a2436ab67497463b2417dc952eaba7
parent2b68dadb846dac063421ed975abecafbd120cbac (diff)
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 <jonathan@libreoffice.org>
-rw-r--r--drawinglayer/source/processor2d/vclprocessor2d.cxx2
-rw-r--r--editeng/source/items/svxfont.cxx6
-rw-r--r--filter/source/svg/svgwriter.cxx3
-rw-r--r--include/vcl/outdev.hxx25
-rw-r--r--sw/source/core/inc/drawfont.hxx36
-rw-r--r--sw/source/core/text/frmform.cxx21
-rw-r--r--sw/source/core/text/guess.cxx45
-rw-r--r--sw/source/core/text/inftxt.cxx19
-rw-r--r--sw/source/core/text/inftxt.hxx12
-rw-r--r--sw/source/core/text/itrform2.cxx2
-rw-r--r--sw/source/core/text/itrpaint.cxx6
-rw-r--r--sw/source/core/text/porfld.cxx4
-rw-r--r--sw/source/core/text/porlay.cxx3
-rw-r--r--sw/source/core/text/porlay.hxx11
-rw-r--r--sw/source/core/text/txtpaint.cxx7
-rw-r--r--sw/source/core/text/txtpaint.hxx15
-rw-r--r--sw/source/core/txtnode/fntcache.cxx41
-rw-r--r--toolkit/source/awt/vclxfont.cxx2
-rw-r--r--vcl/qa/cppunit/complextext.cxx60
-rw-r--r--vcl/qa/cppunit/text.cxx15
-rw-r--r--vcl/source/filter/wmf/emfwr.cxx2
-rw-r--r--vcl/source/filter/wmf/wmfwr.cxx3
-rw-r--r--vcl/source/outdev/text.cxx47
-rw-r--r--vcl/source/text/textlayout.cxx7
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 )
{