Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
10 : #include <swmodeltestbase.hxx>
11 : #include <LibreOfficeKit/LibreOfficeKitEnums.h>
12 : #include <comphelper/dispatchcommand.hxx>
13 : #include <comphelper/propertysequence.hxx>
14 : #include <comphelper/string.hxx>
15 : #include <svx/svdpage.hxx>
16 : #include <svx/svdview.hxx>
17 : #include <vcl/svapp.hxx>
18 : #include <crsskip.hxx>
19 : #include <drawdoc.hxx>
20 : #include <ndtxt.hxx>
21 : #include <wrtsh.hxx>
22 :
23 : static const char* DATA_DIRECTORY = "/sw/qa/extras/tiledrendering/data/";
24 :
25 : /// Testsuite for the SwXTextDocument methods implementing the vcl::ITiledRenderable interface.
26 22 : class SwTiledRenderingTest : public SwModelTestBase
27 : {
28 : public:
29 : SwTiledRenderingTest();
30 : void testRegisterCallback();
31 : void testPostKeyEvent();
32 : void testPostMouseEvent();
33 : void testSetTextSelection();
34 : void testSetGraphicSelection();
35 : void testResetSelection();
36 : void testSearch();
37 : void testSearchViewArea();
38 : void testSearchTextFrame();
39 : void testSearchTextFrameWrapAround();
40 : void testDocumentSizeChanged();
41 :
42 2 : CPPUNIT_TEST_SUITE(SwTiledRenderingTest);
43 1 : CPPUNIT_TEST(testRegisterCallback);
44 1 : CPPUNIT_TEST(testPostKeyEvent);
45 1 : CPPUNIT_TEST(testPostMouseEvent);
46 1 : CPPUNIT_TEST(testSetTextSelection);
47 1 : CPPUNIT_TEST(testSetGraphicSelection);
48 1 : CPPUNIT_TEST(testResetSelection);
49 1 : CPPUNIT_TEST(testSearch);
50 1 : CPPUNIT_TEST(testSearchViewArea);
51 1 : CPPUNIT_TEST(testSearchTextFrame);
52 1 : CPPUNIT_TEST(testSearchTextFrameWrapAround);
53 1 : CPPUNIT_TEST(testDocumentSizeChanged);
54 5 : CPPUNIT_TEST_SUITE_END();
55 :
56 : private:
57 : SwXTextDocument* createDoc(const char* pName);
58 : static void callback(int nType, const char* pPayload, void* pData);
59 : void callbackImpl(int nType, const char* pPayload);
60 : Rectangle m_aInvalidation;
61 : Size m_aDocumentSize;
62 : OString m_aTextSelection;
63 : bool m_bFound;
64 : };
65 :
66 11 : SwTiledRenderingTest::SwTiledRenderingTest()
67 11 : : m_bFound(true)
68 : {
69 11 : }
70 :
71 11 : SwXTextDocument* SwTiledRenderingTest::createDoc(const char* pName)
72 : {
73 11 : load(DATA_DIRECTORY, pName);
74 :
75 11 : SwXTextDocument* pTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
76 11 : CPPUNIT_ASSERT(pTextDocument);
77 11 : pTextDocument->initializeForTiledRendering();
78 11 : return pTextDocument;
79 : }
80 :
81 106 : void SwTiledRenderingTest::callback(int nType, const char* pPayload, void* pData)
82 : {
83 106 : static_cast<SwTiledRenderingTest*>(pData)->callbackImpl(nType, pPayload);
84 106 : }
85 :
86 106 : void SwTiledRenderingTest::callbackImpl(int nType, const char* pPayload)
87 : {
88 106 : switch (nType)
89 : {
90 : case LOK_CALLBACK_INVALIDATE_TILES:
91 : {
92 21 : if (m_aInvalidation.IsEmpty())
93 : {
94 5 : uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload));
95 5 : if (OString("EMPTY") == pPayload)
96 107 : return;
97 4 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), aSeq.getLength());
98 4 : m_aInvalidation.setX(aSeq[0].toInt32());
99 4 : m_aInvalidation.setY(aSeq[1].toInt32());
100 4 : m_aInvalidation.setWidth(aSeq[2].toInt32());
101 4 : m_aInvalidation.setHeight(aSeq[3].toInt32());
102 : }
103 : }
104 20 : break;
105 : case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
106 : {
107 1 : uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload));
108 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), aSeq.getLength());
109 1 : m_aDocumentSize.setWidth(aSeq[0].toInt32());
110 1 : m_aDocumentSize.setHeight(aSeq[1].toInt32());
111 : }
112 1 : break;
113 : case LOK_CALLBACK_TEXT_SELECTION:
114 : {
115 44 : m_aTextSelection = pPayload;
116 : }
117 44 : break;
118 : case LOK_CALLBACK_SEARCH_NOT_FOUND:
119 : {
120 0 : m_bFound = false;
121 : }
122 0 : break;
123 : }
124 : }
125 :
126 1 : void SwTiledRenderingTest::testRegisterCallback()
127 : {
128 : #ifdef MACOSX
129 : // For some reason this particular test requires window system access on OS X.
130 :
131 : // Without window system access, we do get a number of "<<<WARNING>>>
132 : // AquaSalGraphics::CheckContext() FAILED!!!!" [sic] and " <Warning>: CGSConnectionByID: 0 is
133 : // not a valid connection ID" warnings while running the other tests, too, but they still
134 : // succeed.
135 :
136 : if (!vcl::IsWindowSystemAvailable())
137 : return;
138 : #endif
139 :
140 1 : SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
141 1 : pXTextDocument->registerCallback(&SwTiledRenderingTest::callback, this);
142 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
143 : // Insert a character at the beginning of the document.
144 1 : pWrtShell->Insert("x");
145 :
146 : // Check that the top left 256x256px tile would be invalidated.
147 1 : CPPUNIT_ASSERT(!m_aInvalidation.IsEmpty());
148 : #if !defined(WNT) && !defined(MACOSX)
149 1 : Rectangle aTopLeft(0, 0, 256*15, 256*15); // 1 px = 15 twips, assuming 96 DPI.
150 : // FIXME - fails on Windows since about cbd48230bb3a90c4c485fa33123c6653234e02e9
151 : // [plus minus few commits maybe]
152 : // Also on OS X. But is tiled rendering even supposed to work on Windows and OS X?
153 1 : CPPUNIT_ASSERT(m_aInvalidation.IsOver(aTopLeft));
154 : #endif
155 1 : }
156 :
157 1 : void SwTiledRenderingTest::testPostKeyEvent()
158 : {
159 1 : SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
160 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
161 1 : pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
162 1 : SwShellCrsr* pShellCrsr = pWrtShell->getShellCrsr(false);
163 : // Did we manage to go after the first character?
164 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), pShellCrsr->GetPoint()->nContent.GetIndex());
165 :
166 1 : pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
167 1 : pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
168 : // Did we manage to insert the character after the first one?
169 1 : CPPUNIT_ASSERT_EQUAL(OUString("Axaa bbb."), pShellCrsr->GetPoint()->nNode.GetNode().GetTextNode()->GetText());
170 1 : }
171 :
172 1 : void SwTiledRenderingTest::testPostMouseEvent()
173 : {
174 1 : SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
175 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
176 1 : pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
177 1 : SwShellCrsr* pShellCrsr = pWrtShell->getShellCrsr(false);
178 : // Did we manage to go after the first character?
179 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), pShellCrsr->GetPoint()->nContent.GetIndex());
180 :
181 1 : Point aStart = pShellCrsr->GetSttPos();
182 1 : aStart.setX(aStart.getX() - 1000);
183 1 : pXTextDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, aStart.getX(), aStart.getY(), 1);
184 1 : pXTextDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, aStart.getX(), aStart.getY(), 1);
185 : // The new cursor position must be before the first word.
186 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), pShellCrsr->GetPoint()->nContent.GetIndex());
187 1 : }
188 :
189 1 : void SwTiledRenderingTest::testSetTextSelection()
190 : {
191 1 : SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
192 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
193 : // Move the cursor into the second word.
194 1 : pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 5, /*bBasicCall=*/false);
195 : // Create a selection by on the word.
196 1 : pWrtShell->SelWrd();
197 1 : SwShellCrsr* pShellCrsr = pWrtShell->getShellCrsr(false);
198 : // Did we indeed manage to select the second word?
199 1 : CPPUNIT_ASSERT_EQUAL(OUString("bbb"), pShellCrsr->GetText());
200 :
201 : // Now use setTextSelection() to move the start of the selection 1000 twips left.
202 1 : Point aStart = pShellCrsr->GetSttPos();
203 1 : aStart.setX(aStart.getX() - 1000);
204 1 : pXTextDocument->setTextSelection(LOK_SETTEXTSELECTION_START, aStart.getX(), aStart.getY());
205 : // The new selection must include the first word, too -- but not the ending dot.
206 1 : CPPUNIT_ASSERT_EQUAL(OUString("Aaa bbb"), pShellCrsr->GetText());
207 :
208 : // Next: test that LOK_SETTEXTSELECTION_RESET + LOK_SETTEXTSELECTION_END can be used to create a selection.
209 1 : pXTextDocument->setTextSelection(LOK_SETTEXTSELECTION_RESET, aStart.getX(), aStart.getY());
210 1 : pXTextDocument->setTextSelection(LOK_SETTEXTSELECTION_END, aStart.getX() + 1000, aStart.getY());
211 1 : CPPUNIT_ASSERT_EQUAL(OUString("Aaa b"), pShellCrsr->GetText());
212 1 : }
213 :
214 1 : void SwTiledRenderingTest::testSetGraphicSelection()
215 : {
216 1 : SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
217 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
218 1 : SdrPage* pPage = pWrtShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
219 1 : SdrObject* pObject = pPage->GetObj(0);
220 1 : pWrtShell->SelectObj(Point(), 0, pObject);
221 : // Make sure the rectangle has 8 handles: at each corner and at the center of each edge.
222 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(8), pObject->GetHdlCount());
223 : // Take the bottom center one.
224 1 : SdrHdl* pHdl = pObject->GetHdl(6);
225 1 : CPPUNIT_ASSERT_EQUAL(HDL_LOWER, pHdl->GetKind());
226 1 : Rectangle aShapeBefore = pObject->GetSnapRect();
227 : // Resize.
228 1 : pXTextDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_START, pHdl->GetPos().getX(), pHdl->GetPos().getY());
229 1 : pXTextDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_END, pHdl->GetPos().getX(), pHdl->GetPos().getY() + 1000);
230 1 : Rectangle aShapeAfter = pObject->GetSnapRect();
231 : // Check that a resize happened, but aspect ratio is not kept.
232 1 : CPPUNIT_ASSERT_EQUAL(aShapeBefore.getWidth(), aShapeAfter.getWidth());
233 : #if !defined(MACOSX) // FIXME
234 1 : CPPUNIT_ASSERT_EQUAL(aShapeBefore.getHeight() + 1000, aShapeAfter.getHeight());
235 : #endif
236 1 : }
237 :
238 1 : void SwTiledRenderingTest::testResetSelection()
239 : {
240 1 : SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
241 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
242 : // Select one character.
243 1 : pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
244 1 : SwShellCrsr* pShellCrsr = pWrtShell->getShellCrsr(false);
245 : // We have a text selection.
246 1 : CPPUNIT_ASSERT(pShellCrsr->HasMark());
247 :
248 1 : pXTextDocument->resetSelection();
249 : // We no longer have a text selection.
250 1 : CPPUNIT_ASSERT(!pShellCrsr->HasMark());
251 :
252 1 : SdrPage* pPage = pWrtShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
253 1 : SdrObject* pObject = pPage->GetObj(0);
254 1 : Point aPoint = pObject->GetSnapRect().Center();
255 : // Select the shape.
256 1 : pWrtShell->EnterSelFrmMode(&aPoint);
257 : // We have a graphic selection.
258 1 : CPPUNIT_ASSERT(pWrtShell->IsSelFrmMode());
259 :
260 1 : pXTextDocument->resetSelection();
261 : // We no longer have a graphic selection.
262 1 : CPPUNIT_ASSERT(!pWrtShell->IsSelFrmMode());
263 1 : }
264 :
265 : #if !(defined WNT || defined MACOSX)
266 7 : void lcl_search(bool bBackward)
267 : {
268 : uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
269 : {
270 : {"SearchItem.SearchString", uno::makeAny(OUString("shape"))},
271 : {"SearchItem.Backward", uno::makeAny(bBackward)}
272 7 : }));
273 7 : comphelper::dispatchCommand(".uno:ExecuteSearch", aPropertyValues);
274 7 : }
275 : #endif
276 :
277 1 : void SwTiledRenderingTest::testSearch()
278 : {
279 : #if !defined(WNT) && !defined(MACOSX)
280 1 : SwXTextDocument* pXTextDocument = createDoc("search.odt");
281 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
282 1 : size_t nNode = pWrtShell->getShellCrsr(false)->Start()->nNode.GetNode().GetIndex();
283 :
284 : // First hit, in the second paragraph, before the shape.
285 1 : lcl_search(false);
286 1 : CPPUNIT_ASSERT(!pWrtShell->GetDrawView()->GetTextEditObject());
287 1 : size_t nActual = pWrtShell->getShellCrsr(false)->Start()->nNode.GetNode().GetIndex();
288 1 : CPPUNIT_ASSERT_EQUAL(nNode + 1, nActual);
289 :
290 : // Next hit, in the shape.
291 1 : lcl_search(false);
292 1 : CPPUNIT_ASSERT(pWrtShell->GetDrawView()->GetTextEditObject());
293 :
294 : // Next hit, in the shape, still.
295 1 : lcl_search(false);
296 1 : CPPUNIT_ASSERT(pWrtShell->GetDrawView()->GetTextEditObject());
297 :
298 : // Last hit, in the last paragraph, after the shape.
299 1 : lcl_search(false);
300 1 : CPPUNIT_ASSERT(!pWrtShell->GetDrawView()->GetTextEditObject());
301 1 : nActual = pWrtShell->getShellCrsr(false)->Start()->nNode.GetNode().GetIndex();
302 1 : CPPUNIT_ASSERT_EQUAL(nNode + 7, nActual);
303 :
304 : // Now change direction and make sure that the first 2 hits are in the shape, but not the 3rd one.
305 1 : lcl_search(true);
306 1 : CPPUNIT_ASSERT(pWrtShell->GetDrawView()->GetTextEditObject());
307 1 : lcl_search(true);
308 1 : CPPUNIT_ASSERT(pWrtShell->GetDrawView()->GetTextEditObject());
309 1 : lcl_search(true);
310 1 : CPPUNIT_ASSERT(!pWrtShell->GetDrawView()->GetTextEditObject());
311 1 : nActual = pWrtShell->getShellCrsr(false)->Start()->nNode.GetNode().GetIndex();
312 1 : CPPUNIT_ASSERT_EQUAL(nNode + 1, nActual);
313 : #endif
314 1 : }
315 :
316 1 : void SwTiledRenderingTest::testSearchViewArea()
317 : {
318 : #if !defined(WNT) && !defined(MACOSX)
319 1 : SwXTextDocument* pXTextDocument = createDoc("search.odt");
320 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
321 : // Go to the second page, 1-based.
322 1 : pWrtShell->GotoPage(2, false);
323 1 : SwShellCrsr* pShellCrsr = pWrtShell->getShellCrsr(false);
324 : // Get the ~top left corner of the second page.
325 1 : Point aPoint = pShellCrsr->GetSttPos();
326 :
327 : // Go back to the first page, search while the cursor is there, but the
328 : // visible area is the second page.
329 1 : pWrtShell->GotoPage(1, false);
330 : uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
331 : {
332 : {"SearchItem.SearchString", uno::makeAny(OUString("Heading"))},
333 : {"SearchItem.Backward", uno::makeAny(false)},
334 1 : {"SearchItem.SearchStartPointX", uno::makeAny(static_cast<sal_Int32>(aPoint.getX()))},
335 1 : {"SearchItem.SearchStartPointY", uno::makeAny(static_cast<sal_Int32>(aPoint.getY()))}
336 3 : }));
337 1 : comphelper::dispatchCommand(".uno:ExecuteSearch", aPropertyValues);
338 : // This was just "Heading", i.e. SwView::SearchAndWrap() did not search from only the top of the second page.
339 1 : CPPUNIT_ASSERT_EQUAL(OUString("Heading on second page"), pShellCrsr->GetPoint()->nNode.GetNode().GetTextNode()->GetText());
340 : #endif
341 1 : }
342 :
343 1 : void SwTiledRenderingTest::testSearchTextFrame()
344 : {
345 : #if !defined(WNT) && !defined(MACOSX)
346 1 : SwXTextDocument* pXTextDocument = createDoc("search.odt");
347 1 : pXTextDocument->registerCallback(&SwTiledRenderingTest::callback, this);
348 : uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
349 : {
350 : {"SearchItem.SearchString", uno::makeAny(OUString("TextFrame"))},
351 : {"SearchItem.Backward", uno::makeAny(false)},
352 1 : }));
353 1 : comphelper::dispatchCommand(".uno:ExecuteSearch", aPropertyValues);
354 : // This was empty: nothing was highlighted after searching for 'TextFrame'.
355 1 : CPPUNIT_ASSERT(!m_aTextSelection.isEmpty());
356 : #endif
357 1 : }
358 :
359 1 : void SwTiledRenderingTest::testSearchTextFrameWrapAround()
360 : {
361 : #if !defined(WNT) && !defined(MACOSX)
362 1 : SwXTextDocument* pXTextDocument = createDoc("search.odt");
363 1 : pXTextDocument->registerCallback(&SwTiledRenderingTest::callback, this);
364 : uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
365 : {
366 : {"SearchItem.SearchString", uno::makeAny(OUString("TextFrame"))},
367 : {"SearchItem.Backward", uno::makeAny(false)},
368 1 : }));
369 1 : comphelper::dispatchCommand(".uno:ExecuteSearch", aPropertyValues);
370 1 : CPPUNIT_ASSERT(m_bFound);
371 1 : comphelper::dispatchCommand(".uno:ExecuteSearch", aPropertyValues);
372 : // This failed, i.e. the second time 'not found' was reported, instead of wrapping around.
373 1 : CPPUNIT_ASSERT(m_bFound);
374 : #endif
375 1 : }
376 :
377 1 : void SwTiledRenderingTest::testDocumentSizeChanged()
378 : {
379 : #if !defined(WNT) && !defined(MACOSX)
380 : // Get the current document size.
381 1 : SwXTextDocument* pXTextDocument = createDoc("2-pages.odt");
382 1 : pXTextDocument->registerCallback(&SwTiledRenderingTest::callback, this);
383 1 : SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
384 1 : pXTextDocument->initializeForTiledRendering();
385 1 : Size aSize = pXTextDocument->getDocumentSize();
386 :
387 : // Delete the second page and see how the size changes.
388 1 : pWrtShell->Down(false);
389 1 : pWrtShell->DelLeft();
390 : // Document width should not change, this was 0.
391 1 : CPPUNIT_ASSERT_EQUAL(aSize.getWidth(), m_aDocumentSize.getWidth());
392 : // Document height should be smaller now.
393 1 : CPPUNIT_ASSERT(aSize.getHeight() > m_aDocumentSize.getHeight());
394 : #endif
395 1 : }
396 :
397 1 : CPPUNIT_TEST_SUITE_REGISTRATION(SwTiledRenderingTest);
398 :
399 4 : CPPUNIT_PLUGIN_IMPLEMENT();
400 :
401 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|