sw/qa/extras/rtfexport/data/tdf167661.rtf  |   12 ++
 sw/qa/extras/rtfexport/data/tdf167679.fodt |   25 +++++
 sw/qa/extras/rtfexport/rtfexport8.cxx      |  128 +++++++++++++++++++++++++++++
 sw/source/filter/ww8/wrtw8num.cxx          |  105 +++++++++++------------
 sw/source/filter/ww8/wrtw8sty.cxx          |   43 ++++++---
 sw/source/filter/ww8/wrtww8.cxx            |    2 
 sw/source/filter/ww8/wrtww8.hxx            |    6 +
 sw/source/filter/ww8/ww8atr.cxx            |   16 +--
 8 files changed, 257 insertions(+), 80 deletions(-)

New commits:
commit 1749f616197fc10100ceacd974b4e45ce8a02bcd
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sat Jul 26 21:33:06 2025 +0500
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Aug 11 12:12:35 2025 +0200

    tdf#167679: RTF already can export rdrnone
    
    In commit f84b33275f6cce21e93e5dd20f3de5df84df0276 (tdf#129522
    ww8import/export: allow char shadow_NONE overrides, 2020-01-04),
    export of char shadow was implemented, which made CharBorder to
    be called for missing borderline. But it made an exception for
    RTF, because at that time, its code couldn't handle that.
    
    In commit eca3ce35fe9a346965a32f42d02cb6d3f5a3982f (tdf#129631
    writerfilter,sw: RTF import of invalid border..., 2022-08-11),
    RTF export got ability to handle that.
    
    Removal of the exception for RTF fixed missing export of "no
    border" and "no shadow" character formatting.
    
    Change-Id: I5f23b09558d32b403e0c26c727ee01f79374e54d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188418
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189304

diff --git a/sw/qa/extras/rtfexport/data/tdf167679.fodt 
b/sw/qa/extras/rtfexport/data/tdf167679.fodt
new file mode 100644
index 000000000000..fad1dacf5b45
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf167679.fodt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible: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:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible: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="roman" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+  <style:default-style style:family="paragraph">
+   <style:text-properties style:font-name="Liberation Serif" 
fo:font-size="12pt"/>
+  </style:default-style>
+  <style:style style:name="border" style:family="text">
+   <style:text-properties loext:padding="0.5mm" loext:border="0.11pt solid 
#FF0000" loext:shadow="#808080 5pt 5pt"/>
+  </style:style>
+ </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="T1" style:family="text">
+   <style:text-properties loext:padding="0.5mm" loext:border="none" 
loext:shadow="none"/>
+  </style:style>
+ </office:automatic-styles>
+ <office:body>
+  <office:text>
+   <text:p>s<text:span text:style-name="border">om<text:span 
text:style-name="T1">eth</text:span>in</text:span>g</text:p>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index d03dd3fbfe3a..c9b641affc16 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -23,6 +23,7 @@
 #include <com/sun/star/text/XTextDocument.hpp>
 #include <com/sun/star/style/ParagraphAdjust.hpp>
 #include <com/sun/star/style/TabStop.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
 
 #include <basegfx/utils/gradienttools.hxx>
 #include <comphelper/sequenceashashmap.hxx>
