include/svl/itemset.hxx         |    1 +
 sc/inc/patattr.hxx              |    3 +++
 sc/source/core/data/patattr.cxx |   14 +++++++++++++-
 svl/source/items/itemset.cxx    |   19 +++++++++++++++++++
 uitest/uitest/test.py           |    4 ++--
 vcl/source/control/listbox.cxx  |    2 ++
 6 files changed, 40 insertions(+), 3 deletions(-)

New commits:
commit b1df5786458223f21f0eaa9627c0f4c6fa5f1747
Author:     Noel Grandin <[email protected]>
AuthorDate: Sun Dec 21 19:55:04 2025 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Thu Jan 1 09:10:56 2026 +0100

    tdf#166684 use hashing in CellAttributeHelper::registerAndCheck
    
    reduces load time from 1m11s to 33s.
    
    Change-Id: I911c101eb8692bf678e6f7147e64e503e9f2bf0a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196062
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Tomaž Vajngerl <[email protected]>
    (cherry picked from commit 044885e896a441c96a6934b10cbb723fabcf262d)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196357
    Reviewed-by: Noel Grandin <[email protected]>
    Tested-by: Jenkins

diff --git a/include/svl/itemset.hxx b/include/svl/itemset.hxx
index 118e3da7f036..7dd32ff77791 100644
--- a/include/svl/itemset.hxx
+++ b/include/svl/itemset.hxx
@@ -246,6 +246,7 @@ public:
     const SfxItemSet*           GetParent() const { return m_pParent; }
 
     bool                        operator==(const SfxItemSet &) const;
