include/xmloff/txtimp.hxx               |    2 +-
 sw/inc/doc.hxx                          |    4 ++++
 sw/inc/unoparagraph.hxx                 |    3 +++
 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, 38 insertions(+), 5 deletions(-)

New commits:
commit 3ad25e14325aabc84572f7ba097e57436a975754
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 12:12:51 2025 +0500

    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 c04e577c6573..46700459321f 100644
--- a/include/xmloff/txtimp.hxx
+++ b/include/xmloff/txtimp.hxx
@@ -162,7 +162,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 3e3652fab936..fb34700187d2 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -47,6 +47,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;
@@ -1703,6 +1705,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 cbdfe202a1cb..096b442f8cf6 100644
--- a/sw/inc/unoparagraph.hxx
+++ b/sw/inc/unoparagraph.hxx
@@ -200,6 +200,9 @@ public:
 
     /// tries to return less data, but may return more than just text fields
     rtl::Reference<SwXTextPortionEnumeration> createTextFieldsEnumeration();
+
+private:
+    bool m_bDeleteWithoutCorrection = false;
 };
 
 
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 dab5270588e3..9c6a53a34037 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>
@@ -359,6 +360,12 @@ SwXParagraph::setPropertyValue(const OUString& 
rPropertyName,
         const uno::Any& rValue)
 {
     SolarMutexGuard aGuard;
+    // See XMLTextImportHelper::DeleteParagraph
+    if (rPropertyName == "DeleteWithoutCorrection")
+    {
+        m_bDeleteWithoutCorrection = true;
+        return;
+    }
     m_pImpl->SetPropertyValues_Impl( { rPropertyName }, { rValue } );
 }
 
@@ -1254,7 +1261,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_pImpl->m_Mutex);
         m_pImpl->m_EventListeners.disposeAndClear(aGuard2, ev);
diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx
index b2d312cad2e5..6b1fb43fd7c6 100644
--- a/sw/source/filter/xml/xmltbli.cxx
+++ b/sw/source/filter/xml/xmltbli.cxx
@@ -587,7 +587,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 56d21a5196f8..714713e79804 100644
--- a/xmloff/source/text/txtimp.cxx
+++ b/xmloff/source/text/txtimp.cxx
@@ -766,7 +766,7 @@ void XMLTextImportHelper::InsertTextContent(
     }
 }
 
-void XMLTextImportHelper::DeleteParagraph()
+void XMLTextImportHelper::DeleteParagraph(bool dontCorrectBookmarks)
 {
     assert(m_xImpl->m_xText.is());
     assert(m_xImpl->m_xCursor.is());
@@ -786,6 +786,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