@@ -1046,6 +1047,100 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167661)
     }
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf167679)
+{
+    // Given a document with a char style with a border with a shadow, and a 
direct formatting
+    // applied over it, which turns off the border and the shadow:
+    createSwDoc("tdf167679.fodt");
+
+    {
+        auto xRun = getRun(getParagraph(1), 1, u"s"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x000000, 0, 0, 0, 
32767, 0), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_NONE, aShadow.Location);
+    }
+    {
+        auto xRun = getRun(getParagraph(1), 2, u"om"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF0000, 0, 4, 0, 0, 
4), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_BOTTOM_RIGHT, 
aShadow.Location);
+    }
+    {
+        auto xRun = getRun(getParagraph(1), 3, u"eth"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x000000, 0, 0, 0, 
32767, 0), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_NONE, aShadow.Location);
+    }
+    {
+        auto xRun = getRun(getParagraph(1), 4, u"in"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF0000, 0, 4, 0, 0, 
4), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_BOTTOM_RIGHT, 
aShadow.Location);
+    }
+    {
+        auto xRun = getRun(getParagraph(1), 5, u"g"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x000000, 0, 0, 0, 
32767, 0), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_NONE, aShadow.Location);
+    }
+
+    // Check that after export to RTF, the area in the middle still has no 
border
+    saveAndReload(mpFilter);
+
+    {
+        auto xRun = getRun(getParagraph(1), 1, u"s"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x000000, 0, 0, 0, 
32767, 0), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_NONE, aShadow.Location);
+    }
+    {
+        // Without a fix, this failed, because the second run was "omethin": 
the middle
+        // direct formatting that cancelled the border didn't round-trip.
+        auto xRun = getRun(getParagraph(1), 2, u"om"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF0000, 0, 4, 0, 0, 
4), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_BOTTOM_RIGHT, 
aShadow.Location);
+    }
+    {
+        auto xRun = getRun(getParagraph(1), 3, u"eth"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x000000, 0, 0, 0, 
32767, 0), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_NONE, aShadow.Location);
+    }
+    {
+        auto xRun = getRun(getParagraph(1), 4, u"in"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF0000, 0, 4, 0, 0, 
4), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_BOTTOM_RIGHT, 
aShadow.Location);
+    }
+    {
+        auto xRun = getRun(getParagraph(1), 5, u"g"_ustr);
+        auto aBorder = getProperty<table::BorderLine2>(xRun, 
u"CharTopBorder"_ustr);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x000000, 0, 0, 0, 
32767, 0), aBorder);
+
+        auto aShadow = getProperty<table::ShadowFormat>(xRun, 
u"CharShadowFormat"_ustr);
+        CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_NONE, aShadow.Location);
+    }
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 878fe048b66f..8019d895db11 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -6076,17 +6076,13 @@ void AttributeOutputBase::FormatCharBorder( const 
SvxBoxItem& rBox )
        nDist = rBox.GetDistance( SvxBoxItemLine::RIGHT );
     }
 
