include/xmloff/txtimp.hxx               |    2 +-
 sw/inc/doc.hxx                          |    4 ++++
 sw/inc/unoparagraph.hxx                 |    1 +
 sw/source/core/doc/doccorr.cxx          |    3 ++-
 sw/source/core/unocore/unoparagraph.cxx |   15 ++++++++++++++-
 sw/source/filter/xml/xmltbli.cxx        |    2 +-
 xmloff/source/text/txtimp.cxx           |   14 +++++++++++++-
 7 files changed, 36 insertions(+), 5 deletions(-)

New commits:
commit f9b487f44fc8a65febafc5ea713e493369be9445
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Mar 26 21:13:40 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Thu Mar 27 07:52:47 2025 +0100

    tdf#165918: Avoid bookmarks correction when removing temporary nodes
    
    When loading a table, each cell contains an extra node, which is dropped
    when finalizing the cell. The removal of the node calls SwDoc::CorrAbs,
    which it turn calls MarkManager::correctMarksAbsolute. The latter looks
    through all existing bookmarks, checking if they need to be corrected.
    In documents with lots of tables and lots of bookmarks, the time taken
    by eack following call to SwDoc::CorrAbs grows quadratically.
    
    We know, that these extra nodes in cells do not affect bookmarks, and
    it is safe to just skip these specific nodes from bookmark correction.
    
    This speeds up loading bugdoc by 40% in my testing.
    
    Change-Id: I61b587d04c9ae2301d9fef497885fb76c2d3ae74
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183348
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/include/xmloff/txtimp.hxx b/include/xmloff/txtimp.hxx
index ea6515a952d9..c9e9d451afc7 100644
--- a/include/xmloff/txtimp.hxx
+++ b/include/xmloff/txtimp.hxx
@@ -160,7 +160,7 @@ public:
     void InsertString( std::u16string_view rChars,
                        bool& rIgnoreLeadingSpace );
     // Delete current paragraph
-    void DeleteParagraph();
+    void DeleteParagraph(bool dontCorrectBookmarks = false);
 
     void InsertControlCharacter( sal_Int16 nControl );
     void InsertTextContent( css::uno::Reference< css::text::XTextContent > 
const & xContent);
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 394195589919..cb98f4b532ec 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -46,6 +46,7 @@
 #include <set>
 #include <tuple>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 namespace editeng { class SvxBorderLine; }
@@ -330,6 +331,7 @@ private:
     bool mbClipBoard             : 1;    //< TRUE: this document represents 
the clipboard
     bool mbColumnSelection       : 1;    //< TRUE: this content has been 
created by a column selection (clipboard docs only)
     bool mbIsPrepareSelAll       : 1;
+    bool mbDontCorrectBookmarks = false;
 
     enum MissingDictionary { False = -1, Undefined = 0, True = 1 };
     MissingDictionary meDictionaryMissing;
@@ -1755,6 +1757,8 @@ public:
 
     static bool HasParagraphDirectFormatting(const SwPosition& rPos);
 
+    bool SetDontCorrectBookmarks(bool val) { return 
std::exchange(mbDontCorrectBookmarks, val); }
+
 private:
     // Copies master header to left / first one, if necessary - used by 
ChgPageDesc().
     void CopyMasterHeader(const SwPageDesc &rChged, const SwFormatHeader 
&rHead, SwPageDesc &pDesc, bool bLeft, bool bFirst);
diff --git a/sw/inc/unoparagraph.hxx b/sw/inc/unoparagraph.hxx
index 42572649ded2..13e84825c33f 100644
--- a/sw/inc/unoparagraph.hxx
+++ b/sw/inc/unoparagraph.hxx
@@ -234,6 +234,7 @@ private:
     ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> 
m_EventListeners;
     SfxItemPropertySet const& m_rPropSet;
     bool m_bIsDescriptor;
+    bool m_bDeleteWithoutCorrection = false;
     sal_Int32 m_nSelectionStartPos;
     sal_Int32 m_nSelectionEndPos;
     OUString m_sText;
