sw/qa/extras/ooxmlexport/data/para-style-char-position.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport18.cxx                  |   18 ++++++++++
 sw/source/filter/ww8/docxattributeoutput.cxx                |    8 ++++
 writerfilter/source/dmapper/DomainMapper.cxx                |   21 ++++++++++--
 writerfilter/source/dmapper/DomainMapper.hxx                |    6 ++-
 writerfilter/source/dmapper/DomainMapper_Impl.cxx           |    4 +-
 writerfilter/source/dmapper/DomainMapper_Impl.hxx           |    2 -
 writerfilter/source/dmapper/StyleSheetTable.cxx             |    1 
 8 files changed, 53 insertions(+), 7 deletions(-)

New commits:
commit ddf8903e9b7528671e752d24717056f2db039464
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jun 13 15:02:20 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Jun 14 08:43:45 2023 +0200

    DOCX filter: improve handling of negative <w:position> in paragraph styles
    
    The bugdoc has a <w:position w:val="-1"> in its Normal paragraph style,
    which is almost not visible in Word, but we mapped this to default
    subscript text in Writer, leading to very visible bad font height in
    practice.
    
    The root of the problem is that <w:position> works with an absolute
    offset in half-points, while Writer works in percentages, so the
    import/export code can only do a correct mapping in case the font size
    is known. This initial mapping was added in commit
    e70df84352d3670508a4666c97df44f82c1ce934 (try somewhat harder to read
    w:position (bnc#773061), 2012-08-07), and later commit
    d71cf6390a89ea6a4fab724e3a7996f28ca33661 (tdf#99602 writerfilter: import
    subscript into character style, 2019-10-04) gave up on this for
    character styles.
    
    Fix the problem by working with paragraph styles similar to what the
    binary DOC filter already does, just assuming that the font height from
    the style won't be overwritten, or will be overwritten together with a
    matching <w:position>. Do this only for negative <w:position> for now,
    as that's good enough for our needs. Do the opposite of this at export
    time.
    
    It would be still possible in the future to add native handling for
    absolute escapements, and then this mapping would not be needed at all.
    
    Change-Id: I771c7bed27fa2596153aa77c472c91b819fa4cb1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152962
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 85f0a5d7bc54dfba75e8d6dd9c905bc1ac31d927)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153011

diff --git a/sw/qa/extras/ooxmlexport/data/para-style-char-position.docx 
b/sw/qa/extras/ooxmlexport/data/para-style-char-position.docx
new file mode 100644
index 000000000000..946ca0bf9cc2
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/para-style-char-position.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
index 50a058d19c9d..fbb87915369e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
@@ -615,6 +615,24 @@ CPPUNIT_TEST_FIXTURE(Test, testNumberPortionFormatFromODT)
     assertXPath(pXmlDoc, "//w:pPr/w:rPr/w:sz", "val", "48");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testParaStyleCharPosition)
