sw/qa/extras/layout/data/tdf168351.fodt |   45 ++++++++++++++++++++++++++++++++
 sw/qa/extras/layout/layout3.cxx         |   38 +++++++++++++++++++++++++++
 sw/source/core/text/guess.cxx           |    3 ++
 3 files changed, 86 insertions(+)

New commits:
commit 33f20d0a0fb32bf4452c15c6ae0e7c85b2ee6d46
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Wed Sep 10 16:31:10 2025 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Fri Sep 12 15:27:51 2025 +0200

    tdf#168351 sw letter spacing: fix spaces in the last line
    
    Minimum letter spacing and glyph scaling were applied in
    the last paragraph line incompletely, because of missing
    update of the break width, when the last two paragraph
    lines were compressed into a single one. This resulted in
    calculating more blank space, than available, and positive
    kerning, also glyph expansion with missing word spacing and
    overlapping words, instead of negative kerning and glyph
    compression for the desired word spacing.
    
    Follow-up to commit 45ec7bd76196dcc60b4c2db2f6f00623ecbaf5a4
    "tdf#168251 cui offapi xmloff sw glyph scaling: extend UNO/UX/ODF",
    commit 3c53797210bf0a4e3ffb36ed2beac4d5ce229ff2
    "tdf#167648 sw letter spacing: implement minimum letter spacing"
    and commit f83a04c51056445bbf947a31c8c1866a5c30bef1
    "tdf#167648 cui offapi xmloff sw: add DTP-feature maximum letter
    spacing".
    
    Change-Id: I0d72a6fa2f9d945bd463fbe162ef5d0eb377f49a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190862
    Reviewed-by: László Németh <nem...@numbertext.org>
    Tested-by: Jenkins

diff --git a/sw/qa/extras/layout/data/tdf168351.fodt 
b/sw/qa/extras/layout/data/tdf168351.fodt
new file mode 100644
index 000000000000..62c0813d67d4
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf168351.fodt
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; xmlns:c
 alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:officeooo="http://openoffice.org/2009/office"; 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:
 meta:1.0" 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:font-face-decls>
