sw/qa/writerfilter/dmapper/DomainMapper_Impl.cxx                  |   44 
+++++++++-
 sw/qa/writerfilter/dmapper/data/field-char-height-header-toc.docx |binary
 sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx              |    6 -
 sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx              |    4 
 4 files changed, 46 insertions(+), 8 deletions(-)

New commits:
commit 8acfabf1f8bbb444d4fc3275a897da0aa0830e5e
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Oct 14 13:10:35 2025 +0200
Commit:     Xisco Fauli <[email protected]>
CommitDate: Mon Oct 20 15:50:33 2025 +0200

    tdf#168688 DOCX import: fix missing char props in field in header in ToC
    
    Regression from commit 6ee33d0772f991f04e97b5b61d7b11810a1b8ac0
    (tdf#104079 RTF import: fix handling fields inside TOC fields,
    2017-10-17), open the bugdoc, check the font size of "TEST" in the
    header, it should be 24pt, but it's 12pt.
    
    What happens is that the document ends with the table of contents DOCX
    field, so the section properties at the end of the document (including a
    reference to a header) get parsed while the ToC field is still open, so
    we think that m_xTOCMarkerCursor is in use, but it's for the body text
    and we're in the header, so it's not relevant.
    
    Fix the problem by moving m_xTOCMarkerCursor to m_StreamStateStack,
    where all state that should be stashed away & restored later belongs.
    This way the old tdf#104079 use-case keeps working and the new use-case
    gets fixed.
    
    Interestingly this xTOCMarkerCursor is not actually used as a cursor
    anymore and it just indicates if we're inside a ToC or not, but leave
    that unchanged in this commit.
    
    Change-Id: I1d1c9f55413d94dcde9e7c715bc9f9863f354dcb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192392
    Reviewed-by: Miklos Vajna <[email protected]>
    Tested-by: Jenkins
    (cherry picked from commit 86d0a2f84d714da67d83fdba652540ebe1027382)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192720
    Reviewed-by: Xisco Fauli <[email protected]>

diff --git a/sw/qa/writerfilter/dmapper/DomainMapper_Impl.cxx 
b/sw/qa/writerfilter/dmapper/DomainMapper_Impl.cxx
index f9861b0dbe2a..a98f682ab6c4 100644
--- a/sw/qa/writerfilter/dmapper/DomainMapper_Impl.cxx
+++ b/sw/qa/writerfilter/dmapper/DomainMapper_Impl.cxx
@@ -7,7 +7,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include <test/unoapi_test.hxx>
+#include <swmodeltestbase.hxx>
 
 #include <com/sun/star/text/XTextDocument.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
@@ -23,17 +23,23 @@
 #include <com/sun/star/text/XPageCursor.hpp>
 
 #include <vcl/scheduler.hxx>