+{
+    // Given a loaded document where the Normal paragraph style has 
<w:position w:val="-1">:
+    createSwDoc("para-style-char-position.docx");
+
+    // When saving it back to DOCX:
+    save("Office Open XML Text");
+
+    // Then make sure that is not turned into a normal subscript text:
+    xmlDocUniquePtr pXmlDoc = parseExport("word/styles.xml");
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 0
+    // - XPath '/w:styles/w:style[@w:styleId='Normal']/w:rPr/w:position' 
number of nodes is incorrect
+    // i.e. we wrote <w:vertAlign w:val="subscript"> instead of <w:position>.
+    assertXPath(pXmlDoc, 
"/w:styles/w:style[@w:styleId='Normal']/w:rPr/w:position", "val", "-1");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf150966_regularInset)
 {
     // Given a docx document with a rectangular shape with height cy="900000" 
(EMU), tIns="180000"
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index a75682761d84..ba5d14bd8c90 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -7791,8 +7791,14 @@ void DocxAttributeOutput::CharEscapement( const 
SvxEscapementItem& rEscapement )
     OString sIss;
     short nEsc = rEscapement.GetEsc(), nProp = 
rEscapement.GetProportionalHeight();
 
+    bool bParaStyle = false;
+    if (m_rExport.m_bStyDef && m_rExport.m_pCurrentStyle)
+    {
+        bParaStyle = m_rExport.m_pCurrentStyle->Which() == RES_TXTFMTCOLL;
+    }
+
     // Simplify styles to avoid impossible complexity. Import and export as 
defaults only
-    if ( m_rExport.m_bStyDef && nEsc )
+    if ( m_rExport.m_bStyDef && nEsc && !(bParaStyle && nEsc < 0))
     {
         nProp = DFLT_ESC_PROP;
         nEsc = (nEsc > 0) ? DFLT_ESC_AUTO_SUPER : DFLT_ESC_AUTO_SUB;
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index aa131a625ce6..b1d3b71009c6 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -2061,6 +2061,13 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
             {
                 // For some undocumented reason, MS Word seems to ignore this 
in docDefaults
 
+                const StyleSheetEntryPtr pCurrStyle = 
GetStyleSheetTable()->GetCurrentEntry();
+                if (pCurrStyle && pCurrStyle->m_nStyleTypeCode == 
STYLE_TYPE_PARA && nIntValue < 0)
+                {
+                    m_pImpl->deferCharacterProperty(nSprmId, 
uno::Any(nIntValue));
+                    break;
+                }
+
                 // DON'T FIXME: Truly calculating this for Character Styles 
will be tricky,
                 // because it depends on the final fontsize - regardless of
                 // where it is set. So at the style level,
@@ -3534,9 +3541,19 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
     }
 }
 
-void DomainMapper::processDeferredCharacterProperties( const std::map< 
sal_Int32, uno::Any >& deferredCharacterProperties )
+void DomainMapper::ProcessDeferredStyleCharacterProperties()
 {
-    assert( m_pImpl->GetTopContextType() == CONTEXT_CHARACTER );
+    assert(m_pImpl->GetTopContextType() == CONTEXT_STYLESHEET);
+    m_pImpl->processDeferredCharacterProperties(false);
+}
+
+void DomainMapper::processDeferredCharacterProperties(
+    const std::map<sal_Int32, uno::Any>& deferredCharacterProperties, bool 
bCharContext)
+{
+    if (bCharContext)
+    {
+        assert(m_pImpl->GetTopContextType() == CONTEXT_CHARACTER);
+    }
     PropertyMapPtr rContext = m_pImpl->GetTopContext();
     for( const auto& rProp : deferredCharacterProperties )
     {
diff --git a/writerfilter/source/dmapper/DomainMapper.hxx 
b/writerfilter/source/dmapper/DomainMapper.hxx
index b9771b8ad749..a452e2e6e9bc 100644
--- a/writerfilter/source/dmapper/DomainMapper.hxx
+++ b/writerfilter/source/dmapper/DomainMapper.hxx
@@ -123,7 +123,11 @@ public:
     /**
      @see DomainMapper_Impl::processDeferredCharacterProperties()
     */
-    void processDeferredCharacterProperties(const std::map<sal_Int32, 
css::uno::Any>& rDeferredCharacterProperties);
+    void processDeferredCharacterProperties(
+        const std::map<sal_Int32, css::uno::Any>& rDeferredCharacterProperties,
+        bool bCharContext = true);
+
+    void ProcessDeferredStyleCharacterProperties();
 
     /// Enable storing of seen tokens in a named grab bag.
     void enableInteropGrabBag(const OUString& aName);
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 14cdc0a155ca..41ca8bf8d45e 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -9046,12 +9046,12 @@ void 
DomainMapper_Impl::deferCharacterProperty(sal_Int32 id, const css::uno::Any
     m_deferredCharacterProperties[ id ] = value;
 }
 
-void DomainMapper_Impl::processDeferredCharacterProperties()
+void DomainMapper_Impl::processDeferredCharacterProperties(bool bCharContext)
 {
     // Actually process in DomainMapper, so that it's the same source file 
like normal processing.
     if( !m_deferredCharacterProperties.empty())
     {
-        m_rDMapper.processDeferredCharacterProperties( 
m_deferredCharacterProperties );
+        
m_rDMapper.processDeferredCharacterProperties(m_deferredCharacterProperties, 
bCharContext);
         m_deferredCharacterProperties.clear();
     }
 }
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 1e02fd8d3949..4668ebc8ac4c 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -1074,7 +1074,7 @@ public:
      Processes properties deferred using deferCharacterProperty(). To be 
called whenever the top
      CONTEXT_CHARACTER is going to be used (e.g. by appendText()).
     */
-    void processDeferredCharacterProperties();
+    void processDeferredCharacterProperties(bool bCharContext = true);
 
     sal_Int32 getNumberingProperty(const sal_Int32 nListId, sal_Int32 
nListLevel, const OUString& aProp);
     /// Get a property of the current numbering style's current level.
diff --git a/writerfilter/source/dmapper/StyleSheetTable.cxx 
b/writerfilter/source/dmapper/StyleSheetTable.cxx
index a78ac4fda2db..a7c3dc7381c7 100644
--- a/writerfilter/source/dmapper/StyleSheetTable.cxx
+++ b/writerfilter/source/dmapper/StyleSheetTable.cxx
@@ -808,6 +808,7 @@ void 
StyleSheetTable::lcl_entry(writerfilter::Reference<Properties>::Pointer_t r
     m_pImpl->m_pCurrentEntry = pNewEntry;
     m_pImpl->m_rDMapper.PushStyleSheetProperties( 
m_pImpl->m_pCurrentEntry->m_pProperties.get() );
     ref->resolve(*this);
+    m_pImpl->m_rDMapper.ProcessDeferredStyleCharacterProperties();
     //append it to the table
     m_pImpl->m_rDMapper.PopStyleSheetProperties();
     if( !m_pImpl->m_rDMapper.IsOOXMLImport() || 
!m_pImpl->m_pCurrentEntry->m_sStyleName.isEmpty())

Reply via email to