+    size_t                      GetHashCode() const;
 
     /** Compare possibly ignoring SfxItemPool pointer.
 
diff --git a/sc/inc/patattr.hxx b/sc/inc/patattr.hxx
index f08c29710267..1bcc5675b6bb 100644
--- a/sc/inc/patattr.hxx
+++ b/sc/inc/patattr.hxx
@@ -130,6 +130,7 @@ class SAL_DLLPUBLIC_RTTI ScPatternAttr final
     friend class CellAttributeHelper;
 
     SfxItemSet                  maLocalSfxItemSet;
+    mutable std::optional<size_t> moHashCode;
     std::optional<OUString>     moName;
     mutable std::optional<bool> mxVisible;
     mutable std::optional<sal_uInt32> mxNumberFormatKey;
@@ -149,6 +150,7 @@ public:
     SC_DLLPUBLIC ~ScPatternAttr();
 
     bool operator==(const ScPatternAttr& rCmp) const;
+    size_t GetHashCode() const { if (!moHashCode) CalcHashCode(); return 
*moHashCode; }
 
     // version that allows nullptrs
     SC_DLLPUBLIC static bool areSame(const ScPatternAttr* pItem1, const 
ScPatternAttr* pItem2);
@@ -285,6 +287,7 @@ private:
     LanguageType            GetLanguageType() const;
     void                    InvalidateCaches();
     void                    InvalidateCacheFor(sal_uInt16 nWhich);
+    void                    CalcHashCode() const;
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/patattr.cxx b/sc/source/core/data/patattr.cxx
index 6f14db0c8c0c..e4e3587c807d 100644
--- a/sc/source/core/data/patattr.cxx
+++ b/sc/source/core/data/patattr.cxx
@@ -115,12 +115,14 @@ const ScPatternAttr* 
CellAttributeHelper::registerAndCheck(const ScPatternAttr&
     }
     const OUString* pCandidateStyleName = rCandidate.GetStyleName();
     auto it = maRegisteredCellAttributes.lower_bound(pCandidateStyleName);
+    const size_t nCandidateHashCode = rCandidate.GetHashCode();
     for (; it != maRegisteredCellAttributes.end(); ++it)
     {
         const ScPatternAttr* pCheck = *it;
         if (CompareStringPtr(pCheck->GetStyleName(), pCandidateStyleName) != 0)
             break;
-        if (ScPatternAttr::areSame(pCheck, &rCandidate))
+        if (nCandidateHashCode == pCheck->GetHashCode()
+            && ScPatternAttr::areSame(pCheck, &rCandidate))
         {
             pCheck->mnRefCount++;
             if (bPassingOwnership)
@@ -472,6 +474,15 @@ bool ScPatternAttr::operator==(const ScPatternAttr& rCmp) 
const
     return maLocalSfxItemSet == rCmp.maLocalSfxItemSet;
 }
 
+void ScPatternAttr::CalcHashCode() const
+{
+    size_t nHash = 0;
+    if (const OUString* pName = GetStyleName())
+        nHash = pName->hashCode();
+    o3tl::hash_combine(nHash, maLocalSfxItemSet.GetHashCode());
+    moHashCode = nHash;
+}
+
 bool ScPatternAttr::areSame(const ScPatternAttr* pItem1, const ScPatternAttr* 
pItem2)
 {
     if (pItem1 == pItem2)
@@ -1799,6 +1810,7 @@ void ScPatternAttr::InvalidateCaches()
     mxVisible.reset();
     mxNumberFormatKey.reset();
     mxLanguageType.reset();
+    moHashCode.reset();
 }
 
 SfxItemSet& ScPatternAttr::GetItemSetWritable()
diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx
index 5a7efdac8708..ae60b661a8ff 100644
--- a/svl/source/items/itemset.cxx
+++ b/svl/source/items/itemset.cxx
@@ -27,6 +27,7 @@
 
 #include <libxml/xmlwriter.h>
 #include <tools/XmlWriter.hxx>
+#include <o3tl/hash_combine.hxx>
 
 #include <sal/log.hxx>
 #include <svl/itemset.hxx>
@@ -1289,6 +1290,24 @@ bool SfxItemSet::Equals(const SfxItemSet &rCmp, bool 
bComparePool) const
     return true;
 }
 
+size_t SfxItemSet::GetHashCode() const
+{
+    size_t seed = 0;
+
+    for (PoolItemMap::const_iterator it(m_aPoolItemMap.begin()); it != 
m_aPoolItemMap.end(); it++)
+    {
+        const sal_uInt16 nWhich = it->first;
+        const SfxPoolItem *pItem = it->second;
+
+        o3tl::hash_combine(seed, nWhich);
+        if (!IsInvalidItem(pItem) && !IsDisabledItem(pItem)
+            && pItem && pItem->supportsHashCode())
+            o3tl::hash_combine(seed, pItem->hashCode());
+    }
+
+    return seed;
+}
+
 std::unique_ptr<SfxItemSet> SfxItemSet::Clone(bool bItems, SfxItemPool 
*pToPool ) const
 {
     if (pToPool && pToPool != GetPool())
commit 707fa629bb0ca29d896271e819819ef482fa7102
Author:     Noel Grandin <[email protected]>
AuthorDate: Wed Dec 31 12:19:31 2025 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Thu Jan 1 09:10:42 2026 +0100

    some 'make uicheck' fixes for windows
    
    (1) Fix a crash when calling a disposed listbox.
    (2) Load files on the main thread, prevents deadlocks
    
    Change-Id: I24e415bb589ef9cf9e0587725a9213257748ae45
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196354
    Reviewed-by: Noel Grandin <[email protected]>
    Tested-by: Jenkins

diff --git a/uitest/uitest/test.py b/uitest/uitest/test.py
index 883d6564df8d..98ede61a6cf1 100644
--- a/uitest/uitest/test.py
+++ b/uitest/uitest/test.py
@@ -86,7 +86,7 @@ class UITest(object):
                     return
                 time.sleep(DEFAULT_SLEEP)
 
-    def load_component_from_url(self, url, eventName="OnLoad", load_props=()):
+    def load_component_from_url(self, url, eventName="OnLoad", 
load_props=mkPropertyValues({"OnMainThread":True})):
         with EventListener(self._xContext, eventName) as event:
             component =  self.get_desktop().loadComponentFromURL(url, 
"_default", 0, load_props)
             while True:
@@ -99,7 +99,7 @@ class UITest(object):
 
     # Calls UITest.close_doc at exit
     @contextmanager
-    def load_file(self, url, load_props=()):
+    def load_file(self, url, 
load_props=mkPropertyValues({"OnMainThread":True})):
         try:
             yield self.load_component_from_url(url, "OnLoad", load_props)
         finally:
diff --git a/vcl/source/control/listbox.cxx b/vcl/source/control/listbox.cxx
index ce1512b05d67..58b789d4bc56 100644
--- a/vcl/source/control/listbox.cxx
+++ b/vcl/source/control/listbox.cxx
@@ -569,6 +569,8 @@ void ListBox::setPosSizePixel( tools::Long nX, tools::Long 
nY, tools::Long nWidt
 
 void ListBox::Resize()
 {
+    if (isDisposed())
+        return;
     Size aOutSz = GetOutputSizePixel();
     if( IsDropDownBox() )
     {

Reply via email to