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;