From 9e11a7494b2d875331a04961bfb0a28e695609d7 Mon Sep 17 00:00:00 2001 From: Mike Kaganski Date: Sat, 25 Jul 2026 20:32:52 +0500 Subject: [PATCH] tdf#171959 sw: keep trailing blank decorations inside the text area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit b36f181bb71c395f9c48c6358bea550ac4767839 (tdf#168777: Trailing space must show all decorations, also for ODF, 2025-10-11) made the trailing blank of a line show its underline by default. In a justified paragraph that underline is drawn past the right margin. A line's trailing blank lives in a hole portion, which deliberately takes no part in the layout (see 853e13f9146e83b959bc53152ec103470d55fb4f, tdf#57187: make sure to put trailing blanks to hole portion in narrow lines, 2023-12-30), so it hangs outside the line. When the blank is formatted, its decorated part is limited to the room then left on the line - but adjustment happens afterwards, and justification hands exactly that room to the glue between the words. The blank ends up beyond the text area with its decorations still on. Right-aligned text has the same problem, and centred text has it on lines that nearly fill the width. Reconsider the decorated part once the line is adjusted. The room still available is the width of the trailing margin portion(s), which is where adjustment parks whatever is left of the line, so no coordinates are needed. Lines that need no adjustment at all - left-aligned ones - get no margin portion, and keep the room they were formatted against. Where the room no longer fits the whole blank, the hole is split: the first part is decorated and as wide as the room, a plain hole carries the rest. A hole holds nothing but blanks, so the characters divide between the two in proportion to the width, and the cursor still travels over the whole blank. The blank also took a share of the justification stretch while being painted, which made the overshoot about twice the width of a space. It is not part of the line's content, so exclude it. Signed-off-by: Mike Kaganski Change-Id: I82dfe55a10f7b15969bc4561f8f2f04eb7eeee52 Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/7834 Reviewed-by: Caolán McNamara Tested-by: Jenkins CPCI (cherry picked from commit 6ebdd28de79e412501152305b48a64d25b3609c5) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208741 Tested-by: Xisco Fauli Reviewed-by: Xisco Fauli --- sw/qa/extras/layout/data/tdf171959-center.odt | Bin 0 -> 18454 bytes sw/qa/extras/layout/data/tdf171959.odt | Bin 0 -> 20365 bytes sw/qa/extras/layout/layout4.cxx | 78 ++++++++++++++++++ sw/source/core/text/inftxt.cxx | 5 +- sw/source/core/text/itrcrsr.cxx | 76 +++++++++++++++++ sw/source/core/text/portxt.hxx | 1 + 6 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 sw/qa/extras/layout/data/tdf171959-center.odt create mode 100644 sw/qa/extras/layout/data/tdf171959.odt diff --git a/sw/qa/extras/layout/data/tdf171959-center.odt b/sw/qa/extras/layout/data/tdf171959-center.odt new file mode 100644 index 0000000000000000000000000000000000000000..748e3420ab754db5920ea1c1364aa859c3e1bc32 GIT binary patch literal 18454 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ЛuR4l$Hlz`3_I-er3Cj3As@gr=&A80G>Vb(^YXE5QsBW|9FW8Z5g!1I_ zWREKf2Wzs@*AF>)N{Wq0Wf|TGGk5KTELX}0q4ZB~<`W`kyoNlC2pc|VMCZH34Pp3P zg?ydnk9?8RMg>uOmw@JpoXRybFi@ zU|WOOW#w{mMj4A4zSC7Z)An{2CGRnWs8#oHr`3B2JkrlXQ7)oV@;zrq4Lp3CY-yWN z)Ar?Y@OgY2+XCn)Pws=)`r0iPeJ{>%#cGl^kTmUr>WR}o#Vbe@mcWlK>YB%DXa+M4 zG}d*CrOgN3l(|}AbSPJ}Kh8Cb#=!zCo&lK_)*a{S7TNO~ndE##62TxInG#A8zPnDU z32|_yFC{!`ZU)slb{K%hP#-iZ!ZUOlym!Pen0>HsJ&7-1`FtXM| zwYvB`M(>4WS2g@D=mNzG{%S7+Z2F+*Qu|b;t&MH(G@e~atr~JxlsJe{#t;muhiWtt zcPglHdFV3Rf@M{kE2W^PG=B@vs+iUh@(lF&?q&Vmd2w^$RXu`V$Mh5hRZ#3#9>_Vd zR%vp?;z>fyr7lhF7r;rW%Dt>OYVm*Dm@aGeSLD9)ys&GzWlQh)RKJ@8BXaH z4P6P4lb$BIbjv(X&q)~ZNhH56vWmiwjnS3*MS#*RH3zqP75m9TGP8)zv`^21$N8@#kX^~M}*#c-sI?WnSbuhE_W*HecU+1x$_AJUzuIt9xOw14?A#G zx&NN=Ms6srDS{V*ljzi2@7C(EVlM&DXxJdE<%Brea2ue&0l>F=Vt8rOFDrqU@7-^W z*{A-$5au5S0BFYB@y4&}VfaD*E`ohfMDV}O1pFkwmcLIL@@#Ehxy=_zpP%Blx%Vjp zFi+w7%I)SS`E{>-(n0cT`HP?94@d8F7Ztt{mFB;KKmNOaMZ4m+!@zJG5bp^;cNPc( M7`)$8J^gw2H@}OY;Q#;t literal 0 HcmV?d00001 diff --git a/sw/qa/extras/layout/data/tdf171959.odt b/sw/qa/extras/layout/data/tdf171959.odt new file mode 100644 index 0000000000000000000000000000000000000000..5122a7eafc98570b884910d530602968fbe675aa GIT binary patch literal 20365 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 #include #include +#include #include +#include #include #include #include @@ -1987,6 +1989,82 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf164098) pWrtShell->Insert(u"ـ"_ustr); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf171959) +{ + // Every line of this document ends in a blank, and the text is justified and underlined. + createSwDoc("tdf171959.odt"); + + // Whether the trailing blank is decorated can only be settled once the line has been adjusted, + // which happens on the way to painting. + std::shared_ptr xMetaFile = getSwDocShell()->GetPreviewMetaFile(); + + // Justification stretches each line to the right margin, leaving no room for the trailing + // blank, which hangs outside the text area. Without the fix the blank kept its underline, so + // the underline was drawn past the margin. + xmlDocUniquePtr pLayout = parseLayoutDump(); + assertXPath(pLayout, "//SwHolePortion", 7); + assertXPath(pLayout, "//SwHolePortion[@show-underline='true']", 0); + + // The blank is still painted (tdf#43244), only without decorations. + MetafileXmlDump dumper; + xmlDocUniquePtr pMetaXml = dumpAndParse(dumper, *xMetaFile); + assertXPath(pMetaXml, "//textarray[@length='1']", 7); + assertXPath(pMetaXml, "//textarray[@length='1'][preceding-sibling::font[1]/@underline!='0']", + 0); +} + +CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf171959Centered) +{ + // Same document, but centred: here the trailing blank has the right half of the free space to + // live in, so its decorations may show as far as that reaches. + createSwDoc("tdf171959-center.odt"); + getSwDocShell()->GetPreviewMetaFile(); + + xmlDocUniquePtr pLayout = parseLayoutDump(); + + // A line with 365 twips to spare decorates the whole 60 twip blank. + assertXPath(pLayout, "//txt[1]/SwParaPortion/SwLineLayout[2]/SwHolePortion", "width", u"60"); + assertXPath(pLayout, "//txt[1]/SwParaPortion/SwLineLayout[2]/SwHolePortion", "show-underline", + u"true"); + + // A line with only 49 twips left decorates that much, and an undecorated hole carries the rest + // of the blank, so the cursor still travels over all of it. + assertXPath(pLayout, "//txt[1]/SwParaPortion/SwLineLayout[5]/SwHolePortion[1]", "width", u"49"); + assertXPath(pLayout, "//txt[1]/SwParaPortion/SwLineLayout[5]/SwHolePortion[1]", + "show-underline", u"true"); + assertXPath(pLayout, "//txt[1]/SwParaPortion/SwLineLayout[5]/SwHolePortion[2]", "width", u"11"); + assertXPath(pLayout, "//txt[1]/SwParaPortion/SwLineLayout[5]/SwHolePortion[2]", + "show-underline", u"false"); +} + +CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf171959ManyBlanks) +{ + // A centred line ending in many blanks: only the right half of the free space is inside the + // text area, so roughly half of the blanks may keep the decoration. + createSwDoc(); + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + pWrtShell->SetAttrItem(SvxAdjustItem(SvxAdjust::Center, RES_PARATR_ADJUST)); + pWrtShell->Insert("foo" + RepeatedUChar(' ', 200)); + getSwDocShell()->GetPreviewMetaFile(); + + xmlDocUniquePtr pLayout = parseLayoutDump(); + + // The blank was already too long for the line, so it had a plain hole after it: what no longer + // fits the text area joins that one instead of making a third. + assertXPath(pLayout, "//SwLineLayout/SwHolePortion", 2); + assertXPath(pLayout, "//SwLineLayout/SwHolePortion[1]", "show-underline", u"true"); + assertXPath(pLayout, "//SwLineLayout/SwHolePortion[2]", "show-underline", u"false"); + + // The blanks are shared out, not squeezed into the decorated part, and none go missing. + const sal_Int32 nLen1 + = getXPath(pLayout, "//SwLineLayout/SwHolePortion[1]", "length").toInt32(); + const sal_Int32 nLen2 + = getXPath(pLayout, "//SwLineLayout/SwHolePortion[2]", "length").toInt32(); + CPPUNIT_ASSERT_GREATER(sal_Int32(1), nLen1); + CPPUNIT_ASSERT_GREATER(sal_Int32(0), nLen2); + CPPUNIT_ASSERT_EQUAL(sal_Int32(200), nLen1 + nLen2); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx index af767839c260..3ada0c5b69bd 100644 --- a/sw/source/core/text/inftxt.cxx +++ b/sw/source/core/text/inftxt.cxx @@ -701,8 +701,11 @@ void SwTextPaintInfo::DrawText_( const OUString &rText, const SwLinePortion &rPo aDrawInf.SetUnderFnt( m_pUnderFnt ); + // tdf#171959: a hole portion carries the trailing blank that hangs outside the line, so it + // takes no part in the justification of the line's content const tools::Long nSpaceAdd = ( rPor.IsBlankPortion() || rPor.IsDropPortion() || - rPor.InNumberGrp() ) ? 0 : GetSpaceAdd(/*bShrink=*/true); + rPor.InNumberGrp() || rPor.IsHolePortion() ) + ? 0 : GetSpaceAdd(/*bShrink=*/true); if ( nSpaceAdd ) { TextFrameIndex nCharCnt(0); diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx index 7b5f6ce4a363..36a6106597c7 100644 --- a/sw/source/core/text/itrcrsr.cxx +++ b/sw/source/core/text/itrcrsr.cxx @@ -17,6 +17,11 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include +#include + +#include + #include #include #include @@ -40,6 +45,7 @@ #include "pordrop.hxx" #include #include "pormulti.hxx" +#include "portxt.hxx" #include #include @@ -437,6 +443,75 @@ static bool isTrailingDecoration(SwLinePortion* p) return true; // no more portions } +// How much of the text area is still free after this portion: an adjusted line parks whatever is +// left of it in the trailing margin portion(s). Lines that need no adjustment - left-aligned ones - +// get no margin portion at all, and keep the room they were formatted against; those answer none. +static std::optional calcTrailingRoom(const SwLinePortion* p) +{ + std::optional oRoom; + for (; p; p = p->GetNextPortion()) + if (p->IsMarginPortion()) + oRoom = oRoom.value_or(0) + p->Width(); + return oRoom; +} + +// tdf#171959: The trailing blank deliberately hangs outside the line (tdf#57187), so once the line +// is adjusted it can sit past the text area - and its decorations would then be drawn out there. +// Keep them inside by decorating only as much as still fits, and letting a plain hole carry the +// rest of the blank, so the cursor can still be moved over all of it. +static void limitTrailingDecoration(SwLinePortion& rPor, const SwLinePortion* pNext) +{ + if (!rPor.IsHolePortion()) + return; + + auto& rHole = static_cast(rPor); + if (!rHole.ShowUnderline()) + return; + + const std::optional oRoom = calcTrailingRoom(pNext); + if (!oRoom || *oRoom >= rHole.Width()) + return; + + if (*oRoom <= 0) + { + rHole.SetShowUnderline(false); + return; + } + + // A hole holds nothing but blanks, so its characters divide up in proportion to its width. + // Keeping one is the least that makes sense: the decorated part exists to be decorated. + const SwTwips nWidth = rHole.Width(); + const sal_Int32 nCount = sal_Int32(rHole.GetLen()); + // The room is short of the width, so the share of the blanks that fits cannot exceed them all + const sal_Int32 nFits + = o3tl::narrowing((nCount * *oRoom + nWidth / 2) / nWidth); + const TextFrameIndex nKeep(std::max(1, nFits)); + const TextFrameIndex nMoved(rHole.GetLen() - nKeep); + const SwTwips nExcess(nWidth - *oRoom); + + rHole.SetLen(nKeep); + rHole.Width(*oRoom); + + // A blank too long for the line already has a plain hole after it, holding what did not fit. + // The part that no longer fits the text area belongs there too; only make a hole of its own + // when there is none. Note the follower has not been given its width yet, so hand it over as + // extra blank width, the way formatting left it. + SwLinePortion* pFollow = rHole.GetNextPortion(); + if (pFollow && pFollow->IsHolePortion() + && !static_cast(pFollow)->ShowUnderline()) + { + pFollow->SetLen(pFollow->GetLen() + nMoved); + pFollow->ExtraBlankWidth(pFollow->ExtraBlankWidth() + nExcess); + return; + } + + SwHolePortion* pRest = new SwHolePortion(rHole); + pRest->SetShowUnderline(false); + pRest->SetLen(nMoved); + pRest->Width(nExcess); + rHole.Insert(pRest); +} + // tdf#120715 tdf#43100: Make width for some HolePortions, so cursor will be able to move into it. // It should not change the layout, so this should be called after the layout is calculated. void SwTextCursor::AddExtraBlankWidth() @@ -451,6 +526,7 @@ void SwTextCursor::AddExtraBlankWidth() { pPos->Width(pPos->Width() + pPos->ExtraBlankWidth()); pPos->ExtraBlankWidth(0); + limitTrailingDecoration(*pPos, pNextPos); } pPos = pNextPos; } diff --git a/sw/source/core/text/portxt.hxx b/sw/source/core/text/portxt.hxx index 579928994ad5..51b932b36234 100644 --- a/sw/source/core/text/portxt.hxx +++ b/sw/source/core/text/portxt.hxx @@ -79,6 +79,7 @@ public: virtual void Paint( const SwTextPaintInfo &rInf ) const override; bool ShowUnderline() const { return m_bShowUnderline; } + void SetShowUnderline(bool bNew) { m_bShowUnderline = bNew; } // Accessibility: pass information about this portion to the PortionHandler virtual void HandlePortion( SwPortionHandler& rPH ) const override;