sw/qa/extras/ooxmlexport/data/tdf159158_zOrder_headerBehind.odt |binary
 sw/qa/extras/ooxmlexport/ooxmlexport18.cxx                      |   15 ++
 writerfilter/inc/dmapper/GraphicZOrderHelper.hxx                |   10 +
 writerfilter/source/dmapper/DomainMapper_Impl.cxx               |    8 +
 writerfilter/source/dmapper/GraphicHelpers.cxx                  |   58 
+++++++++-
 writerfilter/source/dmapper/GraphicImport.cxx                   |   27 ----
 6 files changed, 89 insertions(+), 29 deletions(-)

New commits:
commit 9aa7dc185af99a540926cc699193449177050386
Author:     Justin Luth <justin.l...@collabora.com>
AuthorDate: Tue Feb 27 19:56:32 2024 -0500
Commit:     Justin Luth <jl...@mail.com>
CommitDate: Fri Mar 1 01:36:30 2024 +0100

    tdf#159158 writerfilter: headers always under other z-orders
    
    I guessed that a negative z-order will be below
    a positive relativeHeight when it is in the header.
    It seems like a reasonable assumption.
    No unit tests hit this situation AFAIK.
    
    make CppunitTest_sw_ooxmlexport18 \
        CPPUNIT_TEST_NAME=testTdf159158_zOrder_headerBehind
    
    Change-Id: I06e31f3df413ad9c32791c8f4b940831630131dd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164105
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <jl...@mail.com>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf159158_zOrder_headerBehind.odt 
b/sw/qa/extras/ooxmlexport/data/tdf159158_zOrder_headerBehind.odt
new file mode 100644
index 000000000000..a4bf98a1f7aa
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/tdf159158_zOrder_headerBehind.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
index 084863c144f4..91fa26ea0a47 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
@@ -1032,6 +1032,21 @@ 
DECLARE_OOXMLEXPORT_TEST(testTdf159158_zOrder_behindDocB, "tdf159158_zOrder_behi
         CPPUNIT_ASSERT_EQUAL(OUString("5-Point Star Blue"), 
getProperty<OUString>(zOrder1,"Name"));
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf159158_zOrder_headerBehind, 
"tdf159158_zOrder_headerBehind.odt")
+{
+    // given a blue star (not marked as behind text) anchored in the header
+    // and an overlapping yellow rectangle anchored in the body text.
+    // (note that in ODT format the star is on top, but for DOCX format it 
must be behind (hidden)
+    uno::Reference<beans::XPropertySet> zOrder0(getShape(1), uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> zOrder1(getShape(2), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(zOrder0, 
"ZOrder")); // lower
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), getProperty<sal_Int32>(zOrder1, 
"ZOrder")); // higher
+    // I don't know why the star is the lowest order in ODT import (maybe 
header weirdness),
+    // but it certainly needs to be the lowest on docx round-trip (also for 
header weirdness)
+    CPPUNIT_ASSERT_EQUAL(OUString("StarInHeader"), 
getProperty<OUString>(zOrder0, "Name"));
+    CPPUNIT_ASSERT_EQUAL(OUString("RectangleInBody"), 
getProperty<OUString>(zOrder1,"Name"));
+}
+
 DECLARE_OOXMLEXPORT_TEST(testTdf155903, "tdf155903.odt")
 {
     // Without the accompanying fix in place, this test would have crashed,
diff --git a/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx 
b/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx
index c6a308ddf819..b5bb27eea81b 100644
--- a/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx
+++ b/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx
@@ -17,11 +17,15 @@ class GraphicZOrderHelper
 {
 public:
     void addItem(css::uno::Reference<css::beans::XPropertySet> const& props,
-                 sal_Int32 relativeHeight);
-    sal_Int32 findZOrder(sal_Int32 relativeHeight, bool bOldStyle = false);
+                 sal_Int64 relativeHeight);
+
+    // must run adjustRelativeHeight before findZOrder - to set zOrder 
priorities
+    static void adjustRelativeHeight(sal_Int64& rRelativeHeight, bool 
bIsZIndex, bool bIsBehindText,
+                                     bool bIsInHeader);
+    sal_Int32 findZOrder(sal_Int64 relativeHeight, bool bOldStyle = false);
 
 private:
-    using Items = std::map<sal_Int32, 
css::uno::Reference<css::beans::XPropertySet>>;
+    using Items = std::map<sal_Int64, 
css::uno::Reference<css::beans::XPropertySet>>;
     Items m_items;
 };
 
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 45ff00958083..bbdfbd35c34a 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -4763,8 +4763,10 @@ void DomainMapper_Impl::PushShapeContext( const 
uno::Reference< drawing::XShape
                     if (rProp.Name == "VML-Z-ORDER")
                     {
                         GraphicZOrderHelper& rZOrderHelper = 
m_rDMapper.graphicZOrderHelper();
-                        sal_Int32 zOrder(0);
+                        sal_Int64 zOrder(0);
                         rProp.Value >>= zOrder;
+                        GraphicZOrderHelper::adjustRelativeHeight(zOrder, 
/*IsZIndex=*/true,
+                                                                  zOrder < 0, 
IsInHeaderFooter());
                         xShapePropertySet->setPropertyValue("ZOrder",
                             uno::Any(rZOrderHelper.findZOrder(zOrder, 
/*LastDuplicateWins*/true)));
                         rZOrderHelper.addItem(xShapePropertySet, zOrder);
@@ -4808,8 +4810,10 @@ void DomainMapper_Impl::PushShapeContext( const 
uno::Reference< drawing::XShape
                     if (rProp.Name == "VML-Z-ORDER")
                     {
                         GraphicZOrderHelper& rZOrderHelper = 
m_rDMapper.graphicZOrderHelper();
-                        sal_Int32 zOrder(0);
+                        sal_Int64 zOrder(0);
                         rProp.Value >>= zOrder;
+                        GraphicZOrderHelper::adjustRelativeHeight(zOrder, 
/*IsZIndex=*/true,
+                                                                  zOrder < 0, 
IsInHeaderFooter());
                         xShapePropertySet->setPropertyValue("ZOrder",
                             uno::Any(rZOrderHelper.findZOrder(zOrder, 
/*LastDuplicateWins*/true)));
                         rZOrderHelper.addItem(xShapePropertySet, zOrder);
diff --git a/writerfilter/source/dmapper/GraphicHelpers.cxx 
b/writerfilter/source/dmapper/GraphicHelpers.cxx
index d01ac5be3800..32e13b04bec8 100644
--- a/writerfilter/source/dmapper/GraphicHelpers.cxx
+++ b/writerfilter/source/dmapper/GraphicHelpers.cxx
@@ -270,11 +270,65 @@ text::WrapTextMode WrapHandler::getWrapMode( ) const
 }
 
 
-void GraphicZOrderHelper::addItem(uno::Reference<beans::XPropertySet> const& 
props, sal_Int32 const relativeHeight)
+void GraphicZOrderHelper::addItem(uno::Reference<beans::XPropertySet> const& 
props,
+                                  sal_Int64 const relativeHeight)
 {
     m_items[ relativeHeight ] = props;
 }
 
+void GraphicZOrderHelper::adjustRelativeHeight(sal_Int64& rRelativeHeight, 
bool bIsZIndex,
+                                               bool bIsBehindText, bool 
bIsInHeader)
+{
+    // zOrder can be defined either by z-index (VML) or by relativeHeight 
(DML).
+    // z-index indicates background with a negative value,
+    // while relativeHeight indicates background with behindDoc = true.
+    //
+    // In general, all z-index-defined shapes appear on top of relativeHeight 
graphics
+    // regardless of the value.
+
+    // priority order
+    // above text:  positive sal_Int32 z-index (opaque/in front of text)
+    //              relativeHeight (represented here as a negative sal_Int32, 
but still opaque)
+    // behind body: negative sal_Int32 z-index (!opaque/in the background)
+    //              behindText relativeHeight
+    //              (in header) positive z-index
+    //              (in header) relativeHeight
+    //              (in header) negative z-index
+    //              (in header) behindText
+
+    const sal_Int64 nMaxUnsignedInt32 = SAL_MAX_UINT32;
+    if (!bIsInHeader)
+    {
+        if (bIsZIndex)
+        {
+            // this number is already fine
+            // positive values are the only positive values coming into zOrder,
+            // and negative values will be !opaque (below text)
+        }
+        else if (!bIsBehindText)
+        {
+            assert (rRelativeHeight < 0);
+            // this number is already fine - will be above text, but 
relativeHeight is negative
+        }
+        else
+        {
+            // reduce to negative level 1 to force below a negative z-index
+            rRelativeHeight -= nMaxUnsignedInt32;
+        }
+    }
+    else // bIsInHeader
+    {
+        if (bIsZIndex && !bIsBehindText)
+            rRelativeHeight -= nMaxUnsignedInt32 * 2; // reduce to negative 
level 2
+        else if (!bIsBehindText)
+            rRelativeHeight -= nMaxUnsignedInt32 * 3; // reduce to negative 
level 3
+        else if (bIsZIndex)
+            rRelativeHeight -= nMaxUnsignedInt32 * 4; // reduce to negative 
level 4
+        else
+            rRelativeHeight -= nMaxUnsignedInt32 * 5; // reduce to negative 
level 5
+    }
+}
+
 // The relativeHeight value in .docx is an arbitrary number, where only the 
relative ordering matters.
 // But in Writer, the z-order is index in 0..(numitems-1) range, so whenever a 
new item needs to be
 // added in the proper z-order, it is necessary to find the proper index.
@@ -282,7 +336,7 @@ void 
GraphicZOrderHelper::addItem(uno::Reference<beans::XPropertySet> const& pro
 // The key to this function is that later on, when setPropertyValue("ZOrder", 
<returned sal_Int32>),
 // SW also automatically increments ALL zOrders >= the one returned for this 
fly.
 // Thus, getProperty PROP_Z_ORDER for relativeHeight "x" can return different 
values for itemZOrder.
-sal_Int32 GraphicZOrderHelper::findZOrder( sal_Int32 relativeHeight, bool 
bOldStyle )
+sal_Int32 GraphicZOrderHelper::findZOrder(sal_Int64 relativeHeight, bool 
bOldStyle)
 {
     // std::map is iterated sorted by key
     auto it = std::find_if(m_items.cbegin(), m_items.cend(),
diff --git a/writerfilter/source/dmapper/GraphicImport.cxx 
b/writerfilter/source/dmapper/GraphicImport.cxx
index bee20740278f..386ac693d81b 100644
--- a/writerfilter/source/dmapper/GraphicImport.cxx
+++ b/writerfilter/source/dmapper/GraphicImport.cxx
@@ -210,7 +210,7 @@ public:
     sal_Int32 m_nTopPosition;
 
     bool      m_bUseSimplePos;
-    std::optional<sal_Int32> m_oZOrder;
+    std::optional<sal_Int64> m_oZOrder;
 
     sal_Int16 m_nHoriOrient;
     sal_Int16 m_nHoriRelation;
@@ -390,36 +390,19 @@ public:
 
     void applyZOrder(uno::Reference<beans::XPropertySet> const & 
xGraphicObjectProperties) const
     {
-        std::optional<sal_Int32> oZOrder = m_oZOrder;
+        std::optional<sal_Int64> oZOrder = m_oZOrder;
         if (m_rGraphicImportType == 
GraphicImportType::IMPORT_AS_DETECTED_INLINE
             && !m_rDomainMapper.IsInShape())
         {
-            oZOrder = SAL_MIN_INT32;
+            oZOrder = SAL_MIN_INT64;
         }
         else if (!oZOrder)
             return;
         else
         {
-            // tdf#120760 Send objects with behinddoc=true to the back.
-
-            // zOrder can be defined either by z-index or by relativeHeight.
-            // z-index indicates background with a negative value,
-            // while relativeHeight indicates background with BehindDoc = true.
-            //
-            // In general, all z-index-defined shapes appear on top of 
relativeHeight graphics
-            // regardless of the value.
-            // So we have to try to put all relativeHeights as far back as 
possible,
-            // and this has already partially happened because they were 
already made to be negative
-            // but now the behindDoc relativeHeights need to be forced to the 
very back.
-            //
-            // Subtract even more so behindDoc relativeHeights will be behind
-            // foreground relativeHeights and also behind all of the negative 
z-indexes
-            // (especially needed for IsInHeaderFooter, as EVERYTHING is 
forced to the background).
-            //
-            // relativeHeight already removed 0x1E00 0000, so can subtract 
another 0x6200 0000
             const bool bBehindText = m_bBehindDoc && !m_bOpaque;
-            if (bBehindText)
-                oZOrder = *oZOrder - 0x62000000;
+            GraphicZOrderHelper::adjustRelativeHeight(*oZOrder, 
/*IsZIndex=*/false, bBehindText,
+                                                      
m_rDomainMapper.IsInHeaderFooter());
         }
 
         // TODO: it is possible that RTF has been wrong all along as well. 
Always true here?

Reply via email to