+#include <editeng/fhgtitem.hxx>
+
+#include <docsh.hxx>
+#include <ndtxt.hxx>
+#include <swtable.hxx>
+#include <txatbase.hxx>
 
 using namespace ::com::sun::star;
 
 namespace
 {
 /// Tests for sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx.
-class Test : public UnoApiTest
+class Test : public SwModelTestBase
 {
 public:
     Test()
-        : UnoApiTest(u"/sw/qa/writerfilter/dmapper/data/"_ustr)
+        : SwModelTestBase(u"/sw/qa/writerfilter/dmapper/data/"_ustr)
     {
     }
 };
@@ -494,6 +500,38 @@ CPPUNIT_TEST_FIXTURE(Test, testIfField)
     // load.
     loadFromFile(u"if-field.docx");
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFieldCharHeightHeaderToC)
+{
+    // Given a document with a header that has a field with a custom font 
size, while the document
+    // ends with a table of contents:
+    // When importing that document:
+    createSwDoc("field-char-height-header-toc.docx");
+
+    // Then make sure the custom font size is not lost:
+    SwDocShell* pDocShell = getSwDocShell();
+    // Navigate to the start of the only table's B1 cell.
+    SwDoc* pDoc = pDocShell->GetDoc();
+    sw::TableFrameFormats& rTableFormats = *pDoc->GetTableFrameFormats();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rTableFormats.size());
+    SwTableFormat* pTableFormat = rTableFormats[0];
+    SwTable* pTable = SwTable::FindTable(pTableFormat);
+    const SwTableBox* pCell = pTable->GetTableBox(u"B1"_ustr);
+    // Get the font size there.
+    const SwStartNode* pStartNode = pCell->GetSttNd();
+    SwNodeIndex aNodeIndex(*pStartNode);
+    ++aNodeIndex;
+    const SwTextNode* pTextNode = aNodeIndex.GetNode().GetTextNode();
+    SwTextAttr* pAttr = pTextNode->GetTextAttrAt(0, RES_TXTATR_AUTOFMT);
+    // Without the accompanying fix in place, this test would have failed, 
there was no direct
+    // formatting, so we got 12pt from style instead of the wanted 24pt.
+    CPPUNIT_ASSERT(pAttr);
+    const SwFormatAutoFormat& rAutoFormat
+        = static_txtattr_cast<SwTextAttrEnd*>(pAttr)->GetAutoFormat();
+    const SvxFontHeightItem& rFontHeightItem
+        = rAutoFormat.GetStyleHandle()->Get(RES_CHRATR_FONTSIZE);
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(480), 
rFontHeightItem.GetHeight());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/writerfilter/dmapper/data/field-char-height-header-toc.docx 
b/sw/qa/writerfilter/dmapper/data/field-char-height-header-toc.docx
new file mode 100644
index 000000000000..eb855c8ac978
Binary files /dev/null and 
b/sw/qa/writerfilter/dmapper/data/field-char-height-header-toc.docx differ
diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx 
b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
index 5a1e6cbe752b..3bca1637c980 100644
--- a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
+++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
@@ -2707,7 +2707,7 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
                 {
                     uno::Reference<text::XTextCursor> xCursor;
                     if (m_StreamStateStack.top().bParaHadField
-                        && !IsInComments() && !m_xTOCMarkerCursor.is())
+                        && !IsInComments() && 
!m_StreamStateStack.top().xTOCMarkerCursor.is())
                     {
                         // Workaround to make sure char props of the field are 
not lost.
                         // Not relevant for editeng-based comments.
@@ -7518,7 +7518,7 @@ void DomainMapper_Impl::handleToc
             const auto xTextCursor = 
xTextAppend->getText()->createTextCursor();
             if (xTextCursor)
                 xTextCursor->gotoEnd(false);
-            m_xTOCMarkerCursor = xTextCursor;
+            m_StreamStateStack.top().xTOCMarkerCursor = xTextCursor;
         }
         else
         {
@@ -7528,7 +7528,7 @@ void DomainMapper_Impl::handleToc
 
             // init [xTOCMarkerCursor]
             uno::Reference< text::XText > xText = xTextAppend->getText();
-            m_xTOCMarkerCursor = xText->createTextCursor();
+            m_StreamStateStack.top().xTOCMarkerCursor = 
xText->createTextCursor();
 
             // create header of the TOC with the TOC title inside
             createSectionForRange(m_StreamStateStack.top().xSdtEntryStart, 
xTextRangeEndOfTocHeader, u"com.sun.star.text.IndexHeaderSection", true);
diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx 
b/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx
index e1a9931ef0fd..237b4a4d1db1 100644
--- a/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx
+++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx
@@ -274,6 +274,8 @@ struct SubstreamContext
     // inline paragraph: hidden paragraph mark by w:specVanish
     bool bIsInlineParagraph = false;
     bool bIsPreviousInlineParagraph = false;
+
+    css::uno::Reference< css::text::XTextCursor > xTOCMarkerCursor;
 };
 
 /// Information about a paragraph to be finished after a field end.
@@ -675,8 +677,6 @@ private:
     bool                            m_bIsLastSectionGroup;
     bool                            m_bUsingEnhancedFields;
 
-    css::uno::Reference< css::text::XTextCursor > m_xTOCMarkerCursor;
-
     ::std::set<::std::pair<PagePartType, PageType>> m_HeaderFooterSeen;
 
     // LN_CT_PPrBase_spacing has specified both a line and a lineRule?

Reply via email to