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 52b423993a5d34927c11674f8bb6e2c9a6ad927f
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Oct 14 13:10:35 2025 +0200
Commit:     Caolán McNamara <[email protected]>
CommitDate: Tue Oct 14 14:06:26 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/+/192367
    Tested-by: Caolán McNamara <[email protected]>
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/sw/qa/writerfilter/dmapper/DomainMapper_Impl.cxx 
b/sw/qa/writerfilter/dmapper/DomainMapper_Impl.cxx
index 040282e79d62..ddefd9e2faa0 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)
     {
     }
 };
@@ -478,6 +484,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 b075246ee417..27b3bcf19b4d 100644
--- a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
+++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
@@ -2670,7 +2670,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.
@@ -7372,7 +7372,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
         {
@@ -7382,7 +7382,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 96501148f981..fee2b89bd2ef 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