delay, collect and compress LOK invalidations for Writer views
[LibreOffice.git] / sw / qa / core / txtnode / txtnode.cxx
blob49472c25cecd83391ff1f35ddd8e22feaa96b468
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <swmodeltestbase.hxx>
12 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
13 #include <comphelper/lok.hxx>
14 #include <sfx2/viewsh.hxx>
15 #include <sfx2/lokcallback.hxx>
16 #include <vcl/gdimtf.hxx>
17 #include <vcl/scheduler.hxx>
19 #include <IDocumentStatistics.hxx>
20 #include <fmtanchr.hxx>
21 #include <frameformats.hxx>
22 #include <wrtsh.hxx>
23 #include <unotxdoc.hxx>
24 #include <docsh.hxx>
26 constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/txtnode/data/";
28 /// Covers sw/source/core/txtnode/ fixes.
29 class SwCoreTxtnodeTest : public SwModelTestBase
33 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testBtlrCellChinese)
35 // Load a document with a table cell, with btlr cell direction. The cell has text which is
36 // classified as vertical, i.e. the glyph has the same direction in both the lrtb ("Latin") and
37 // tbrl ("Chinese") directions. Make sure that Chinese text is handled the same way in the btlr
38 // case as it's handled in the Latin case.
39 load(DATA_DIRECTORY, "btlr-cell-chinese.doc");
40 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
41 SwDocShell* pShell = pTextDoc->GetDocShell();
42 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
43 MetafileXmlDump dumper;
44 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
45 assertXPath(pXmlDoc, "//font[1]", "orientation", "900");
46 // Without the accompanying fix in place, this test would have failed with:
47 // - Expected: false
48 // - Actual : true
49 // i.e. the glyph was rotated further, so it was upside down.
50 assertXPath(pXmlDoc, "//font[1]", "vertical", "false");
53 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTextBoxCopyAnchor)
55 load(DATA_DIRECTORY, "textbox-copy-anchor.docx");
56 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
57 SwDocShell* pShell = pTextDoc->GetDocShell();
58 SwWrtShell* pWrtShell = pShell->GetWrtShell();
59 SwDoc aClipboard;
60 pWrtShell->SelAll();
61 pWrtShell->Copy(aClipboard);
62 pWrtShell->SttEndDoc(/*bStart=*/false);
63 pWrtShell->Paste(aClipboard);
65 const SwFrameFormats& rFormats = *pShell->GetDoc()->GetSpzFrameFormats();
66 // Without the accompanying fix in place, this test would have failed with:
67 // - Expected: 4
68 // - Actual : 6
69 // i.e. 2 fly frames were copied twice.
70 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rFormats.size());
72 SwPosition aDrawAnchor1 = *rFormats[0]->GetAnchor().GetContentAnchor();
73 SwPosition aFlyAnchor1 = *rFormats[1]->GetAnchor().GetContentAnchor();
74 CPPUNIT_ASSERT_EQUAL(aFlyAnchor1.nNode, aDrawAnchor1.nNode);
75 SwPosition aDrawAnchor2 = *rFormats[2]->GetAnchor().GetContentAnchor();
76 SwPosition aFlyAnchor2 = *rFormats[3]->GetAnchor().GetContentAnchor();
77 // This also failed, aFlyAnchor2 was wrong, as it got out of sync with aDrawAnchor2.
78 CPPUNIT_ASSERT_EQUAL(aFlyAnchor2.nNode, aDrawAnchor2.nNode);
81 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTextBoxNodeSplit)
83 load(DATA_DIRECTORY, "textbox-node-split.docx");
84 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
85 SwDocShell* pShell = pTextDoc->GetDocShell();
86 SwWrtShell* pWrtShell = pShell->GetWrtShell();
87 pWrtShell->SttEndDoc(/*bStart=*/false);
88 // Without the accompanying fix in place, this would have crashed in
89 // SwFlyAtContentFrame::SwClientNotify().
90 pWrtShell->SplitNode();
93 namespace
95 struct ViewCallback : public SfxLokCallbackInterface
97 int m_nInvalidations = 0;
99 virtual void libreOfficeKitViewCallback(int, const char*) override {}
100 virtual void libreOfficeKitViewCallback(int, const char*, int) override {}
101 virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle*, int) override
103 ++m_nInvalidations;
108 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTitleFieldInvalidate)
110 // Set up LOK to track invalidations.
111 comphelper::LibreOfficeKit::setActive(true);
113 // Given a document with a title field:
114 load(DATA_DIRECTORY, "title-field-invalidate.fodt");
115 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
116 pTextDoc->initializeForTiledRendering({});
117 SwDocShell* pShell = pTextDoc->GetDocShell();
118 SwDoc* pDoc = pShell->GetDoc();
119 SwWrtShell* pWrtShell = pShell->GetWrtShell();
120 pWrtShell->SttEndDoc(/*bStt=*/false);
121 ViewCallback aCallback;
122 pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&aCallback);
123 Scheduler::ProcessEventsToIdle();
124 aCallback.m_nInvalidations = 0;
126 // When typing to the document:
127 pWrtShell->Insert("x");
128 pWrtShell->GetSfxViewShell()->flushPendingLOKInvalidateTiles();
130 // Then make sure that only the text frame at the cursor is invalidated:
131 pDoc->getIDocumentStatistics().GetUpdatedDocStat(/*bCompleteAsync=*/true, /*bFields=*/false);
132 // Without the accompanying fix in place, this test would have failed with:
133 // - Expected: 1
134 // - Actual : 2
135 // i.e. the footer was also invalidated on each keypress.
136 CPPUNIT_ASSERT_EQUAL(1, aCallback.m_nInvalidations);
138 // Tear down LOK.
139 pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(nullptr);
140 mxComponent->dispose();
141 mxComponent.clear();
142 comphelper::LibreOfficeKit::setActive(false);
145 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testFlyAnchorUndo)
147 // Given a document with a fly frame, anchored after the last char of the document:
148 load(DATA_DIRECTORY, "fly-anchor-undo.odt");
149 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
150 SwDocShell* pShell = pTextDoc->GetDocShell();
151 SwDoc* pDoc = pShell->GetDoc();
152 const SwFrameFormats& rSpz = *pDoc->GetSpzFrameFormats();
153 sal_Int32 nExpected = rSpz[0]->GetAnchor().GetContentAnchor()->nContent.GetIndex();
155 // When deleting that last character and undoing it:
156 SwWrtShell* pWrtShell = pShell->GetWrtShell();
157 pWrtShell->SttEndDoc(/*bStt=*/false);
158 pWrtShell->DelLeft();
159 pWrtShell->Undo();
161 // Then make sure the anchor position after the undo is the same as the original:
162 sal_Int32 nActual = rSpz[0]->GetAnchor().GetContentAnchor()->nContent.GetIndex();
163 // Without the accompanying fix in place, this test would have failed with:
164 // - Expected: 3
165 // - Actual : 2
166 // i.e. the anchor position was left unchanged by the undo.
167 CPPUNIT_ASSERT_EQUAL(nExpected, nActual);
170 CPPUNIT_PLUGIN_IMPLEMENT();
172 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */