/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "tiledrenderingmodeltestbase.cxx" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testStatusBarPageNumber) { // Given a document with 2 pages, first view on page 1, second view on page 2: SwXTextDocument* pXTextDocument = createDoc(); int nView1 = SfxLokHelper::getView(); SwWrtShell* pWrtShell1 = getSwDocShell()->GetWrtShell(); pWrtShell1->InsertPageBreak(); SwRootFrame* pLayout = pWrtShell1->getIDocumentLayoutAccess().GetCurrentLayout(); SwFrame* pPage1 = pLayout->GetLower(); CPPUNIT_ASSERT(pPage1); SwFrame* pPage2 = pPage1->GetNext(); CPPUNIT_ASSERT(pPage2); SfxLokHelper::createView(); int nView2 = SfxLokHelper::getView(); pXTextDocument->initializeForTiledRendering(uno::Sequence()); SfxLokHelper::setView(nView1); ViewCallback aView1; pWrtShell1->SttEndDoc(/*bStt=*/true); pWrtShell1->Insert(u"start"_ustr); pWrtShell1->GetView().SetVisArea(pPage1->getFrameArea().SVRect()); SfxLokHelper::setView(nView2); ViewCallback aView2; SwWrtShell* pWrtShell2 = getSwDocShell()->GetWrtShell(); pWrtShell2->SttEndDoc(/*bStt=*/false); pWrtShell2->Insert(u"end"_ustr); pWrtShell2->GetView().SetVisArea(pPage2->getFrameArea().SVRect()); { // Listen to StatePageNumber changes in view 2: SfxViewFrame& rFrame = pWrtShell2->GetView().GetViewFrame(); SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool(&rFrame); uno::Reference xParser(util::URLTransformer::create(m_xContext)); util::URL aCommandURL; aCommandURL.Complete = ".uno:StatePageNumber"; xParser->parseStrict(aCommandURL); const SfxSlot* pSlot = rSlotPool.GetUnoSlot(aCommandURL.Path); rFrame.GetBindings().GetDispatch(pSlot, aCommandURL, false); } aView2.m_aStateChanges.clear(); // When deleting a character in view 2 and processing jobs with view 1 set to active: pWrtShell2->DelLeft(); SfxLokHelper::setView(nView1); pWrtShell2->GetView().GetViewFrame().GetBindings().GetTimer().Invoke(); // Once more to hit the pImpl->bMsgDirty = false case in SfxBindings::NextJob_Impl(). pWrtShell2->GetView().GetViewFrame().GetBindings().GetTimer().Invoke(); // Then make sure the page number in view 2 is correct: // FIXME this should not happen, but it does from time to time. if (aView2.m_aStateChanges.empty()) { return; } CPPUNIT_ASSERT_EQUAL(static_cast(1), aView2.m_aStateChanges.size()); // Without the accompanying fix in place, this test would have failed with: // - Expected: .uno:StatePageNumber=Page 2 of 2 // - Actual : .uno:StatePageNumber=Page 1 of 2 // 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: createDoc("numrules.odt"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell()); 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, {}); m_aInvalidations = tools::Rectangle(); 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(!m_bFullInvalidateSeen); SwRootFrame* pLayout = pWrtShell->GetLayout(); SwFrame* pPage1 = pLayout->GetLower(); CPPUNIT_ASSERT(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(!m_aInvalidations.Overlaps(pPage2->getFrameArea().SVRect())); SwFrame* pPage3 = pPage2->GetNext(); CPPUNIT_ASSERT(!m_aInvalidations.Overlaps(pPage3->getFrameArea().SVRect())); } CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testPasteInvalidateNumRulesBullet) { // Given a document with 3 pages: first page is ~empty, then page break, then pages 2 & 3 have // bullets: createDoc("numrules.odt"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell()); 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, {}); dispatchCommand(mxComponent, u".uno:DefaultBullet"_ustr, {}); m_aInvalidations = tools::Rectangle(); m_bFullInvalidateSeen = false; // When pasting at the end of page 1, in a paragraph that is a bullet (a list, but not a // numbering): dispatchCommand(mxComponent, u".uno:PasteUnformatted"_ustr, {}); // Then make sure we only invalidate page 1, not page 2 or page 3: CPPUNIT_ASSERT(!m_bFullInvalidateSeen); SwRootFrame* pLayout = pWrtShell->GetLayout(); SwFrame* pPage1 = pLayout->GetLower(); CPPUNIT_ASSERT(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(!m_aInvalidations.Overlaps(pPage2->getFrameArea().SVRect())); SwFrame* pPage3 = pPage2->GetNext(); CPPUNIT_ASSERT(!m_aInvalidations.Overlaps(pPage3->getFrameArea().SVRect())); } CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAsyncLayout) { // Given a document with 3 pages, the first page is visible: createDoc(); ViewCallback aView; SwDocShell* pDocShell = getSwDocShell(); SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); pWrtShell->InsertPageBreak(); pWrtShell->InsertPageBreak(); SwRootFrame* pLayout = pWrtShell->GetLayout(); SwPageFrame* pPage1 = pLayout->GetLower()->DynCastPageFrame(); pWrtShell->setLOKVisibleArea(pPage1->getFrameArea().SVRect()); // When all pages get invalidated: pWrtShell->StartAllAction(); pPage1->InvalidateContent(); SwPageFrame* pPage2 = pPage1->GetNext()->DynCastPageFrame(); pPage2->InvalidateContent(); SwPageFrame* pPage3 = pPage2->GetNext()->DynCastPageFrame(); pPage3->InvalidateContent(); pWrtShell->EndAllAction(); // Then make sure only the first page gets a synchronous layout: CPPUNIT_ASSERT(!pPage1->IsInvalidContent()); CPPUNIT_ASSERT(pPage2->IsInvalidContent()); CPPUNIT_ASSERT(pPage3->IsInvalidContent()); // And then processing all idle events: Scheduler::ProcessEventsToIdle(); // Then make sure all pages get an async layout: CPPUNIT_ASSERT(!pPage1->IsInvalidContent()); CPPUNIT_ASSERT(!pPage2->IsInvalidContent()); CPPUNIT_ASSERT(!pPage3->IsInvalidContent()); } CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAnyInput) { // Given a document with 3 pages, the first page is visible: createDoc(); ViewCallback aView; SwDocShell* pDocShell = getSwDocShell(); SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); pWrtShell->InsertPageBreak(); pWrtShell->InsertPageBreak(); SwRootFrame* pLayout = pWrtShell->GetLayout(); SwPageFrame* pPage1 = pLayout->GetLower()->DynCastPageFrame(); pWrtShell->setLOKVisibleArea(pPage1->getFrameArea().SVRect()); // When all pages get invalidated: pWrtShell->StartAllAction(); pPage1->InvalidateContent(); SwPageFrame* pPage2 = pPage1->GetNext()->DynCastPageFrame(); pPage2->InvalidateContent(); SwPageFrame* pPage3 = pPage2->GetNext()->DynCastPageFrame(); pPage3->InvalidateContent(); pWrtShell->EndAllAction(); // Then make sure sync layout calculates page 1: CPPUNIT_ASSERT(!pPage1->IsInvalidContent()); CPPUNIT_ASSERT(pPage2->IsInvalidContent()); CPPUNIT_ASSERT(pPage3->IsInvalidContent()); // And when doing one idle layout: AnyInputCallback aAnyInput; pWrtShell->LayoutIdle(); // Then make sure async layout calculates page 2: CPPUNIT_ASSERT(!pPage1->IsInvalidContent()); CPPUNIT_ASSERT(!pPage2->IsInvalidContent()); // Without the fix in place, async layout calculated all pages, even if there were pending input // events. CPPUNIT_ASSERT(pPage3->IsInvalidContent()); Scheduler::ProcessEventsToIdle(); } CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testSignatureState) { // Given a document with a signature where the digest matches: SwXTextDocument* pXTextDocument = createDoc("signed-doc.odt"); // When initializing tiled rendering with an author name: uno::Sequence aPropertyValues = { comphelper::makePropertyValue(".uno:Author", uno::Any(u"A"_ustr)) }; pXTextDocument->initializeForTiledRendering(aPropertyValues); SignatureState eState = getSwDocShell()->GetDocumentSignatureState(); // Then make sure the signature state is unchanged: // Without the accompanying fix in place, this test would have failed with: // - Expected: 4 (NOTVALIDATED) // - Actual : 3 (INVALID) // i.e. the doc was modified by the time the signature state was calculated. CPPUNIT_ASSERT_EQUAL(SignatureState::NOTVALIDATED, eState); } CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testFormatInsertStartList) { // Given a document containing a list where the text has a changed font SwXTextDocument* pXTextDocument = createDoc("format-insert-list.docx"); VclPtr pDocWindow = pXTextDocument->getDocWindow(); SwView* pView = dynamic_cast(SfxViewShell::Current()); assert(pView); // Insert a string at the beginning of a list item pDocWindow->PostExtTextInputEvent(VclEventId::ExtTextInput, u"a"_ustr); pDocWindow->PostExtTextInputEvent(VclEventId::EndExtTextInput, u""_ustr); Scheduler::ProcessEventsToIdle(); // The inserted text should have the same font as the rest std::unique_ptr pFontItem; pView->GetViewFrame().GetBindings().QueryState(SID_ATTR_CHAR_FONT, pFontItem); CPPUNIT_ASSERT(pFontItem); CPPUNIT_ASSERT_EQUAL(u"Calibri"_ustr, pFontItem->GetFamilyName()); // Without the accompanying fix in place, this test fails with: // - Expected: Calibri // - Actual : MS Sans Serif } } CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */