sc/qa/unit/cond_format.cxx                |   14 ++++++++++++++
 sc/qa/unit/data/xlsx/tdf169379.xlsx       |binary
 sc/qa/unit/subsequent_export_test4.cxx    |    5 +++--
 sc/source/filter/oox/condformatbuffer.cxx |   17 +++++++++++++----
 4 files changed, 30 insertions(+), 6 deletions(-)

New commits:
commit 204d7655010199bb1c70ce7dee5428f2f02d4808
Author:     Noel Grandin <[email protected]>
AuthorDate: Fri Nov 14 10:52:50 2025 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Fri Nov 14 12:18:39 2025 +0100

    tdf#169379 Conditional formats collapsed
    
    We were combining conditional formats that the user wanted kept separate.
    
    This is a regression from
        commit e2cc1f8a6bd27907800416a5396942a0c7ca56ce
        Author: Noel Grandin <[email protected]>
        Date:   Fri Feb 28 10:51:44 2025 +0200
        tdf#134864 speedup load of pathological conditional formats in XLS
    
    We lose some performance by doing less deduplication, but luckily not too 
much,
    the pathological document from tdf#134864 loads in about twice the time now.
    (but still much much faster than before the optimisation)
    
    Change-Id: Id8c5741ad69bec7ca43f1b0fb53022bc617fffdd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194009
    Reviewed-by: Noel Grandin <[email protected]>
    Tested-by: Jenkins

diff --git a/sc/qa/unit/cond_format.cxx b/sc/qa/unit/cond_format.cxx
index b8effde2664a..44d5b11ae782 100644
--- a/sc/qa/unit/cond_format.cxx
+++ b/sc/qa/unit/cond_format.cxx
@@ -1166,4 +1166,18 @@ CPPUNIT_TEST_FIXTURE(CondFormatTest, testTdf79998)
     CPPUNIT_ASSERT_EQUAL(u"Utilities (FX Kurse, Kreditkart"_ustr, 
aTabNames2[1]);
 }
 
+// Test that we do not deduplicate conditional formats more than we should.
+CPPUNIT_TEST_FIXTURE(CondFormatTest, tdf169379)
+{
+    // previously, we were combining all of these into one conditional format.
+    createScDoc("xlsx/tdf169379.xlsx");
+    ScDocument* pDoc = getScDoc();
+    ScConditionalFormat* pFormat = pDoc->GetCondFormat(0, 0, 0); // first 
column
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(3), pFormat->GetKey());
+    pFormat = pDoc->GetCondFormat(1, 0, 0); // second column
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(2), pFormat->GetKey());
+    pFormat = pDoc->GetCondFormat(2, 0, 0); // third column
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), pFormat->GetKey());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/qa/unit/data/xlsx/tdf169379.xlsx 
b/sc/qa/unit/data/xlsx/tdf169379.xlsx
new file mode 100644
index 000000000000..0fb819b83d7a
Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf169379.xlsx differ
diff --git a/sc/qa/unit/subsequent_export_test4.cxx 
b/sc/qa/unit/subsequent_export_test4.cxx
index d9a6ab69945b..6d71550692b6 100644
--- a/sc/qa/unit/subsequent_export_test4.cxx
+++ b/sc/qa/unit/subsequent_export_test4.cxx
@@ -1513,10 +1513,11 @@ CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf148820)
     xmlDocUniquePtr pSheet = parseExport(u"xl/worksheets/sheet1.xml"_ustr);
     CPPUNIT_ASSERT(pSheet);
 
-    CPPUNIT_ASSERT_EQUAL(u"5"_ustr,
+    CPPUNIT_ASSERT_EQUAL(u"20"_ustr,
                          getXPathContent(pSheet, 
"count(/x:worksheet/x:conditionalFormatting)"));
     CPPUNIT_ASSERT_EQUAL(
-        u"5"_ustr, getXPathContent(pSheet, 
"count(/x:worksheet/x:conditionalFormatting/x:cfRule)"));
+        u"20"_ustr,
+        getXPathContent(pSheet, 
"count(/x:worksheet/x:conditionalFormatting/x:cfRule)"));
     sal_Int32 nDxfIdCondFormatFirst
         = getXPath(pSheet, "/x:worksheet/x:conditionalFormatting[1]/x:cfRule", 
"dxfId").toInt32()
           + 1;
diff --git a/sc/source/filter/oox/condformatbuffer.cxx 
b/sc/source/filter/oox/condformatbuffer.cxx
index b4033f170652..20426cc4393f 100644
--- a/sc/source/filter/oox/condformatbuffer.cxx
+++ b/sc/source/filter/oox/condformatbuffer.cxx
@@ -1352,13 +1352,22 @@ private:
     static size_t hashCode(const CondFormat& r)
     {
         std::size_t seed(0);
-        // note that we deliberately skip the maRanges field, because, if 
necessary, we will merge
-        // new entries into that field.
+        o3tl::hash_combine(seed, hashCode(r.maModel.maRanges));
         o3tl::hash_combine(seed, r.maModel.mbPivot);
         for (const auto & rPair : r.maRules)
             o3tl::hash_combine(seed, hashCode(*rPair.second));
         return seed;
     }
+    static size_t hashCode(const ScRangeList& rRangeList)
+    {
+        std::size_t seed(0);
+        for (const ScRange & rRange : rRangeList)
+        {
+            o3tl::hash_combine(seed, rRange.aStart);
+            o3tl::hash_combine(seed, rRange.aEnd);
+        }
+        return seed;
+    }
     static size_t hashCode(const CondFormatRule& r)
     {
         std::size_t seed(0);
@@ -1396,8 +1405,8 @@ struct CondFormatEquals
     {
         if (lhs.get() == rhs.get())
             return true;
-        // note that we deliberately skip the maRanges field, because, if 
necessary, we will merge
-        // new entries into that field.
+        if (lhs->maModel.maRanges != rhs->maModel.maRanges)
+            return false;
         if (lhs->maModel.mbPivot != rhs->maModel.mbPivot)
             return false;
         auto it1 = lhs->maRules.begin();

Reply via email to