sw/inc/shellio.hxx                               |    6 ++
 sw/qa/extras/tiledrendering2/data/numrules.odt   |binary
 sw/qa/extras/tiledrendering2/tiledrendering2.cxx |   62 +++++++++++++++++++++--
 sw/source/filter/basflt/shellio.cxx              |    5 +
 sw/source/uibase/dochdl/swdtflvr.cxx             |   15 +++++
 5 files changed, 84 insertions(+), 4 deletions(-)

New commits:
commit dc3e022866893d8c0950f2269c0c8d61c24ed9bf
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Jul 15 14:40:24 2024 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Jul 15 17:11:00 2024 +0200

    cool#9504 sw: don't invalidate num rules when pasting into a non-num 
paragraph
    
    The bugdoc has ~300 pages of content, most of that is bullets, but
    otherwise not complex, pasting a trivial string at doc end (which is not
    a bulleted paragraph) takes a noticeable time:
    
    debug:20449:20330: SwLayAction::InternalAction: start
    debug:20449:20330: SwLayAction::InternalAction: end, took 268 ms
    
    Profiling points out that we re-layout the internal document, which is
    not expected: we just pasted on the first page, causing no layout change
    on page 2 and later pages. Watching who turns on m_bInvalidContent on
    the page frames, it can be noticed that SwReader::Read() invalidates all
    numberings after pasting.
    
    Fix the problem by not doing that in case we paste plain text and we
    know the insertion point is not in a numbering: the invalidation is not
    useful in this case and fixes the unexpected delay.
    
    Other related ideas are 1) don't do the layout for all pages in one go
    2) recognize that the bullets need no invalidation, unlike an actual
    numbering with numbers. Neither of these are done in this commit yet.
    
    Change-Id: Id7b2c022b31acb358f42ddd77195db70ae451109
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170499
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/inc/shellio.hxx b/sw/inc/shellio.hxx
index d802cc80d446..370f6f6daa68 100644
--- a/sw/inc/shellio.hxx
+++ b/sw/inc/shellio.hxx
@@ -154,6 +154,7 @@ class SW_DLLPUBLIC SwReader: public SwDocFac
     OUString maFileName;
     OUString msBaseURL;
     bool mbSkipImages;
+    bool mbSkipInvalidateNumRules = false;
 
 public:
 
@@ -175,6 +176,11 @@ public:
     bool HasGlossaries( const Reader& );
     bool ReadGlossaries( const Reader&, SwTextBlocks&, bool bSaveRelFiles );
 
+    void SetSkipInvalidateNumRules(bool bSkipInvalidateNumRules)
+    {
+        mbSkipInvalidateNumRules = bSkipInvalidateNumRules;
+    }
+
 protected:
     void                SetBaseURL( const OUString& rURL ) { msBaseURL = rURL; 
}
     void                SetSkipImages( bool bSkipImages ) { mbSkipImages = 
bSkipImages; }
diff --git a/sw/qa/extras/tiledrendering2/data/numrules.odt 
b/sw/qa/extras/tiledrendering2/data/numrules.odt
new file mode 100644
index 000000000000..8beaba7fd0bd
Binary files /dev/null and b/sw/qa/extras/tiledrendering2/data/numrules.odt 
differ
diff --git a/sw/qa/extras/tiledrendering2/tiledrendering2.cxx 
b/sw/qa/extras/tiledrendering2/tiledrendering2.cxx
index 331dca09b167..779192bdc250 100644
--- a/sw/qa/extras/tiledrendering2/tiledrendering2.cxx
+++ b/sw/qa/extras/tiledrendering2/tiledrendering2.cxx
@@ -21,6 +21,7 @@
 #include <sfx2/lokhelper.hxx>
 #include <test/lokcallback.hxx>
 #include <sfx2/msgpool.hxx>
+#include <comphelper/string.hxx>
 
 #include <wrtsh.hxx>
 #include <view.hxx>
@@ -42,7 +43,7 @@ public:
     virtual void tearDown() override;
 
 protected:
-    SwXTextDocument* createDoc();
+    SwXTextDocument* createDoc(const char* pName = nullptr);
 };
 
 SwTiledRenderingTest::SwTiledRenderingTest()
@@ -69,9 +70,12 @@ void SwTiledRenderingTest::tearDown()
     test::BootstrapFixture::tearDown();
 }
 
