include/oox/vml/vmlshapecontainer.hxx    |    5 ++++-
 sc/source/filter/inc/commentsbuffer.hxx  |    3 ++-
 sc/source/filter/inc/drawingfragment.hxx |    8 ++++++++
 sc/source/filter/oox/commentsbuffer.cxx  |   11 ++++++++---
 sc/source/filter/oox/drawingfragment.cxx |   20 ++++++++++++++++++++
 5 files changed, 42 insertions(+), 5 deletions(-)

New commits:
commit b3df12b9781daa19eff2b1e30526e65ca2aaa193
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Thu May 22 11:09:10 2025 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Sun May 25 12:31:17 2025 +0200

    tdf#166684 avoid O(n^2) loop when importing comments
    
    shaves 5% off load time
    
    Change-Id: I5778b619b859c4090f6d35b1608032148f81795c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185652
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/include/oox/vml/vmlshapecontainer.hxx 
b/include/oox/vml/vmlshapecontainer.hxx
index 6f50730bcacc..5f8dc70ba97e 100644
--- a/include/oox/vml/vmlshapecontainer.hxx
+++ b/include/oox/vml/vmlshapecontainer.hxx
@@ -53,6 +53,8 @@ struct ShapeParentAnchor
 class ShapeContainer
 {
 public:
+    typedef RefVector< ShapeBase >                  ShapeVector;
+
     explicit            ShapeContainer( Drawing& rDrawing );
                         ~ShapeContainer();
 
@@ -106,9 +108,10 @@ public:
                             const css::uno::Reference< css::drawing::XShapes 
>& rxShapes,
                             const ShapeParentAnchor* pParentAnchor = nullptr ) 
const;
 
+    const ShapeVector & getAllShapes() const { return maShapes; }
+
 private:
     typedef RefVector< ShapeType >                  ShapeTypeVector;
-    typedef RefVector< ShapeBase >                  ShapeVector;
     typedef RefMap< OUString, ShapeType >    ShapeTypeMap;
     typedef RefMap< OUString, ShapeBase >    ShapeMap;
 
diff --git a/sc/source/filter/inc/commentsbuffer.hxx 
b/sc/source/filter/inc/commentsbuffer.hxx
index 74e4d7cb123d..a1c6c8fb65b5 100644
--- a/sc/source/filter/inc/commentsbuffer.hxx
+++ b/sc/source/filter/inc/commentsbuffer.hxx
@@ -21,6 +21,7 @@
 
 #include "richstring.hxx"
 #include "worksheethelper.hxx"
+#include "drawingfragment.hxx"
 #include <com/sun/star/awt/Rectangle.hpp>
 
 namespace oox::xls {
@@ -58,7 +59,7 @@ public:
     RichStringRef const & createText();
 
     /** Finalizes the formatted string of the comment. */
-    void                finalizeImport();
+    void                finalizeImport(const VmlDrawing::NoteShapesMap& 
rNoteShapeMap);
 
     OUString getAuthorName();
 
diff --git a/sc/source/filter/inc/drawingfragment.hxx 
b/sc/source/filter/inc/drawingfragment.hxx
index 820983a80262..64c7644e3ca3 100644
--- a/sc/source/filter/inc/drawingfragment.hxx
+++ b/sc/source/filter/inc/drawingfragment.hxx
@@ -141,11 +141,19 @@ private:
 class VmlDrawing final : public ::oox::vml::Drawing, public WorksheetHelper
 {
 public:
+    struct NoteShapesMapHash
+    {
+        size_t operator()(const std::pair<sal_Int32, sal_Int32> & key) const;
+    };
+    using NoteShapesMap = std::unordered_map<std::pair<sal_Int32,sal_Int32>, 
const ::oox::vml::ShapeBase*, NoteShapesMapHash>;
+
     explicit            VmlDrawing( const WorksheetHelper& rHelper );
 
     /** Returns the drawing shape for a cell note at the specified position. */
     const ::oox::vml::ShapeBase* getNoteShape( const ScAddress& rPos ) const;
 
+    NoteShapesMap buildNoteShapesMap() const;
+
     /** Filters cell note shapes. */
     virtual bool        isShapeSupported( const ::oox::vml::ShapeBase& rShape 
) const override;
 
diff --git a/sc/source/filter/oox/commentsbuffer.cxx 
b/sc/source/filter/oox/commentsbuffer.cxx
index 1f1b0b242fde..cc01420cd0a2 100644
--- a/sc/source/filter/oox/commentsbuffer.cxx
+++ b/sc/source/filter/oox/commentsbuffer.cxx
@@ -188,7 +188,7 @@ namespace
     };
 }
 