-    // RTF: avoid regressions since RTF doesn't know how to export a 
border_NONE style-override
-    if( pBorderLine || GetExport().GetExportFormat() != 
MSWordExportBase::ExportFormat::RTF )
-    {
-        const SfxPoolItem* pItem = GetExport().HasItem( RES_CHRATR_SHADOW );
-        const SvxShadowItem* pShadowItem = static_cast<const 
SvxShadowItem*>(pItem);
-        const bool bShadow = pBorderLine &&
-            pShadowItem && pShadowItem->GetLocation() != 
SvxShadowLocation::NONE &&
-            pShadowItem->GetWidth() > 0;
+    const SfxPoolItem* pItem = GetExport().HasItem( RES_CHRATR_SHADOW );
+    const SvxShadowItem* pShadowItem = static_cast<const 
SvxShadowItem*>(pItem);
+    const bool bShadow = pBorderLine &&
+        pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE &&
+        pShadowItem->GetWidth() > 0;
 
-        CharBorder( pBorderLine, nDist, bShadow );
-    }
+    CharBorder( pBorderLine, nDist, bShadow );
 }
 
 /*
commit 66a612ee153e64afd5fe7024555be960e56c0a89
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Jul 24 15:35:13 2025 +0500
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Aug 11 12:12:21 2025 +0200

    tdf#167661: collect bullet fonts before exporting font table
    
    The problem was, that InitFontTable, used to collect all fonts used
    in the document, didn't handle bullets. When font table was written,
    some fonts needed for bullets could be still missing from it; only
    when writing list levels, these fonts were added to maFonts.
    
    It might seem that that is a bug in SwDoc::ForEachCharacterFontItem,
    called from InitFontTable. It might be; and maybe even needs to be
    addressed at some point (though I don't know which side effects it
    could have). But in the case of export to RTF, this wouldn't fix it
    completely, because there is some special processing of bullets in
    MSWordExportBase::SubstituteBullet, which might change the exported
    font name; therefore, it could happen to still be not covered by an
    iteration over actual document's fonts.
    
    1. Extract the code filling used numbering rules in GetNumberingId,
    into a separate function (EnsureUsedNumberingTable).
    
    2. Extract the code getting bullet string + font in NumberingLevel,
    into a separate function (GetNumberingLevelBulletStringAndFont).
    
    3. In wwFontHelper::InitFontTable, use these functions to iterate
    the used numbering rules, and handle fonts of these. To do that,
    let the function take an Export object.
    
    Change-Id: Ib7ecdeb9908cd3bd53346ccb035d623fa603db0d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188277
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189303

diff --git a/sw/qa/extras/rtfexport/data/tdf167661.rtf 
b/sw/qa/extras/rtfexport/data/tdf167661.rtf
new file mode 100644
index 000000000000..368c0c56a338
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf167661.rtf
@@ -0,0 +1,12 @@
+{ tf1
+{onttbl
+{0bidi romancharset0prq2 Liberation Sans;}
+{1bidi nilcharset2prq2 Wingdings;}}
+{\*\listtable
+{\list\listtemplateid-1
+{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u183
 ?;}{\levelnumbers;}1 i-360\li720\lin720 }
+{\listname ;}\listid1}}
+{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}}
+\pard i-360\li720 i0\ls1 in0\lin720\itap00 bullet list item
+\par
+}
\ No newline at end of file
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index 9c36b8596691..d03dd3fbfe3a 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -1013,6 +1013,39 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167660)
     CPPUNIT_ASSERT(buffer_view.find("\u-1278") != std::string_view::npos);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf167661)
+{
+    // Given a document with a bulleted list using Wingdings
+    createSwDoc("tdf167661.rtf");
+
+    {
+        // Check font of the bullet
+        auto xNumberingRules = 
getProperty<uno::Reference<container::XIndexAccess>>(
+            getParagraph(1), u"NumberingRules"_ustr);
+
+        comphelper::SequenceAsHashMap level1(
+            
xNumberingRules->getByIndex(0).get<uno::Sequence<beans::PropertyValue>>());
+
+        CPPUNIT_ASSERT_EQUAL(u"Wingdings"_ustr, 
level1[u"BulletFontName"_ustr].get<OUString>());
+    }
+
+    saveAndReload(mpFilter);
+
+    {
+        // Check that the font of the bullet is not lost
+        auto xNumberingRules = 
getProperty<uno::Reference<container::XIndexAccess>>(
+            getParagraph(1), u"NumberingRules"_ustr);
+
+        comphelper::SequenceAsHashMap level1(
+            
xNumberingRules->getByIndex(0).get<uno::Sequence<beans::PropertyValue>>());
+
+        // Without a fix, this failed with
+        // - Expected: Wingdings
+        // - Actual  : 0
+        CPPUNIT_ASSERT_EQUAL(u"Wingdings"_ustr, 
level1[u"BulletFontName"_ustr].get<OUString>());
+    }
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/filter/ww8/wrtw8num.cxx 
b/sw/source/filter/ww8/wrtw8num.cxx
index 6cac001caef5..58a027b5bf4a 100644
--- a/sw/source/filter/ww8/wrtw8num.cxx
+++ b/sw/source/filter/ww8/wrtw8num.cxx
@@ -117,7 +117,7 @@ void MSWordExportBase::AddListLevelOverride(sal_uInt16 
nListId,
     m_ListLevelOverrides[nListId][nLevelNum] = nStartAt;
 }
 
-sal_uInt16 MSWordExportBase::GetNumberingId( const SwNumRule& rNumRule )
+void MSWordExportBase::EnsureUsedNumberingTable()
 {
     if ( !m_pUsedNumTable )
     {
@@ -146,6 +146,11 @@ sal_uInt16 MSWordExportBase::GetNumberingId( const 
SwNumRule& rNumRule )
             m_pUsedNumTable->push_back( pR );
         }
     }
+}
+
+sal_uInt16 MSWordExportBase::GetNumberingId( const SwNumRule& rNumRule )
+{
+    EnsureUsedNumberingTable();
     SwNumRule* p = const_cast<SwNumRule*>(&rNumRule);
     sal_uInt16 nRet = o3tl::narrowing<sal_uInt16>(m_pUsedNumTable->GetPos(p));
 
@@ -413,6 +418,35 @@ void MSWordExportBase::AbstractNumberingDefinitions()
     }
 }
 
+std::pair<OUString, std::unique_ptr<wwFont>>
+MSWordExportBase::GetNumberingLevelBulletStringAndFont(const SwNumFormat& 
rLevelFormat)
+{
+    assert(rLevelFormat.GetNumberingType() == SVX_NUM_CHAR_SPECIAL
+           || rLevelFormat.GetNumberingType() == SVX_NUM_BITMAP);
+
+    sal_UCS4 cBullet = rLevelFormat.GetBulletChar();
+    OUString sNumStr(&cBullet, 1);
+
+    std::optional<vcl::Font> pBulletFont = rLevelFormat.GetBulletFont();
+    if (!pBulletFont)
+    {
+        pBulletFont = numfunc::GetDefBulletFont();
+    }
+
+    rtl_TextEncoding eChrSet = pBulletFont->GetCharSet();
+    OUString sFontName = pBulletFont->GetFamilyName();
+    FontFamily eFamily = pBulletFont->GetFamilyTypeMaybeAskConfig();
+
+    if (IsOpenSymbol(sFontName))
+        SubstituteBullet(sNumStr, eChrSet, sFontName);
+
+    if (sFontName.isEmpty())
+        sFontName = pBulletFont->GetFamilyName();
+
+    return { sNumStr, std::make_unique<wwFont>(sFontName, 
pBulletFont->GetPitchMaybeAskConfig(),
+                                               eFamily, eChrSet) };
+}
+
 void MSWordExportBase::NumberingLevel(
         SwNumRule const& rRule, sal_uInt8 const nLvl)
 {
@@ -462,17 +496,25 @@ void MSWordExportBase::NumberingLevel(
 
     // Build the NumString for this Level
     OUString sNumStr;
-    OUString sFontName;
-    bool bWriteBullet = false;
-    std::optional<vcl::Font> pBulletFont;
-    rtl_TextEncoding eChrSet=0;
-    FontFamily eFamily=FAMILY_DECORATIVE;
+
+    // Attributes of the numbering
+    std::unique_ptr<wwFont> pPseudoFont;
+    const SfxItemSet* pOutSet = nullptr;
+
+    // cbGrpprlChpx
+    SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> aSet( 
m_rDoc.GetAttrPool() );
+
     if (SVX_NUM_CHAR_SPECIAL == rFormat.GetNumberingType() ||
         SVX_NUM_BITMAP == rFormat.GetNumberingType())
     {
         // Use bullet
-        sal_UCS4 cBullet = rFormat.GetBulletChar();
-        sNumStr = OUString(&cBullet, 1);
+        std::tie(sNumStr, pPseudoFont) = 
GetNumberingLevelBulletStringAndFont(rFormat);
+
+        pOutSet = &aSet;
+        if (rFormat.GetCharFormat())
+            aSet.Put( rFormat.GetCharFormat()->GetAttrSet() );
+        aSet.ClearItem( RES_CHRATR_CJK_FONT );
+        aSet.ClearItem( RES_CHRATR_FONT );
     }
     else
     {
@@ -551,51 +593,8 @@ void MSWordExportBase::NumberingLevel(
             assert(false && "deprecated format still exists and is unhandled. 
Inform Vasily or Justin");
     }
 
-    if (SVX_NUM_CHAR_SPECIAL == rFormat.GetNumberingType() ||
-        SVX_NUM_BITMAP == rFormat.GetNumberingType())
-    {
-        bWriteBullet = true;
-
-        pBulletFont = rFormat.GetBulletFont();
-        if (!pBulletFont)
-        {
-            pBulletFont = numfunc::GetDefBulletFont();
-        }
-
-        eChrSet = pBulletFont->GetCharSet();
-        sFontName = pBulletFont->GetFamilyName();
-        eFamily = pBulletFont->GetFamilyTypeMaybeAskConfig();
-
-        if (IsOpenSymbol(sFontName))
-            SubstituteBullet(sNumStr, eChrSet, sFontName);
-    }
-
-    // Attributes of the numbering
-    std::unique_ptr<wwFont> pPseudoFont;
-    const SfxItemSet* pOutSet = nullptr;
-
-    // cbGrpprlChpx
-    SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> aSet( 
m_rDoc.GetAttrPool() );
-    if (rFormat.GetCharFormat() || bWriteBullet)
-    {
-        if (bWriteBullet)
-        {
-            pOutSet = &aSet;
-
-            if (rFormat.GetCharFormat())
-                aSet.Put( rFormat.GetCharFormat()->GetAttrSet() );
-            aSet.ClearItem( RES_CHRATR_CJK_FONT );
-            aSet.ClearItem( RES_CHRATR_FONT );
-
-            if (sFontName.isEmpty())
-                sFontName = pBulletFont->GetFamilyName();
-
-            pPseudoFont.reset(new wwFont( sFontName, 
pBulletFont->GetPitchMaybeAskConfig(),
-                eFamily, eChrSet));
-        }
-        else
-            pOutSet = &rFormat.GetCharFormat()->GetAttrSet();
-    }
+    if (!pOutSet && rFormat.GetCharFormat())
+        pOutSet = &rFormat.GetCharFormat()->GetAttrSet();
 
     sal_Int16 nIndentAt = 0;
     sal_Int16 nFirstLineIndex = 0;
diff --git a/sw/source/filter/ww8/wrtw8sty.cxx 
b/sw/source/filter/ww8/wrtw8sty.cxx
index 79b8371714d0..6ba31b1ad55b 100644
--- a/sw/source/filter/ww8/wrtw8sty.cxx
+++ b/sw/source/filter/ww8/wrtw8sty.cxx
@@ -919,7 +919,7 @@ sal_uInt16 wwFontHelper::GetId(const wwFont &rFont)
     return nRet;
 }
 
-void wwFontHelper::InitFontTable(const SwDoc& rDoc)
+void wwFontHelper::InitFontTable(MSWordExportBase& rExport)
 {
     GetId(wwFont(u"Times New Roman", PITCH_VARIABLE,
         FAMILY_ROMAN, RTL_TEXTENCODING_MS_1252));
@@ -930,18 +930,10 @@ void wwFontHelper::InitFontTable(const SwDoc& rDoc)
     GetId(wwFont(u"Arial", PITCH_VARIABLE, FAMILY_SWISS,
         RTL_TEXTENCODING_MS_1252));
 
-    const SvxFontItem* pFont = GetDfltAttr(RES_CHRATR_FONT);
+    GetId(*GetDfltAttr(RES_CHRATR_FONT));
 
-    GetId(wwFont(pFont->GetFamilyName(), pFont->GetPitch(),
-        pFont->GetFamily(), pFont->GetCharSet()));
-
-    const SfxItemPool& rPool = rDoc.GetAttrPool();
-    pFont = rPool.GetUserDefaultItem(RES_CHRATR_FONT);
-    if (nullptr != pFont)
-    {
-        GetId(wwFont(pFont->GetFamilyName(), pFont->GetPitch(),
-            pFont->GetFamily(), pFont->GetCharSet()));
-    }
+    if (const SvxFontItem* pFont = 
rExport.m_rDoc.GetAttrPool().GetUserDefaultItem(RES_CHRATR_FONT))
+        GetId(*pFont);
 
     if (!m_bLoadAllFonts)
         return;
@@ -949,14 +941,35 @@ void wwFontHelper::InitFontTable(const SwDoc& rDoc)
     const TypedWhichId<SvxFontItem> aTypes[] { RES_CHRATR_FONT, 
RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT };
     for (const TypedWhichId<SvxFontItem> & pId : aTypes)
     {
-        const_cast<SwDoc&>(rDoc).ForEachCharacterFontItem(pId, 
/*bIgnoreAutoStyles*/false,
+        rExport.m_rDoc.ForEachCharacterFontItem(pId, 
/*bIgnoreAutoStyles*/false,
             [this] (const SvxFontItem& rFontItem) -> bool
             {
-                GetId(wwFont(rFontItem.GetFamilyName(), rFontItem.GetPitch(),
-                             rFontItem.GetFamily(), rFontItem.GetCharSet()));
+                GetId(rFontItem);
                 return true;
             });
     }