diff --git a/sw/source/core/doc/doccorr.cxx b/sw/source/core/doc/doccorr.cxx
index 783e1aa2346f..61cad6e1eca4 100644
--- a/sw/source/core/doc/doccorr.cxx
+++ b/sw/source/core/doc/doccorr.cxx
@@ -179,7 +179,8 @@ void SwDoc::CorrAbs(const SwNode& rOldNode,
     SwPosition aNewPos(rNewPos);
     aNewPos.AdjustContent(nOffset);
 
-    getIDocumentMarkAccess()->correctMarksAbsolute(rOldNode, rNewPos, nOffset);
+    if (!mbDontCorrectBookmarks)
+        getIDocumentMarkAccess()->correctMarksAbsolute(rOldNode, rNewPos, 
nOffset);
     // fix redlines
     {
         SwRedlineTable& rTable = getIDocumentRedlineAccess().GetRedlineTable();
diff --git a/sw/source/core/unocore/unoparagraph.cxx 
b/sw/source/core/unocore/unoparagraph.cxx
index 9696897e95e9..89a7edbad5c8 100644
--- a/sw/source/core/unocore/unoparagraph.cxx
+++ b/sw/source/core/unocore/unoparagraph.cxx
@@ -54,6 +54,7 @@
 
 #include <com/sun/star/drawing/BitmapMode.hpp>
 #include <comphelper/propertyvalue.hxx>
+#include <comphelper/scopeguard.hxx>
 #include <comphelper/sequence.hxx>
 #include <comphelper/servicehelper.hxx>
 #include <editeng/unoipset.hxx>
@@ -291,6 +292,12 @@ SwXParagraph::setPropertyValue(const OUString& 
rPropertyName,
         const uno::Any& rValue)
 {
     SolarMutexGuard aGuard;
+    // See XMLTextImportHelper::DeleteParagraph
+    if (rPropertyName == "DeleteWithoutCorrection")
+    {
+        m_bDeleteWithoutCorrection = true;
+        return;
+    }
     SetPropertyValues_Impl( { rPropertyName }, { rValue } );
 }
 
@@ -1182,7 +1189,13 @@ void SAL_CALL SwXParagraph::dispose()
     if (pTextNode)
     {
         SwCursor aCursor( SwPosition( *pTextNode ), nullptr );
-        
pTextNode->GetDoc().getIDocumentContentOperations().DelFullPara(aCursor);
+        {
+            auto& rDoc = pTextNode->GetDoc();
+            comphelper::ScopeGuard aGuard2(
+                [&rDoc, restore = 
rDoc.SetDontCorrectBookmarks(m_bDeleteWithoutCorrection)]()
+                { rDoc.SetDontCorrectBookmarks(restore); });
+            rDoc.getIDocumentContentOperations().DelFullPara(aCursor);
+        }
         lang::EventObject const ev(getXWeak());
         std::unique_lock aGuard2(m_Mutex);
         m_EventListeners.disposeAndClear(aGuard2, ev);
diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx
index 5d55d355b76b..a64efde0b759 100644
--- a/sw/source/filter/xml/xmltbli.cxx
+++ b/sw/source/filter/xml/xmltbli.cxx
@@ -586,7 +586,7 @@ void SwXMLTableCellContext_Impl::endFastElement(sal_Int32 )
     {
         if( m_bHasTextContent )
         {
-            GetImport().GetTextImport()->DeleteParagraph();
+            GetImport().GetTextImport()->DeleteParagraph(true);
             if( m_nColRepeat > 1 && m_nColSpan == 1 )
             {
                 // The original text is invalid after deleting the last
diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx
index 43dade94fcca..35ceb8d2898e 100644
--- a/xmloff/source/text/txtimp.cxx
+++ b/xmloff/source/text/txtimp.cxx
@@ -764,7 +764,7 @@ void XMLTextImportHelper::InsertTextContent(
     }
 }
 
-void XMLTextImportHelper::DeleteParagraph()
+void XMLTextImportHelper::DeleteParagraph(bool dontCorrectBookmarks)
 {
     assert(m_xImpl->m_xText.is());
     assert(m_xImpl->m_xCursor.is());
@@ -784,6 +784,18 @@ void XMLTextImportHelper::DeleteParagraph()
             assert(xComp.is());
             if( xComp.is() )
             {
+                if (dontCorrectBookmarks)
+                {
+                    try
+                    {
+                        // See SwXParagraph::setPropertyValue
+                        if (auto xProps = xComp.query<beans::XPropertySet>())
+                            
xProps->setPropertyValue(u"DeleteWithoutCorrection"_ustr, {});
+                    }
+                    catch (const beans::UnknownPropertyException&)
+                    {
+                    }
+                }
                 xComp->dispose();
                 bDelete = false;
             }

Reply via email to