+  <style:font-face style:name="Liberation Serif" 
svg:font-family="&apos;Liberation Serif&apos;" 
style:font-family-generic="modern" style:font-pitch="fixed"/>
+ </office:font-face-decls>
+ <office:styles>
+  <style:default-style style:family="paragraph">
+   <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" 
fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" 
loext:hyphenation-keep-line="false" style:text-autospace="ideograph-alpha" 
style:punctuation-wrap="hanging" style:line-break="strict" 
style:tab-stop-distance="35.46pt" style:writing-mode="page"/>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="en" fo:country="US" style:letter-kerning="true" 
fo:hyphenate="false" fo:hyphenation-remain-char-count="2" 
fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" 
loext:hyphenation-no-last-word="false" 
loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/>
+  </style:default-style>
+  <style:style style:name="Standard" style:family="paragraph" 
style:class="text"/>
+  <style:style style:name="Text_20_body" style:display-name="Text body" 
style:family="paragraph" style:parent-style-name="Standard" style:class="text" 
style:master-page-name="">
+   <style:paragraph-properties fo:margin-left="0pt" fo:margin-right="0pt" 
fo:margin-top="0pt" fo:margin-bottom="0pt" style:contextual-spacing="false" 
fo:line-height="100%" fo:text-align="start" style:justify-single-word="false" 
fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" 
fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" 
loext:hyphenation-keep-line="false" fo:text-indent="11.99pt" 
style:auto-text-indent="false" style:page-number="auto"/>
+   <style:text-properties fo:hyphenate="true" 
fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" 
loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" 
loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/>
+  </style:style>
+ </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="P1" style:family="paragraph" 
style:parent-style-name="Text_20_body" style:master-page-name="">
+   <style:paragraph-properties fo:text-align="justify" 
style:justify-single-word="false" fo:hyphenation-ladder-count="no-limit" 
fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" 
loext:hyphenation-keep-line="true" fo:text-indent="0pt" 
style:auto-text-indent="false" style:page-number="auto" 
style:writing-mode="lr-tb" loext:letter-spacing-minimum="-25%" 
loext:letter-spacing-maximum="5%"/>
+   <style:text-properties officeooo:paragraph-rsid="00110e77" 
fo:hyphenate="false" fo:hyphenation-remain-char-count="2" 
fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" 
loext:hyphenation-no-last-word="false" 
loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/>
+  </style:style>
+  <style:style style:name="T1" style:family="text">
+   <style:text-properties fo:letter-spacing="0.51pt"/>
+  </style:style>
+  <style:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="595.3pt" 
fo:page-height="841.89pt" style:num-format="1" 
style:print-orientation="portrait" fo:margin-top="72pt" fo:margin-bottom="72pt" 
fo:margin-left="28.35pt" fo:margin-right="398.89pt" style:writing-mode="lr-tb" 
style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" 
style:layout-grid-base-height="20.01pt" style:layout-grid-ruby-height="10.01pt" 
style:layout-grid-mode="none" style:layout-grid-ruby-below="false" 
style:layout-grid-print="false" style:layout-grid-display="false" 
style:footnote-max-height="0pt" loext:margin-gutter="0pt">
+    <style:footnote-sep style:width="0.51pt" 
style:distance-before-sep="2.86pt" style:distance-after-sep="2.86pt" 
style:line-style="solid" style:adjustment="left" style:rel-width="25%" 
style:color="#000000"/>
+   </style:page-layout-properties>
+   <style:header-style/>
+   <style:footer-style/>
+  </style:page-layout>
+  <style:style style:name="dp1" style:family="drawing-page">
+   <style:drawing-page-properties draw:background-size="full"/>
+  </style:style>
+ </office:automatic-styles>
+ <office:master-styles>
+  <style:master-page style:name="Standard" style:page-layout-name="pm1" 
draw:style-name="dp1"/>
+ </office:master-styles>
+ <office:body>
+  <office:text>
+   <text:p text:style-name="P1"><text:span text:style-name="T1">vehicula 
vestibulum est vel ultricies.</text:span></text:p>
+  </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/layout/layout3.cxx b/sw/qa/extras/layout/layout3.cxx
index 1cd8d590f546..7c60f5e02c35 100644
--- a/sw/qa/extras/layout/layout3.cxx
+++ b/sw/qa/extras/layout/layout3.cxx
@@ -697,6 +697,44 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf168251)
     }
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf168351)
+{
+    createSwDoc("tdf168351.fodt");
+    // Ensure that all text portions are calculated before testing.
+    SwDocShell* pShell = getSwDocShell();
+
+    // Dump the rendering of the first page as an XML file.
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+    MetafileXmlDump dumper;
+
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    CPPUNIT_ASSERT(pXmlDoc);
+
+    // Find the first text array action
+    for (size_t nAction = 0; nAction < xMetaFile->GetActionSize(); nAction++)
+    {
+        auto pAction = xMetaFile->GetAction(nAction);
+        if (pAction->GetType() == MetaActionType::TEXTARRAY)
+        {
+            auto pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction);
+            auto pDXArray = pTextArrayAction->GetDXArray();
+
+            // There should be 38 characters on the first line
+            CPPUNIT_ASSERT_EQUAL(size_t(38), pDXArray.size());
+
+            // This was 830, now 789, according to the applied negative letter 
spacing
+            CPPUNIT_ASSERT_LESS(sal_Int32(800), sal_Int32(pDXArray[7]));
+
+            // restore desired word spacing between the first two words
+            // This was -6.5 (missing word spacing), now 57,
+            // according to the applied letter spacing
+            CPPUNIT_ASSERT_GREATER(sal_Int32(50), sal_Int32(pDXArray[9]) - 
sal_Int32(pDXArray[8]));
+
+            break;
+        }
+    }
+}
+
 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf164499)
 {
     createSwDoc("tdf164499.docx");
diff --git a/sw/source/core/text/guess.cxx b/sw/source/core/text/guess.cxx
index f75ffa5510cf..18732a7704ad 100644
--- a/sw/source/core/text/guess.cxx
+++ b/sw/source/core/text/guess.cxx
@@ -561,6 +561,9 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, 
SwTextFormatInfo &rInf,
 
             m_nBreakWidth += nLeftRightBorderSpace;
 
+            // tdf#168351 store enlarged break width for minimum letter 
spacing/glyph scaling
+            rInf.SetBreakWidth(m_nBreakWidth);
+
             return bRet;
         }
     }

Reply via email to