+
+    // Bullets in lists may need own fonts; and may even want to substitute 
fonts (see
+    // MSWordExportBase::SubstituteBullet). We need to collect these here, too.
+    rExport.EnsureUsedNumberingTable();
+    for (const SwNumRule* pRule : *rExport.m_pUsedNumTable)
+    {
+        assert(pRule);
+        int n = pRule->IsContinusNum() ? WW8ListManager::nMinLevel : 
WW8ListManager::nMaxLevel;
+        for (int nLvl = 0; nLvl < n; ++nLvl)
+        {
+            const SwNumFormat& rFormat = pRule->Get(nLvl);
+
+            if (rFormat.GetNumberingType() == SVX_NUM_CHAR_SPECIAL
+                || rFormat.GetNumberingType() == SVX_NUM_BITMAP)
+            {
+                const auto [s, pFont] = 
rExport.GetNumberingLevelBulletStringAndFont(rFormat);
+                (void)s;
+                assert(pFont);
+                GetId(*pFont);
+            }
+        }
+    }
 }
 
 sal_uInt16 wwFontHelper::GetId(const SvxFontItem& rFont)
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index d06267a7f2a3..7c4bb66fa760 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -3463,7 +3463,7 @@ ErrCode MSWordExportBase::ExportDocument( bool bWriteAll )
     // fix the SwPositions in m_aFrames after SetRedlineFlags
     UpdateFramePositions(m_aFrames);
 