-void Comment::finalizeImport()
+void Comment::finalizeImport(const VmlDrawing::NoteShapesMap& rNoteShapesMap)
 {
     // BIFF12 stores cell range instead of cell address, use first cell of 
this range
     OSL_ENSURE( maModel.maRange.aStart == maModel.maRange.aEnd,
@@ -221,8 +221,10 @@ void Comment::finalizeImport()
 
         // convert shape formatting and visibility
         bool bVisible = true;
-        if( const ::oox::vml::ShapeBase* pVmlNoteShape = 
getVmlDrawing().getNoteShape( maModel.maRange.aStart ) )
+        auto it = 
rNoteShapesMap.find(std::make_pair(maModel.maRange.aStart.Col(), 
maModel.maRange.aStart.Row()));
+        if( it != rNoteShapesMap.end() )
         {
+            const ::oox::vml::ShapeBase* pVmlNoteShape = it->second;
             // position and formatting
             css::awt::Rectangle aShapeRect = 
pVmlNoteShape->getShapeRectangle();
             if (aShapeRect.Width > 0 || aShapeRect.Height > 0)
@@ -313,7 +315,10 @@ void CommentsBuffer::finalizeImport()
     auto pModel = getScDocument().GetDrawLayer();
     bool bWasLocked = pModel->isLocked();
     pModel->setLock(true);
-    maComments.forEachMem( &Comment::finalizeImport );
+    // build an index once, instead of scanning a potentially large list for 
every note.
+    VmlDrawing::NoteShapesMap aNoteShapesIndex = 
getVmlDrawing().buildNoteShapesMap();
+    for (const std::shared_ptr<Comment> & rxComment : maComments)
+        rxComment->finalizeImport(aNoteShapesIndex);
     pModel->setLock(bWasLocked);
 }
 
diff --git a/sc/source/filter/oox/drawingfragment.cxx 
b/sc/source/filter/oox/drawingfragment.cxx
index 85e809b55591..6b58204ddc1d 100644
--- a/sc/source/filter/oox/drawingfragment.cxx
+++ b/sc/source/filter/oox/drawingfragment.cxx
@@ -483,6 +483,26 @@ const ::oox::vml::ShapeBase* VmlDrawing::getNoteShape( 
const ScAddress& rPos ) c
     return getShapes().findShape( VmlFindNoteFunc( rPos ) );
 }
 
+VmlDrawing::NoteShapesMap VmlDrawing::buildNoteShapesMap() const
+{
+    VmlDrawing::NoteShapesMap aMap;
+    for (const std::shared_ptr<oox::vml::ShapeBase> & rxShape : 
getShapes().getAllShapes())
+    {
+        const ::oox::vml::ClientData* pClientData = rxShape->getClientData();
+        if (pClientData)
+            aMap[std::make_pair(pClientData->mnCol, pClientData->mnRow)] = 
rxShape.get();
+    }
+    return aMap;
+}
+
+size_t VmlDrawing::NoteShapesMapHash::operator()(const std::pair<sal_Int32, 
sal_Int32>& rKey) const
+{
+    std::size_t seed = 0;
+    o3tl::hash_combine(seed, rKey.first);
+    o3tl::hash_combine(seed, rKey.second);
+    return seed;
+}
+
 bool VmlDrawing::isShapeSupported( const ::oox::vml::ShapeBase& rShape ) const
 {
     const ::oox::vml::ClientData* pClientData = rShape.getClientData();

Reply via email to