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 :
11 : #include <cppunit/extensions/HelperMacros.h>
12 : #include "cppunit/plugin/TestPlugIn.h"
13 :
14 : #include <svtools/grfmgr.hxx>
15 :
16 : #include <test/bootstrapfixture.hxx>
17 :
18 : #include <tools/stream.hxx>
19 :
20 : #include <vcl/image.hxx>
21 :
22 : #include <com/sun/star/frame/Desktop.hpp>
23 : #include <officecfg/Office/Common.hxx>
24 : #include <unotest/macros_test.hxx>
25 : #include <comphelper/processfactory.hxx>
26 : #include <unotxdoc.hxx>
27 : #include <docsh.hxx>
28 : #include <doc.hxx>
29 : #include <ndgrf.hxx>
30 : #include <boost/shared_ptr.hpp>
31 :
32 : using namespace css;
33 :
34 : namespace
35 : {
36 :
37 12 : class GraphicObjectTest: public test::BootstrapFixture, public unotest::MacrosTest
38 : {
39 :
40 : public:
41 : void testSwap();
42 : void testSizeBasedAutoSwap();
43 : void testTdf88836();
44 : void testTdf88935();
45 :
46 :
47 4 : virtual void setUp() SAL_OVERRIDE
48 : {
49 4 : test::BootstrapFixture::setUp();
50 :
51 4 : mxDesktop.set(css::frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory())));
52 4 : }
53 :
54 : private:
55 : DECL_LINK(getLinkStream, GraphicObject*);
56 :
57 : private:
58 2 : CPPUNIT_TEST_SUITE(GraphicObjectTest);
59 1 : CPPUNIT_TEST(testSwap);
60 1 : CPPUNIT_TEST(testSizeBasedAutoSwap);
61 1 : CPPUNIT_TEST(testTdf88836);
62 1 : CPPUNIT_TEST(testTdf88935);
63 5 : CPPUNIT_TEST_SUITE_END();
64 : };
65 :
66 : static const char aGraphicFile[] = "/svtools/qa/unit/data/graphic.png";
67 : static const sal_uLong nGraphicSizeBytes = 4800;
68 :
69 3 : const Graphic lcl_loadGraphic(const rtl::OUString &rUrl)
70 : {
71 3 : const Image aImage(rUrl);
72 3 : return Graphic(aImage.GetBitmapEx());
73 : }
74 :
75 0 : IMPL_LINK(GraphicObjectTest, getLinkStream, GraphicObject*, /*pGraphObj*/)
76 : {
77 0 : return reinterpret_cast<sal_IntPtr>(GRFMGR_AUTOSWAPSTREAM_LINK);
78 : }
79 :
80 1 : void GraphicObjectTest::testSwap()
81 : {
82 : // simple non-linked case
83 : {
84 1 : GraphicObject aGraphObj(lcl_loadGraphic(getURLFromSrc(aGraphicFile)));
85 1 : CPPUNIT_ASSERT(!aGraphObj.HasSwapStreamHdl());
86 1 : CPPUNIT_ASSERT(!aGraphObj.IsSwappedOut());
87 1 : CPPUNIT_ASSERT_EQUAL(nGraphicSizeBytes, aGraphObj.GetGraphic().GetSizeBytes());
88 : // swap out
89 1 : CPPUNIT_ASSERT(aGraphObj.SwapOut());
90 1 : CPPUNIT_ASSERT(aGraphObj.IsSwappedOut());
91 : // swap in
92 1 : CPPUNIT_ASSERT(aGraphObj.SwapIn());
93 1 : CPPUNIT_ASSERT(!aGraphObj.IsSwappedOut());
94 : // the data are still there
95 1 : CPPUNIT_ASSERT_EQUAL(nGraphicSizeBytes, aGraphObj.GetGraphic().GetSizeBytes());
96 : }
97 :
98 : // linked case
99 : {
100 1 : GraphicObject aGraphObj(lcl_loadGraphic(getURLFromSrc(aGraphicFile)));
101 1 : aGraphObj.SetSwapStreamHdl(LINK(this, GraphicObjectTest, getLinkStream));
102 :
103 1 : CPPUNIT_ASSERT(aGraphObj.HasSwapStreamHdl());
104 1 : CPPUNIT_ASSERT(!aGraphObj.IsSwappedOut());
105 1 : CPPUNIT_ASSERT_EQUAL(nGraphicSizeBytes, aGraphObj.GetGraphic().GetSizeBytes());
106 : // swap out
107 1 : CPPUNIT_ASSERT(aGraphObj.SwapOut());
108 1 : CPPUNIT_ASSERT(aGraphObj.IsSwappedOut());
109 : // swap in
110 1 : CPPUNIT_ASSERT(aGraphObj.SwapIn());
111 1 : CPPUNIT_ASSERT(!aGraphObj.IsSwappedOut());
112 : // the data are still there
113 1 : CPPUNIT_ASSERT_EQUAL(nGraphicSizeBytes, aGraphObj.GetGraphic().GetSizeBytes());
114 : }
115 :
116 : // combination of two GraphicObjects
117 : {
118 1 : GraphicObject aGraphObj(lcl_loadGraphic(getURLFromSrc(aGraphicFile)));
119 :
120 2 : GraphicObject aGraphObj2(aGraphObj);
121 1 : aGraphObj2.SetSwapStreamHdl(LINK(this, GraphicObjectTest, getLinkStream));
122 :
123 1 : CPPUNIT_ASSERT(!aGraphObj.IsSwappedOut());
124 1 : CPPUNIT_ASSERT(!aGraphObj2.IsSwappedOut());
125 1 : CPPUNIT_ASSERT_EQUAL(nGraphicSizeBytes, aGraphObj.GetGraphic().GetSizeBytes());
126 1 : CPPUNIT_ASSERT_EQUAL(nGraphicSizeBytes, aGraphObj2.GetGraphic().GetSizeBytes());
127 :
128 : // GraphicObjects never share the same Graphic. A new one is created as one step during
129 : // registration of the GraphicObject at GraphicManager.
130 :
131 : // swap out
132 1 : CPPUNIT_ASSERT(aGraphObj.SwapOut());
133 1 : CPPUNIT_ASSERT(aGraphObj.IsSwappedOut());
134 1 : CPPUNIT_ASSERT(!aGraphObj2.IsSwappedOut());
135 1 : CPPUNIT_ASSERT(aGraphObj2.SwapOut());
136 1 : CPPUNIT_ASSERT(aGraphObj2.IsSwappedOut());
137 : // swap in
138 1 : CPPUNIT_ASSERT(aGraphObj2.SwapIn());
139 1 : CPPUNIT_ASSERT(!aGraphObj2.IsSwappedOut());
140 1 : CPPUNIT_ASSERT(aGraphObj.IsSwappedOut());
141 1 : CPPUNIT_ASSERT(aGraphObj.SwapIn());
142 1 : CPPUNIT_ASSERT(!aGraphObj.IsSwappedOut());
143 : // the data are still there
144 1 : CPPUNIT_ASSERT_EQUAL(nGraphicSizeBytes, aGraphObj.GetGraphic().GetSizeBytes());
145 2 : CPPUNIT_ASSERT_EQUAL(nGraphicSizeBytes, aGraphObj2.GetGraphic().GetSizeBytes());
146 : }
147 1 : }
148 :
149 1 : void GraphicObjectTest::testSizeBasedAutoSwap()
150 : {
151 : // Set cache size to a very small value to check what happens
152 : {
153 1 : std::shared_ptr< comphelper::ConfigurationChanges > aBatch(comphelper::ConfigurationChanges::create());
154 1 : officecfg::Office::Common::Cache::GraphicManager::TotalCacheSize::set(sal_Int32(1), aBatch);
155 1 : aBatch->commit();
156 : }
157 :
158 : uno::Reference< lang::XComponent > xComponent =
159 1 : loadFromDesktop(getURLFromSrc("svtools/qa/unit/data/document_with_two_images.odt"), "com.sun.star.text.TextDocument");
160 :
161 1 : SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument *>(xComponent.get());
162 1 : CPPUNIT_ASSERT(pTxtDoc);
163 1 : SwDoc* pDoc = pTxtDoc->GetDocShell()->GetDoc();
164 1 : CPPUNIT_ASSERT(pDoc);
165 1 : SwNodes& aNodes = pDoc->GetNodes();
166 :
167 : // Find images
168 1 : const GraphicObject* pGrafObj1 = 0;
169 1 : const GraphicObject* pGrafObj2 = 0;
170 19 : for( sal_uLong nIndex = 0; nIndex < aNodes.Count(); ++nIndex)
171 : {
172 18 : if( aNodes[nIndex]->IsGrfNode() )
173 : {
174 2 : SwGrfNode* pGrfNode = aNodes[nIndex]->GetGrfNode();
175 2 : CPPUNIT_ASSERT(pGrfNode);
176 2 : if( !pGrafObj1 )
177 : {
178 1 : pGrafObj1 = &pGrfNode->GetGrfObj();
179 : }
180 : else
181 : {
182 1 : pGrafObj2 = &pGrfNode->GetGrfObj();
183 : }
184 : }
185 : }
186 1 : CPPUNIT_ASSERT_MESSAGE("Missing image", pGrafObj1 != 0 && pGrafObj2 != 0);
187 :
188 : {
189 : // First image should be swapped out
190 1 : CPPUNIT_ASSERT(pGrafObj1->IsSwappedOut());
191 1 : CPPUNIT_ASSERT_EQUAL(sal_uLong(697230), pGrafObj1->GetSizeBytes());
192 :
193 : // Still swapped out: size is cached
194 1 : CPPUNIT_ASSERT(pGrafObj1->IsSwappedOut());
195 : }
196 :
197 : {
198 : // Second image should be in the memory
199 : // Size based swap out is triggered by swap in, so the last swapped in image should be
200 : // in the memory despite of size limit is reached.
201 1 : CPPUNIT_ASSERT(!pGrafObj2->IsSwappedOut());
202 1 : CPPUNIT_ASSERT_EQUAL(sal_uLong(1620000), pGrafObj2->GetSizeBytes());
203 : }
204 :
205 : // Swap in first image -> second image will be swapped out
206 : {
207 1 : pGrafObj1->GetGraphic(); // GetGraphic calls swap in on a const object
208 1 : CPPUNIT_ASSERT(!pGrafObj1->IsSwappedOut());
209 1 : CPPUNIT_ASSERT(pGrafObj2->IsSwappedOut());
210 : }
211 :
212 : // Swap in second image -> first image will be swapped out
213 : {
214 1 : pGrafObj2->GetGraphic(); // GetGraphic calls swap in on a const object
215 1 : CPPUNIT_ASSERT(!pGrafObj2->IsSwappedOut());
216 1 : CPPUNIT_ASSERT(pGrafObj1->IsSwappedOut());
217 : }
218 :
219 : // Use bigger cache
220 : {
221 1 : GraphicManager& rGrfMgr = pGrafObj1->GetGraphicManager();
222 1 : rGrfMgr.SetMaxCacheSize((pGrafObj1->GetSizeBytes()+pGrafObj2->GetSizeBytes())*10);
223 : }
224 : // Swap in both images -> both should be swapped in
225 : {
226 1 : pGrafObj1->GetGraphic();
227 1 : pGrafObj2->GetGraphic();
228 1 : CPPUNIT_ASSERT(!pGrafObj1->IsSwappedOut());
229 1 : CPPUNIT_ASSERT(!pGrafObj2->IsSwappedOut());
230 : }
231 :
232 1 : xComponent->dispose();
233 1 : }
234 :
235 1 : void GraphicObjectTest::testTdf88836()
236 : {
237 : // Construction with empty bitmap -> type should be GRAPHIC_NONE
238 1 : Graphic aGraphic = Bitmap();
239 1 : CPPUNIT_ASSERT_EQUAL(GRAPHIC_NONE, aGraphic.GetType());
240 1 : aGraphic = Graphic(BitmapEx());
241 1 : CPPUNIT_ASSERT_EQUAL(GRAPHIC_NONE, aGraphic.GetType());
242 1 : }
243 :
244 1 : void GraphicObjectTest::testTdf88935()
245 : {
246 : // Cache size was not updated by deletion of graphic objects
247 :
248 : // Load a file with two images
249 : uno::Reference< lang::XComponent > xComponent =
250 1 : loadFromDesktop(getURLFromSrc("svtools/qa/unit/data/document_with_two_images.odt"), "com.sun.star.text.TextDocument");
251 1 : SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument *>(xComponent.get());
252 1 : CPPUNIT_ASSERT(pTxtDoc);
253 1 : SwDoc* pDoc = pTxtDoc->GetDocShell()->GetDoc();
254 1 : CPPUNIT_ASSERT(pDoc);
255 1 : SwNodes& aNodes = pDoc->GetNodes();
256 :
257 : // Find images
258 1 : const GraphicObject* pGraphObj1 = 0;
259 1 : const GraphicObject* pGraphObj2 = 0;
260 19 : for( sal_uLong nIndex = 0; nIndex < aNodes.Count(); ++nIndex)
261 : {
262 18 : if( aNodes[nIndex]->IsGrfNode() )
263 : {
264 2 : SwGrfNode* pGrfNode = aNodes[nIndex]->GetGrfNode();
265 2 : CPPUNIT_ASSERT(pGrfNode);
266 2 : if( !pGraphObj1 )
267 : {
268 1 : pGraphObj1 = &pGrfNode->GetGrfObj();
269 : }
270 : else
271 : {
272 1 : pGraphObj2 = &pGrfNode->GetGrfObj();
273 : }
274 : }
275 : }
276 1 : CPPUNIT_ASSERT_MESSAGE("Missing image", pGraphObj1 != 0 && pGraphObj2 != 0);
277 :
278 : // Set cache size
279 : {
280 1 : GraphicManager& rGrfMgr = pGraphObj1->GetGraphicManager();
281 1 : rGrfMgr.SetMaxCacheSize((pGraphObj1->GetSizeBytes()+pGraphObj2->GetSizeBytes())*10);
282 : }
283 :
284 : // Both images fit into the cache
285 : {
286 1 : pGraphObj1->GetGraphic();
287 1 : pGraphObj2->GetGraphic();
288 1 : CPPUNIT_ASSERT(!pGraphObj1->IsSwappedOut());
289 1 : CPPUNIT_ASSERT(!pGraphObj2->IsSwappedOut());
290 : }
291 :
292 : // Create and remove some copy of the first image
293 51 : for( int i = 0; i < 50; ++i )
294 : {
295 50 : GraphicObject aGraphObj3(*pGraphObj1, &pGraphObj1->GetGraphicManager());
296 50 : CPPUNIT_ASSERT(aGraphObj3.SwapOut());
297 50 : CPPUNIT_ASSERT(aGraphObj3.SwapIn());
298 50 : }
299 :
300 : // Both images fit into the cache
301 : {
302 1 : pGraphObj1->GetGraphic();
303 1 : pGraphObj2->GetGraphic();
304 1 : CPPUNIT_ASSERT(!pGraphObj1->IsSwappedOut());
305 1 : CPPUNIT_ASSERT(!pGraphObj2->IsSwappedOut());
306 : }
307 :
308 1 : xComponent->dispose();
309 1 : }
310 :
311 1 : CPPUNIT_TEST_SUITE_REGISTRATION(GraphicObjectTest);
312 :
313 : }
314 :
315 4 : CPPUNIT_PLUGIN_IMPLEMENT();
316 :
317 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|