-SwXTextDocument* SwTiledRenderingTest::createDoc()
+SwXTextDocument* SwTiledRenderingTest::createDoc(const char* pName)
 {
-    createSwDoc();
+    if (!pName)
+        createSwDoc();
+    else
+        createSwDoc(pName);
     auto pTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
     CPPUNIT_ASSERT(pTextDocument);
     
pTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
@@ -86,6 +90,8 @@ class ViewCallback final
 
 public:
     std::vector<OString> m_aStateChanges;
+    tools::Rectangle m_aInvalidations;
+    bool m_bFullInvalidateSeen = false;
     TestLokCallbackWrapper m_callbackWrapper;
 
     ViewCallback()
@@ -112,6 +118,24 @@ public:
     {
         switch (nType)
         {
+            case LOK_CALLBACK_INVALIDATE_TILES:
+            {
+                if (std::string_view("EMPTY") == pPayload)
+                {
+                    m_bFullInvalidateSeen = true;
+                    return;
+                }
+                uno::Sequence<OUString> aSeq
+                    = 
comphelper::string::convertCommaSeparated(OUString::fromUtf8(pPayload));
+                CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), 
aSeq.getLength());
+                tools::Rectangle aInvalidation;
+                aInvalidation.SetLeft(aSeq[0].toInt32());
+                aInvalidation.SetTop(aSeq[1].toInt32());
+                aInvalidation.setWidth(aSeq[2].toInt32());
+                aInvalidation.setHeight(aSeq[3].toInt32());
+                m_aInvalidations.Union(aInvalidation);
+                break;
+            }
             case LOK_CALLBACK_STATE_CHANGED:
             {
                 m_aStateChanges.push_back(pPayload);
@@ -175,6 +199,38 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testStatusBarPageNumber)
     // i.e. view 2 got the page number of view 1.
     CPPUNIT_ASSERT_EQUAL(".uno:StatePageNumber=Page 2 of 2"_ostr, 
aView2.m_aStateChanges[0]);
 }
+
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testPasteInvalidateNumRules)
+{
+    // Given a document with 3 pages: first page is ~empty, then page break, 
then pages 2 & 3 have
+    // bullets:
+    SwXTextDocument* pXTextDocument = createDoc("numrules.odt");
+    CPPUNIT_ASSERT(pXTextDocument);
+    ViewCallback aView;
+    SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/true);
+    pWrtShell->Down(/*bSelect=*/false);
+    pWrtShell->Insert(u"test"_ustr);
+    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 4, 
/*bBasicCall=*/false);
+    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
+    aView.m_aInvalidations = tools::Rectangle();
+    aView.m_bFullInvalidateSeen = false;
+
+    // When pasting at the end of page 1:
+    dispatchCommand(mxComponent, u".uno:PasteUnformatted"_ustr, {});
+
+    // Then make sure we only invalidate page 1, not page 2 or page 3:
+    CPPUNIT_ASSERT(!aView.m_bFullInvalidateSeen);
+    SwRootFrame* pLayout = pWrtShell->GetLayout();
+    SwFrame* pPage1 = pLayout->GetLower();
+    
CPPUNIT_ASSERT(aView.m_aInvalidations.Overlaps(pPage1->getFrameArea().SVRect()));
+    SwFrame* pPage2 = pPage1->GetNext();
+    // Without the accompanying fix in place, this test would have failed, we 
invalidated page 2 and
+    // page 3 as well.
+    
CPPUNIT_ASSERT(!aView.m_aInvalidations.Overlaps(pPage2->getFrameArea().SVRect()));
+    SwFrame* pPage3 = pPage2->GetNext();
+    
CPPUNIT_ASSERT(!aView.m_aInvalidations.Overlaps(pPage3->getFrameArea().SVRect()));
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/basflt/shellio.cxx 
b/sw/source/filter/basflt/shellio.cxx
index 9c306617d501..875d67d4321a 100644
--- a/sw/source/filter/basflt/shellio.cxx
+++ b/sw/source/filter/basflt/shellio.cxx
@@ -342,7 +342,10 @@ ErrCodeMsg SwReader::Read( const Reader& rOptions )
     mxDoc->SetInXMLImport( false );
     mxDoc->SetInWriterfilterImport(false);
 
-    mxDoc->InvalidateNumRules();
+    if (!mbSkipInvalidateNumRules)
+    {
+        mxDoc->InvalidateNumRules();
+    }
     mxDoc->UpdateNumRule();
     mxDoc->ChkCondColls();
     mxDoc->SetAllUniqueFlyNames();
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx 
b/sw/source/uibase/dochdl/swdtflvr.cxx
index 29e3d74984be..e9cbe2fe675d 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -2152,11 +2152,22 @@ bool SwTransferable::PasteFileContent( const 
TransferableDataHelper& rData,
     SvStream* pStream = nullptr;
     Reader* pRead = nullptr;
     OUString sData;
+    bool bSkipInvalidateNumRules = false;
     switch( nFormat )
     {
     case SotClipboardFormatId::STRING:
         {
             pRead = ReadAscii;
+
+            const SwPosition& rInsertPosition = *rSh.GetCursor()->Start();
+            SwTextNode* pTextNode = rInsertPosition.GetNode().GetTextNode();
+            if (pTextNode && !pTextNode->GetNum())
+            {
+                // Insertion point is not a numbering and we paste plain text: 
then no need to
+                // invalidate all numberings.
+                bSkipInvalidateNumRules = true;
+            }
+
             if( rData.GetString( nFormat, sData ) )
             {
                 pStream = new SvMemoryStream( const_cast<sal_Unicode 
*>(sData.getStr()),
@@ -2216,6 +2227,10 @@ bool SwTransferable::PasteFileContent( const 
TransferableDataHelper& rData,
 
         if (bIgnoreComments)
             pRead->SetIgnoreHTMLComments(true);
+        if (bSkipInvalidateNumRules)
+        {
+            aReader.SetSkipInvalidateNumRules(bSkipInvalidateNumRules);
+        }
 
         if( aReader.Read( *pRead ).IsError() )
             pResId = STR_ERROR_CLPBRD_READ;

Reply via email to