-    m_aFontHelper.InitFontTable(m_rDoc);
+    m_aFontHelper.InitFontTable(*this);
     GatherChapterFields();
 
     CollectOutlineBookmarks(m_rDoc);
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index c52665f8d16b..dc7f37e3d959 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -319,7 +319,7 @@ private:
 public:
     wwFontHelper() : m_bLoadAllFonts(false) {}
     /// rDoc used only to get the initial standard font(s) in use.
-    void InitFontTable(const SwDoc& rDoc);
+    void InitFontTable(MSWordExportBase& rExport);
     sal_uInt16 GetId(const SvxFontItem& rFont);
     sal_uInt16 GetId(const wwFont& rFont);
     void WriteFontTable( SvStream *pTableStream, WW8Fib& pFib );
@@ -603,6 +603,7 @@ public:
 
     /// Return the numeric id of the numbering rule
     sal_uInt16 GetNumberingId( const SwNumRule& rNumRule );
+    void EnsureUsedNumberingTable();
 
     /// Return the numeric id of the style.
     sal_uInt16 GetId( const SwTextFormatColl& rColl ) const;
@@ -770,6 +771,9 @@ public:
     /// Write one numbering level
     void NumberingLevel(SwNumRule const& rRule, sal_uInt8 nLvl);
 
+    std::pair<OUString, std::unique_ptr<wwFont>>
+    GetNumberingLevelBulletStringAndFont(const SwNumFormat& rLevelFormat);
+
     // Convert the bullet according to the font.
     void SubstituteBullet( OUString& rNumStr, rtl_TextEncoding& rChrSet,
         OUString& rFontName ) const;

Reply via email to