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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <salhelper/timer.hxx>
21 : #include <svtools/grfmgr.hxx>
22 : #include <tools/debug.hxx>
23 : #include <vcl/metaact.hxx>
24 : #include <vcl/outdev.hxx>
25 : #include <tools/poly.hxx>
26 : #include <rtl/strbuf.hxx>
27 : #include "grfcache.hxx"
28 : #include <rtl/crc.h>
29 : #include <memory>
30 :
31 : #define RELEASE_TIMEOUT 10000
32 : #define MAX_BMP_EXTENT 4096
33 :
34 : static const char aHexData[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
35 :
36 : class GraphicID
37 : {
38 : private:
39 :
40 : sal_uInt32 mnID1;
41 : sal_uInt32 mnID2;
42 : sal_uInt32 mnID3;
43 : sal_uInt32 mnID4;
44 :
45 : GraphicID();
46 :
47 : public:
48 :
49 :
50 : GraphicID( const GraphicObject& rObj );
51 3964 : ~GraphicID() {}
52 :
53 2245 : sal_Bool operator==( const GraphicID& rID ) const
54 : {
55 4104 : return( rID.mnID1 == mnID1 && rID.mnID2 == mnID2 &&
56 3804 : rID.mnID3 == mnID3 && rID.mnID4 == mnID4 );
57 : }
58 :
59 : OString GetIDString() const;
60 451 : sal_Bool IsEmpty() const { return( 0 == mnID4 ); }
61 : };
62 :
63 4040 : GraphicID::GraphicID( const GraphicObject& rObj )
64 : {
65 4040 : const Graphic& rGraphic = rObj.GetGraphic();
66 :
67 4040 : mnID1 = ( (sal_uLong) rGraphic.GetType() ) << 28;
68 :
69 4040 : switch( rGraphic.GetType() )
70 : {
71 : case( GRAPHIC_BITMAP ):
72 : {
73 511 : if(rGraphic.getSvgData().get())
74 : {
75 0 : const SvgDataPtr& rSvgDataPtr = rGraphic.getSvgData();
76 0 : const basegfx::B2DRange& rRange = rSvgDataPtr->getRange();
77 :
78 0 : mnID1 |= rSvgDataPtr->getSvgDataArrayLength();
79 0 : mnID2 = basegfx::fround(rRange.getWidth());
80 0 : mnID3 = basegfx::fround(rRange.getHeight());
81 0 : mnID4 = rtl_crc32(0, rSvgDataPtr->getSvgDataArray().get(), rSvgDataPtr->getSvgDataArrayLength());
82 : }
83 511 : else if( rGraphic.IsAnimated() )
84 : {
85 0 : const Animation aAnimation( rGraphic.GetAnimation() );
86 :
87 0 : mnID1 |= ( aAnimation.Count() & 0x0fffffff );
88 0 : mnID2 = aAnimation.GetDisplaySizePixel().Width();
89 0 : mnID3 = aAnimation.GetDisplaySizePixel().Height();
90 0 : mnID4 = rGraphic.GetChecksum();
91 : }
92 : else
93 : {
94 511 : const BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
95 :
96 511 : mnID1 |= ( ( ( (sal_uLong) aBmpEx.GetTransparentType() << 8 ) | ( aBmpEx.IsAlpha() ? 1 : 0 ) ) & 0x0fffffff );
97 511 : mnID2 = aBmpEx.GetSizePixel().Width();
98 511 : mnID3 = aBmpEx.GetSizePixel().Height();
99 511 : mnID4 = rGraphic.GetChecksum();
100 : }
101 : }
102 511 : break;
103 :
104 : case( GRAPHIC_GDIMETAFILE ):
105 : {
106 206 : const GDIMetaFile& rMtf = rGraphic.GetGDIMetaFile();
107 :
108 206 : mnID1 |= ( rMtf.GetActionSize() & 0x0fffffff );
109 206 : mnID2 = rMtf.GetPrefSize().Width();
110 206 : mnID3 = rMtf.GetPrefSize().Height();
111 206 : mnID4 = rGraphic.GetChecksum();
112 : }
113 206 : break;
114 :
115 : default:
116 3323 : mnID2 = mnID3 = mnID4 = 0;
117 3323 : break;
118 : }
119 4040 : }
120 :
121 4358 : OString GraphicID::GetIDString() const
122 : {
123 4358 : OStringBuffer aHexStr;
124 4358 : sal_Int32 nShift, nIndex = 0;
125 4358 : aHexStr.setLength(32);
126 :
127 39222 : for( nShift = 28; nShift >= 0; nShift -= 4 )
128 34864 : aHexStr[nIndex++] = aHexData[ ( mnID1 >> (sal_uInt32) nShift ) & 0xf ];
129 :
130 39222 : for( nShift = 28; nShift >= 0; nShift -= 4 )
131 34864 : aHexStr[nIndex++] = aHexData[ ( mnID2 >> (sal_uInt32) nShift ) & 0xf ];
132 :
133 39222 : for( nShift = 28; nShift >= 0; nShift -= 4 )
134 34864 : aHexStr[nIndex++] = aHexData[ ( mnID3 >> (sal_uInt32) nShift ) & 0xf ];
135 :
136 39222 : for( nShift = 28; nShift >= 0; nShift -= 4 )
137 34864 : aHexStr[nIndex++] = aHexData[ ( mnID4 >> (sal_uInt32) nShift ) & 0xf ];
138 :
139 4358 : return aHexStr.makeStringAndClear();
140 : }
141 :
142 : class GraphicCacheEntry
143 : {
144 : private:
145 :
146 : GraphicObjectList_impl maGraphicObjectList;
147 :
148 : GraphicID maID;
149 : GfxLink maGfxLink;
150 : BitmapEx* mpBmpEx;
151 : GDIMetaFile* mpMtf;
152 : Animation* mpAnimation;
153 : bool mbSwappedAll;
154 :
155 : // SvgData support
156 : SvgDataPtr maSvgData;
157 :
158 : bool ImplInit( const GraphicObject& rObj );
159 : bool ImplMatches( const GraphicObject& rObj ) const { return( GraphicID( rObj ) == maID ); }
160 : void ImplFillSubstitute( Graphic& rSubstitute );
161 :
162 : public:
163 :
164 : GraphicCacheEntry( const GraphicObject& rObj );
165 : ~GraphicCacheEntry();
166 :
167 7054 : const GraphicID& GetID() const { return maID; }
168 :
169 : void AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute );
170 : bool ReleaseGraphicObjectReference( const GraphicObject& rObj );
171 4879 : size_t GetGraphicObjectReferenceCount() { return maGraphicObjectList.size(); }
172 : bool HasGraphicObjectReference( const GraphicObject& rObj );
173 :
174 : void TryToSwapIn();
175 : void GraphicObjectWasSwappedOut( const GraphicObject& rObj );
176 : bool FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute );
177 : void GraphicObjectWasSwappedIn( const GraphicObject& rObj );
178 : };
179 :
180 3628 : GraphicCacheEntry::GraphicCacheEntry( const GraphicObject& rObj ) :
181 : maID ( rObj ),
182 : mpBmpEx ( NULL ),
183 : mpMtf ( NULL ),
184 : mpAnimation ( NULL ),
185 3628 : mbSwappedAll ( true )
186 : {
187 3628 : mbSwappedAll = !ImplInit( rObj );
188 3628 : maGraphicObjectList.push_back( (GraphicObject*)&rObj );
189 3628 : }
190 :
191 7104 : GraphicCacheEntry::~GraphicCacheEntry()
192 : {
193 : DBG_ASSERT(
194 : maGraphicObjectList.empty(),
195 : "GraphicCacheEntry::~GraphicCacheEntry(): Not all GraphicObjects are removed from this entry"
196 : );
197 :
198 3552 : delete mpBmpEx;
199 3552 : delete mpMtf;
200 3552 : delete mpAnimation;
201 3552 : }
202 :
203 3634 : bool GraphicCacheEntry::ImplInit( const GraphicObject& rObj )
204 : {
205 3634 : bool bRet = false;
206 :
207 3634 : if( !rObj.IsSwappedOut() )
208 : {
209 3634 : const Graphic& rGraphic = rObj.GetGraphic();
210 :
211 3634 : if( mpBmpEx )
212 0 : delete mpBmpEx, mpBmpEx = NULL;
213 :
214 3634 : if( mpMtf )
215 0 : delete mpMtf, mpMtf = NULL;
216 :
217 3634 : if( mpAnimation )
218 0 : delete mpAnimation, mpAnimation = NULL;
219 :
220 3634 : switch( rGraphic.GetType() )
221 : {
222 : case( GRAPHIC_BITMAP ):
223 : {
224 226 : if(rGraphic.getSvgData().get())
225 : {
226 0 : maSvgData = rGraphic.getSvgData();
227 : }
228 226 : else if( rGraphic.IsAnimated() )
229 : {
230 0 : mpAnimation = new Animation( rGraphic.GetAnimation() );
231 : }
232 : else
233 : {
234 226 : mpBmpEx = new BitmapEx( rGraphic.GetBitmapEx() );
235 : }
236 : }
237 226 : break;
238 :
239 : case( GRAPHIC_GDIMETAFILE ):
240 : {
241 94 : mpMtf = new GDIMetaFile( rGraphic.GetGDIMetaFile() );
242 : }
243 94 : break;
244 :
245 : default:
246 : DBG_ASSERT( GetID().IsEmpty(), "GraphicCacheEntry::ImplInit: Could not initialize graphic! (=>KA)" );
247 3314 : break;
248 : }
249 :
250 3634 : if( rGraphic.IsLink() )
251 236 : maGfxLink = ( (Graphic&) rGraphic ).GetLink();
252 : else
253 3398 : maGfxLink = GfxLink();
254 :
255 3634 : bRet = true;
256 : }
257 :
258 3634 : return bRet;
259 : }
260 :
261 1329 : void GraphicCacheEntry::ImplFillSubstitute( Graphic& rSubstitute )
262 : {
263 : // create substitute for graphic;
264 1329 : const Size aPrefSize( rSubstitute.GetPrefSize() );
265 1329 : const MapMode aPrefMapMode( rSubstitute.GetPrefMapMode() );
266 1329 : const Link aAnimationNotifyHdl( rSubstitute.GetAnimationNotifyHdl() );
267 2658 : const String aDocFileName( rSubstitute.GetDocFileName() );
268 1329 : const sal_uLong nDocFilePos = rSubstitute.GetDocFilePos();
269 1329 : const GraphicType eOldType = rSubstitute.GetType();
270 1329 : const bool bDefaultType = ( rSubstitute.GetType() == GRAPHIC_DEFAULT );
271 :
272 1329 : if( rSubstitute.IsLink() && ( GFX_LINK_TYPE_NONE == maGfxLink.GetType() ) )
273 0 : maGfxLink = rSubstitute.GetLink();
274 :
275 1329 : if(maSvgData.get())
276 : {
277 0 : rSubstitute = maSvgData;
278 : }
279 1329 : else if( mpBmpEx )
280 : {
281 1277 : rSubstitute = *mpBmpEx;
282 : }
283 52 : else if( mpAnimation )
284 : {
285 0 : rSubstitute = *mpAnimation;
286 : }
287 52 : else if( mpMtf )
288 : {
289 51 : rSubstitute = *mpMtf;
290 : }
291 : else
292 : {
293 1 : rSubstitute.Clear();
294 : }
295 :
296 1329 : if( eOldType != GRAPHIC_NONE )
297 : {
298 1066 : rSubstitute.SetPrefSize( aPrefSize );
299 1066 : rSubstitute.SetPrefMapMode( aPrefMapMode );
300 1066 : rSubstitute.SetAnimationNotifyHdl( aAnimationNotifyHdl );
301 1066 : rSubstitute.SetDocFileName( aDocFileName, nDocFilePos );
302 : }
303 :
304 1329 : if( GFX_LINK_TYPE_NONE != maGfxLink.GetType() )
305 : {
306 694 : rSubstitute.SetLink( maGfxLink );
307 : }
308 :
309 1329 : if( bDefaultType )
310 : {
311 1 : rSubstitute.SetDefaultType();
312 1329 : }
313 1329 : }
314 :
315 1329 : void GraphicCacheEntry::AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute )
316 : {
317 1329 : if( mbSwappedAll )
318 0 : mbSwappedAll = !ImplInit( rObj );
319 :
320 1329 : ImplFillSubstitute( rSubstitute );
321 1329 : maGraphicObjectList.push_back( (GraphicObject*) &rObj );
322 1329 : }
323 :
324 18998 : bool GraphicCacheEntry::ReleaseGraphicObjectReference( const GraphicObject& rObj )
325 : {
326 112695 : for(
327 18998 : GraphicObjectList_impl::iterator it = maGraphicObjectList.begin();
328 75130 : it != maGraphicObjectList.end();
329 : ++it
330 : ) {
331 23446 : if( &rObj == *it )
332 : {
333 4879 : maGraphicObjectList.erase( it );
334 4879 : return true;
335 : }
336 : }
337 :
338 14119 : return false;
339 : }
340 :
341 11942 : bool GraphicCacheEntry::HasGraphicObjectReference( const GraphicObject& rObj )
342 : {
343 11942 : bool bRet = false;
344 :
345 29846 : for( size_t i = 0, n = maGraphicObjectList.size(); ( i < n ) && !bRet; ++i )
346 17904 : if( &rObj == maGraphicObjectList[ i ] )
347 1918 : bRet = true;
348 :
349 11942 : return bRet;
350 : }
351 :
352 269 : void GraphicCacheEntry::TryToSwapIn()
353 : {
354 269 : if( mbSwappedAll && !maGraphicObjectList.empty() )
355 0 : maGraphicObjectList.front()->FireSwapInRequest();
356 269 : }
357 :
358 23 : void GraphicCacheEntry::GraphicObjectWasSwappedOut( const GraphicObject& /*rObj*/ )
359 : {
360 23 : mbSwappedAll = true;
361 :
362 46 : for( size_t i = 0, n = maGraphicObjectList.size(); ( i < n ) && mbSwappedAll; ++i )
363 23 : if( !maGraphicObjectList[ i ]->IsSwappedOut() )
364 1 : mbSwappedAll = false;
365 :
366 23 : if( mbSwappedAll )
367 : {
368 22 : delete mpBmpEx, mpBmpEx = NULL;
369 22 : mpMtf = NULL; // No need to delete it as it has already been dereferenced
370 22 : delete mpAnimation, mpAnimation = NULL;
371 :
372 : // #119176# also reset SvgData
373 22 : maSvgData.reset();
374 : }
375 23 : }
376 :
377 8 : bool GraphicCacheEntry::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
378 : {
379 8 : bool bRet = false;
380 :
381 8 : if( !mbSwappedAll && rObj.IsSwappedOut() )
382 : {
383 0 : ImplFillSubstitute( rSubstitute );
384 0 : bRet = true;
385 : }
386 :
387 8 : return bRet;
388 : }
389 :
390 7 : void GraphicCacheEntry::GraphicObjectWasSwappedIn( const GraphicObject& rObj )
391 : {
392 7 : if( mbSwappedAll )
393 6 : mbSwappedAll = !ImplInit( rObj );
394 7 : }
395 :
396 : class GraphicDisplayCacheEntry
397 : {
398 : private:
399 :
400 : ::salhelper::TTimeValue maReleaseTime;
401 : const GraphicCacheEntry* mpRefCacheEntry;
402 : GDIMetaFile* mpMtf;
403 : BitmapEx* mpBmpEx;
404 : GraphicAttr maAttr;
405 : Size maOutSizePix;
406 : sal_uLong mnCacheSize;
407 : sal_uLong mnOutDevDrawMode;
408 : sal_uInt16 mnOutDevBitCount;
409 :
410 : static bool IsCacheableAsBitmap( const GDIMetaFile& rMtf, OutputDevice* pOut, const Size& rSz );
411 :
412 : public:
413 :
414 : static sal_uLong GetNeededSize( OutputDevice* pOut, const Point& rPt, const Size& rSz,
415 : const GraphicObject& rObj, const GraphicAttr& rAttr );
416 :
417 : public:
418 :
419 1 : GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry,
420 : OutputDevice* pOut, const Point& rPt, const Size& rSz,
421 : const GraphicObject& rObj, const GraphicAttr& rAttr,
422 : const BitmapEx& rBmpEx ) :
423 : mpRefCacheEntry( pRefCacheEntry ),
424 1 : mpMtf( NULL ), mpBmpEx( new BitmapEx( rBmpEx ) ),
425 : maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ),
426 1 : mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ),
427 1 : mnOutDevDrawMode( pOut->GetDrawMode() ),
428 4 : mnOutDevBitCount( pOut->GetBitCount() )
429 : {
430 1 : }
431 :
432 0 : GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry,
433 : OutputDevice* pOut, const Point& rPt, const Size& rSz,
434 : const GraphicObject& rObj, const GraphicAttr& rAttr,
435 : const GDIMetaFile& rMtf ) :
436 : mpRefCacheEntry( pRefCacheEntry ),
437 0 : mpMtf( new GDIMetaFile( rMtf ) ), mpBmpEx( NULL ),
438 : maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ),
439 0 : mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ),
440 0 : mnOutDevDrawMode( pOut->GetDrawMode() ),
441 0 : mnOutDevBitCount( pOut->GetBitCount() )
442 : {
443 0 : }
444 :
445 :
446 : ~GraphicDisplayCacheEntry();
447 :
448 : const GraphicAttr& GetAttr() const { return maAttr; }
449 : const Size& GetOutputSizePixel() const { return maOutSizePix; }
450 2 : sal_uLong GetCacheSize() const { return mnCacheSize; }
451 1 : const GraphicCacheEntry* GetReferencedCacheEntry() const { return mpRefCacheEntry; }
452 : sal_uLong GetOutDevDrawMode() const { return mnOutDevDrawMode; }
453 : sal_uInt16 GetOutDevBitCount() const { return mnOutDevBitCount; }
454 :
455 1 : void SetReleaseTime( const ::salhelper::TTimeValue& rReleaseTime ) { maReleaseTime = rReleaseTime; }
456 0 : const ::salhelper::TTimeValue& GetReleaseTime() const { return maReleaseTime; }
457 :
458 0 : sal_Bool Matches( OutputDevice* pOut, const Point& /*rPtPixel*/, const Size& rSzPixel,
459 : const GraphicCacheEntry* pCacheEntry, const GraphicAttr& rAttr ) const
460 : {
461 : // #i46805# Additional match
462 : // criteria: outdev draw mode and
463 : // bit count. One cannot reuse
464 : // this cache object, if it's
465 : // e.g. generated for
466 : // DRAWMODE_GRAYBITMAP.
467 0 : return( ( pCacheEntry == mpRefCacheEntry ) &&
468 0 : ( maAttr == rAttr ) &&
469 0 : ( ( maOutSizePix == rSzPixel ) || ( !maOutSizePix.Width() && !maOutSizePix.Height() ) ) &&
470 0 : ( pOut->GetBitCount() == mnOutDevBitCount ) &&
471 0 : ( pOut->GetDrawMode() == mnOutDevDrawMode ) );
472 : }
473 :
474 : void Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const;
475 : };
476 :
477 : // This whole function is based on checkMetadataBitmap() from grfmgr2.cxx, see that one for details.
478 : // If you do changes here, change the original function too.
479 0 : static void checkMetadataBitmap( const BitmapEx& rBmpEx,
480 : Point /*rSrcPoint*/,
481 : Size rSrcSize,
482 : const Point& rDestPoint,
483 : const Size& rDestSize,
484 : const Size& rRefSize,
485 : bool& o_rbNonBitmapActionEncountered )
486 : {
487 0 : if( rSrcSize == Size())
488 0 : rSrcSize = rBmpEx.GetSizePixel();
489 :
490 0 : if( rDestPoint != Point( 0, 0 ))
491 : {
492 0 : o_rbNonBitmapActionEncountered = true;
493 0 : return;
494 : }
495 0 : if( rDestSize != rRefSize )
496 0 : { if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100
497 0 : && abs( rDestSize.Width() - rRefSize.Width()) < 5
498 0 : && abs( rDestSize.Height() - rRefSize.Height()) < 5 )
499 : ; // ok, assume it's close enough
500 : else
501 : { // fall back to mtf rendering
502 0 : o_rbNonBitmapActionEncountered = true;
503 0 : return;
504 : }
505 : }
506 : }
507 :
508 : // This function is based on GraphicManager::ImplCreateOutput(), in fact it mostly copies
509 : // it, the difference is that this one does not create anything, it only checks if
510 : // ImplCreateOutput() would use the optimization of using the single bitmap.
511 : // If you do changes here, change the original function too.
512 0 : bool GraphicDisplayCacheEntry::IsCacheableAsBitmap( const GDIMetaFile& rMtf,
513 : OutputDevice* pOut, const Size& rSz )
514 : {
515 0 : const Size aNewSize( rMtf.GetPrefSize() );
516 0 : GDIMetaFile rOutMtf = rMtf;
517 :
518 : // Count bitmap actions, and flag actions that paint, but
519 : // are no bitmaps.
520 0 : sal_Int32 nNumBitmaps(0);
521 0 : bool bNonBitmapActionEncountered(false);
522 0 : if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
523 : {
524 0 : const MapMode rPrefMapMode( rMtf.GetPrefMapMode() );
525 0 : const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) );
526 :
527 : sal_uInt32 nCurPos;
528 : MetaAction* pAct;
529 0 : for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct;
530 : pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ )
531 : {
532 0 : switch( pAct->GetType() )
533 : {
534 : case META_FONT_ACTION:
535 : // FALLTHROUGH intended
536 : case META_NULL_ACTION:
537 : // FALLTHROUGH intended
538 :
539 : // OutDev state changes (which don't affect bitmap
540 : // output)
541 : case META_LINECOLOR_ACTION:
542 : // FALLTHROUGH intended
543 : case META_FILLCOLOR_ACTION:
544 : // FALLTHROUGH intended
545 : case META_TEXTCOLOR_ACTION:
546 : // FALLTHROUGH intended
547 : case META_TEXTFILLCOLOR_ACTION:
548 : // FALLTHROUGH intended
549 : case META_TEXTALIGN_ACTION:
550 : // FALLTHROUGH intended
551 : case META_TEXTLINECOLOR_ACTION:
552 : // FALLTHROUGH intended
553 : case META_TEXTLINE_ACTION:
554 : // FALLTHROUGH intended
555 : case META_PUSH_ACTION:
556 : // FALLTHROUGH intended
557 : case META_POP_ACTION:
558 : // FALLTHROUGH intended
559 : case META_LAYOUTMODE_ACTION:
560 : // FALLTHROUGH intended
561 : case META_TEXTLANGUAGE_ACTION:
562 : // FALLTHROUGH intended
563 : case META_COMMENT_ACTION:
564 0 : break;
565 :
566 : // bitmap output methods
567 : case META_BMP_ACTION:
568 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
569 : {
570 0 : MetaBmpAction* pAction = (MetaBmpAction*)pAct;
571 :
572 : checkMetadataBitmap(
573 0 : BitmapEx( pAction->GetBitmap()),
574 : Point(), Size(),
575 0 : pOut->LogicToPixel( pAction->GetPoint(),
576 : rPrefMapMode ),
577 0 : pAction->GetBitmap().GetSizePixel(),
578 : rSizePix,
579 0 : bNonBitmapActionEncountered );
580 : }
581 0 : ++nNumBitmaps;
582 0 : break;
583 :
584 : case META_BMPSCALE_ACTION:
585 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
586 : {
587 0 : MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct;
588 :
589 : checkMetadataBitmap(
590 0 : BitmapEx( pAction->GetBitmap()),
591 : Point(), Size(),
592 0 : pOut->LogicToPixel( pAction->GetPoint(),
593 : rPrefMapMode ),
594 0 : pOut->LogicToPixel( pAction->GetSize(),
595 : rPrefMapMode ),
596 : rSizePix,
597 0 : bNonBitmapActionEncountered );
598 : }
599 0 : ++nNumBitmaps;
600 0 : break;
601 :
602 : case META_BMPSCALEPART_ACTION:
603 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
604 : {
605 0 : MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct;
606 :
607 0 : checkMetadataBitmap( BitmapEx( pAction->GetBitmap() ),
608 0 : pAction->GetSrcPoint(),
609 0 : pAction->GetSrcSize(),
610 0 : pOut->LogicToPixel( pAction->GetDestPoint(),
611 : rPrefMapMode ),
612 0 : pOut->LogicToPixel( pAction->GetDestSize(),
613 : rPrefMapMode ),
614 : rSizePix,
615 0 : bNonBitmapActionEncountered );
616 : }
617 0 : ++nNumBitmaps;
618 0 : break;
619 :
620 : case META_BMPEX_ACTION:
621 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
622 : {
623 0 : MetaBmpExAction* pAction = (MetaBmpExAction*)pAct;
624 :
625 : checkMetadataBitmap(
626 0 : pAction->GetBitmapEx(),
627 : Point(), Size(),
628 0 : pOut->LogicToPixel( pAction->GetPoint(),
629 : rPrefMapMode ),
630 0 : pAction->GetBitmapEx().GetSizePixel(),
631 : rSizePix,
632 0 : bNonBitmapActionEncountered );
633 : }
634 0 : ++nNumBitmaps;
635 0 : break;
636 :
637 : case META_BMPEXSCALE_ACTION:
638 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
639 : {
640 0 : MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct;
641 :
642 : checkMetadataBitmap(
643 0 : pAction->GetBitmapEx(),
644 : Point(), Size(),
645 0 : pOut->LogicToPixel( pAction->GetPoint(),
646 : rPrefMapMode ),
647 0 : pOut->LogicToPixel( pAction->GetSize(),
648 : rPrefMapMode ),
649 : rSizePix,
650 0 : bNonBitmapActionEncountered );
651 : }
652 0 : ++nNumBitmaps;
653 0 : break;
654 :
655 : case META_BMPEXSCALEPART_ACTION:
656 0 : if( !nNumBitmaps && !bNonBitmapActionEncountered )
657 : {
658 0 : MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct;
659 :
660 0 : checkMetadataBitmap( pAction->GetBitmapEx(),
661 0 : pAction->GetSrcPoint(),
662 0 : pAction->GetSrcSize(),
663 0 : pOut->LogicToPixel( pAction->GetDestPoint(),
664 : rPrefMapMode ),
665 0 : pOut->LogicToPixel( pAction->GetDestSize(),
666 : rPrefMapMode ),
667 : rSizePix,
668 0 : bNonBitmapActionEncountered );
669 : }
670 0 : ++nNumBitmaps;
671 0 : break;
672 :
673 : // these actions actually output something (that's
674 : // different from a bitmap)
675 : case META_RASTEROP_ACTION:
676 0 : if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT )
677 0 : break;
678 : // FALLTHROUGH intended
679 : case META_PIXEL_ACTION:
680 : // FALLTHROUGH intended
681 : case META_POINT_ACTION:
682 : // FALLTHROUGH intended
683 : case META_LINE_ACTION:
684 : // FALLTHROUGH intended
685 : case META_RECT_ACTION:
686 : // FALLTHROUGH intended
687 : case META_ROUNDRECT_ACTION:
688 : // FALLTHROUGH intended
689 : case META_ELLIPSE_ACTION:
690 : // FALLTHROUGH intended
691 : case META_ARC_ACTION:
692 : // FALLTHROUGH intended
693 : case META_PIE_ACTION:
694 : // FALLTHROUGH intended
695 : case META_CHORD_ACTION:
696 : // FALLTHROUGH intended
697 : case META_POLYLINE_ACTION:
698 : // FALLTHROUGH intended
699 : case META_POLYGON_ACTION:
700 : // FALLTHROUGH intended
701 : case META_POLYPOLYGON_ACTION:
702 : // FALLTHROUGH intended
703 :
704 : case META_TEXT_ACTION:
705 : // FALLTHROUGH intended
706 : case META_TEXTARRAY_ACTION:
707 : // FALLTHROUGH intended
708 : case META_STRETCHTEXT_ACTION:
709 : // FALLTHROUGH intended
710 : case META_TEXTRECT_ACTION:
711 : // FALLTHROUGH intended
712 :
713 : case META_MASK_ACTION:
714 : // FALLTHROUGH intended
715 : case META_MASKSCALE_ACTION:
716 : // FALLTHROUGH intended
717 : case META_MASKSCALEPART_ACTION:
718 : // FALLTHROUGH intended
719 :
720 : case META_GRADIENT_ACTION:
721 : // FALLTHROUGH intended
722 : case META_HATCH_ACTION:
723 : // FALLTHROUGH intended
724 : case META_WALLPAPER_ACTION:
725 : // FALLTHROUGH intended
726 :
727 : case META_TRANSPARENT_ACTION:
728 : // FALLTHROUGH intended
729 : case META_EPS_ACTION:
730 : // FALLTHROUGH intended
731 : case META_FLOATTRANSPARENT_ACTION:
732 : // FALLTHROUGH intended
733 : case META_GRADIENTEX_ACTION:
734 : // FALLTHROUGH intended
735 :
736 : // OutDev state changes that _do_ affect bitmap
737 : // output
738 : case META_CLIPREGION_ACTION:
739 : // FALLTHROUGH intended
740 : case META_ISECTRECTCLIPREGION_ACTION:
741 : // FALLTHROUGH intended
742 : case META_ISECTREGIONCLIPREGION_ACTION:
743 : // FALLTHROUGH intended
744 : case META_MOVECLIPREGION_ACTION:
745 : // FALLTHROUGH intended
746 :
747 : case META_MAPMODE_ACTION:
748 : // FALLTHROUGH intended
749 : case META_REFPOINT_ACTION:
750 : // FALLTHROUGH intended
751 : default:
752 0 : bNonBitmapActionEncountered = true;
753 0 : break;
754 : }
755 0 : }
756 : }
757 0 : return nNumBitmaps == 1 && !bNonBitmapActionEncountered;
758 : }
759 :
760 3 : sal_uLong GraphicDisplayCacheEntry::GetNeededSize( OutputDevice* pOut, const Point& /*rPt*/, const Size& rSz,
761 : const GraphicObject& rObj, const GraphicAttr& rAttr )
762 : {
763 3 : const Graphic& rGraphic = rObj.GetGraphic();
764 3 : const GraphicType eType = rGraphic.GetType();
765 :
766 3 : bool canCacheAsBitmap = false;
767 3 : if( GRAPHIC_BITMAP == eType )
768 3 : canCacheAsBitmap = true;
769 0 : else if( GRAPHIC_GDIMETAFILE == eType )
770 0 : canCacheAsBitmap = IsCacheableAsBitmap( rGraphic.GetGDIMetaFile(), pOut, rSz );
771 : else
772 0 : return 0;
773 3 : if( canCacheAsBitmap )
774 : {
775 3 : const Size aOutSizePix( pOut->LogicToPixel( rSz ) );
776 3 : const long nBitCount = pOut->GetBitCount();
777 :
778 6 : if( ( aOutSizePix.Width() > MAX_BMP_EXTENT ) ||
779 3 : ( aOutSizePix.Height() > MAX_BMP_EXTENT ) )
780 : {
781 0 : return ULONG_MAX;
782 : }
783 3 : else if( nBitCount )
784 : {
785 3 : sal_uLong nNeededSize = aOutSizePix.Width() * aOutSizePix.Height() * nBitCount / 8;
786 3 : if( rObj.IsTransparent() || ( rAttr.GetRotation() % 3600 ) )
787 3 : nNeededSize += nNeededSize / nBitCount;
788 3 : return nNeededSize;
789 : }
790 : else
791 : {
792 : OSL_FAIL( "GraphicDisplayCacheEntry::GetNeededSize(): pOut->GetBitCount() == 0" );
793 0 : return 256000;
794 : }
795 : }
796 : else
797 0 : return rGraphic.GetSizeBytes();
798 : }
799 :
800 2 : GraphicDisplayCacheEntry::~GraphicDisplayCacheEntry()
801 : {
802 1 : if( mpMtf )
803 0 : delete mpMtf;
804 :
805 1 : if( mpBmpEx )
806 1 : delete mpBmpEx;
807 1 : }
808 :
809 0 : void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const
810 : {
811 0 : if( mpMtf )
812 0 : GraphicManager::ImplDraw( pOut, rPt, rSz, *mpMtf, maAttr );
813 0 : else if( mpBmpEx )
814 : {
815 0 : if( maAttr.IsRotated() )
816 : {
817 0 : Polygon aPoly( Rectangle( rPt, rSz ) );
818 :
819 0 : aPoly.Rotate( rPt, maAttr.GetRotation() % 3600 );
820 0 : const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
821 0 : pOut->DrawBitmapEx( aRotBoundRect.TopLeft(), aRotBoundRect.GetSize(), *mpBmpEx );
822 : }
823 : else
824 0 : pOut->DrawBitmapEx( rPt, rSz, *mpBmpEx );
825 : }
826 0 : }
827 :
828 311 : GraphicCache::GraphicCache( sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) :
829 : mnReleaseTimeoutSeconds ( 0UL ),
830 : mnMaxDisplaySize ( nDisplayCacheSize ),
831 : mnMaxObjDisplaySize ( nMaxObjDisplayCacheSize ),
832 311 : mnUsedDisplaySize ( 0UL )
833 : {
834 311 : maReleaseTimer.SetTimeoutHdl( LINK( this, GraphicCache, ReleaseTimeoutHdl ) );
835 311 : maReleaseTimer.SetTimeout( RELEASE_TIMEOUT );
836 311 : maReleaseTimer.Start();
837 311 : }
838 :
839 263 : GraphicCache::~GraphicCache()
840 : {
841 : DBG_ASSERT( !maGraphicCache.size(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in cache" );
842 : DBG_ASSERT( maDisplayCache.empty(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in display cache" );
843 263 : }
844 :
845 4957 : void GraphicCache::AddGraphicObject(
846 : const GraphicObject& rObj,
847 : Graphic& rSubstitute,
848 : const OString* pID,
849 : const GraphicObject* pCopyObj
850 : )
851 : {
852 4957 : sal_Bool bInserted = sal_False;
853 :
854 9914 : if( !rObj.IsSwappedOut()
855 6608 : && ( pID
856 4694 : || ( pCopyObj
857 2502 : && ( pCopyObj->GetType() != GRAPHIC_NONE )
858 : )
859 3718 : || ( rObj.GetType() != GRAPHIC_NONE )
860 : )
861 : )
862 : {
863 1651 : if( pCopyObj
864 1651 : && !maGraphicCache.empty()
865 : )
866 : {
867 976 : GraphicCacheEntryList::iterator it = maGraphicCache.begin();
868 16560 : while( !bInserted
869 20936 : && ( it != maGraphicCache.end() )
870 : )
871 : {
872 6328 : if( (*it)->HasGraphicObjectReference( *pCopyObj ) )
873 : {
874 976 : (*it)->AddGraphicObjectReference( rObj, rSubstitute );
875 976 : bInserted = sal_True;
876 : }
877 : else
878 : {
879 5352 : ++it;
880 : }
881 : }
882 : }
883 :
884 1651 : if( !bInserted )
885 : {
886 675 : GraphicCacheEntryList::iterator it = maGraphicCache.begin();
887 675 : ::std::auto_ptr< GraphicID > apID;
888 :
889 675 : if( !pID )
890 : {
891 412 : apID.reset( new GraphicID( rObj ) );
892 : }
893 :
894 10782 : while( !bInserted
895 14278 : && ( it != maGraphicCache.end() )
896 : )
897 : {
898 4202 : const GraphicID& rEntryID = (*it)->GetID();
899 :
900 4202 : if( pID )
901 : {
902 1957 : if( rEntryID.GetIDString() == *pID )
903 : {
904 263 : (*it)->TryToSwapIn();
905 :
906 : // since pEntry->TryToSwapIn can modify our current list, we have to
907 : // iterate from beginning to add a reference to the appropriate
908 : // CacheEntry object; after this, quickly jump out of the outer iteration
909 6923 : for( GraphicCacheEntryList::iterator jt = maGraphicCache.begin();
910 6397 : !bInserted && jt != maGraphicCache.end();
911 : ++jt
912 : )
913 : {
914 1957 : const GraphicID& rID = (*jt)->GetID();
915 :
916 1957 : if( rID.GetIDString() == *pID )
917 : {
918 263 : (*jt)->AddGraphicObjectReference( rObj, rSubstitute );
919 263 : bInserted = sal_True;
920 : }
921 : }
922 :
923 263 : if( !bInserted )
924 : {
925 0 : maGraphicCache.push_back( new GraphicCacheEntry( rObj ) );
926 0 : bInserted = sal_True;
927 : }
928 : }
929 : }
930 : else
931 : {
932 2245 : if( rEntryID == *apID )
933 : {
934 90 : (*it)->AddGraphicObjectReference( rObj, rSubstitute );
935 90 : bInserted = sal_True;
936 : }
937 : }
938 :
939 4202 : if( !bInserted )
940 3849 : ++it;
941 675 : }
942 : }
943 : }
944 :
945 4957 : if( !bInserted )
946 3628 : maGraphicCache.push_back( new GraphicCacheEntry( rObj ) );
947 4957 : }
948 :
949 4879 : void GraphicCache::ReleaseGraphicObject( const GraphicObject& rObj )
950 : {
951 : // Release cached object
952 4879 : bool bRemoved = false;
953 4879 : GraphicCacheEntryList::iterator it = maGraphicCache.begin();
954 28756 : while (!bRemoved && it != maGraphicCache.end())
955 : {
956 18998 : bRemoved = (*it)->ReleaseGraphicObjectReference( rObj );
957 :
958 18998 : if( bRemoved )
959 : {
960 4879 : if( 0 == (*it)->GetGraphicObjectReferenceCount() )
961 : {
962 : // if graphic cache entry has no more references,
963 : // the corresponding display cache object can be removed
964 3552 : GraphicDisplayCacheEntryList::iterator it2 = maDisplayCache.begin();
965 7105 : while( it2 != maDisplayCache.end() )
966 : {
967 1 : GraphicDisplayCacheEntry* pDisplayEntry = *it2;
968 1 : if( pDisplayEntry->GetReferencedCacheEntry() == *it )
969 : {
970 1 : mnUsedDisplaySize -= pDisplayEntry->GetCacheSize();
971 1 : it2 = maDisplayCache.erase( it2 );
972 1 : delete pDisplayEntry;
973 : }
974 : else
975 0 : ++it2;
976 : }
977 :
978 : // delete graphic cache entry
979 3552 : delete *it;
980 3552 : it = maGraphicCache.erase( it );
981 : }
982 : }
983 : else
984 14119 : ++it;
985 : }
986 :
987 : DBG_ASSERT( bRemoved, "GraphicCache::ReleaseGraphicObject(...): GraphicObject not found in cache" );
988 4879 : }
989 :
990 23 : void GraphicCache::GraphicObjectWasSwappedOut( const GraphicObject& rObj )
991 : {
992 : // notify cache that rObj is swapped out (and can thus be pruned
993 : // from the cache)
994 23 : GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
995 :
996 23 : if( pEntry )
997 23 : pEntry->GraphicObjectWasSwappedOut( rObj );
998 23 : }
999 :
1000 8 : sal_Bool GraphicCache::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
1001 : {
1002 8 : GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
1003 :
1004 8 : if( !pEntry )
1005 0 : return sal_False;
1006 :
1007 8 : return pEntry->FillSwappedGraphicObject( rObj, rSubstitute );
1008 : }
1009 :
1010 7 : void GraphicCache::GraphicObjectWasSwappedIn( const GraphicObject& rObj )
1011 : {
1012 7 : GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
1013 :
1014 7 : if( pEntry )
1015 : {
1016 7 : if( pEntry->GetID().IsEmpty() )
1017 : {
1018 0 : ReleaseGraphicObject( rObj );
1019 0 : AddGraphicObject( rObj, (Graphic&) rObj.GetGraphic(), NULL, NULL );
1020 : }
1021 : else
1022 7 : pEntry->GraphicObjectWasSwappedIn( rObj );
1023 : }
1024 7 : }
1025 :
1026 0 : void GraphicCache::SetMaxDisplayCacheSize( sal_uLong nNewCacheSize )
1027 : {
1028 0 : mnMaxDisplaySize = nNewCacheSize;
1029 :
1030 0 : if( GetMaxDisplayCacheSize() < GetUsedDisplayCacheSize() )
1031 0 : ImplFreeDisplayCacheSpace( GetUsedDisplayCacheSize() - GetMaxDisplayCacheSize() );
1032 0 : }
1033 :
1034 0 : void GraphicCache::SetMaxObjDisplayCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached )
1035 : {
1036 0 : const sal_Bool bDestroy = ( bDestroyGreaterCached && ( nNewMaxObjSize < mnMaxObjDisplaySize ) );
1037 :
1038 0 : mnMaxObjDisplaySize = std::min( nNewMaxObjSize, mnMaxDisplaySize );
1039 :
1040 0 : if( bDestroy )
1041 : {
1042 0 : GraphicDisplayCacheEntryList::iterator it = maDisplayCache.begin();
1043 0 : while( it != maDisplayCache.end() )
1044 : {
1045 0 : GraphicDisplayCacheEntry* pCacheObj = *it;
1046 0 : if( pCacheObj->GetCacheSize() > mnMaxObjDisplaySize )
1047 : {
1048 0 : mnUsedDisplaySize -= pCacheObj->GetCacheSize();
1049 0 : it = maDisplayCache.erase( it );
1050 0 : delete pCacheObj;
1051 : }
1052 : else
1053 0 : ++it;
1054 : }
1055 : }
1056 0 : }
1057 :
1058 311 : void GraphicCache::SetCacheTimeout( sal_uLong nTimeoutSeconds )
1059 : {
1060 311 : if( mnReleaseTimeoutSeconds != nTimeoutSeconds )
1061 : {
1062 311 : ::salhelper::TTimeValue aReleaseTime;
1063 :
1064 311 : if( ( mnReleaseTimeoutSeconds = nTimeoutSeconds ) != 0 )
1065 : {
1066 311 : osl_getSystemTime( &aReleaseTime );
1067 311 : aReleaseTime.addTime( ::salhelper::TTimeValue( nTimeoutSeconds, 0 ) );
1068 : }
1069 :
1070 933 : for( GraphicDisplayCacheEntryList::const_iterator it = maDisplayCache.begin();
1071 622 : it != maDisplayCache.end(); ++it )
1072 : {
1073 0 : (*it)->SetReleaseTime( aReleaseTime );
1074 : }
1075 : }
1076 311 : }
1077 :
1078 1 : sal_Bool GraphicCache::IsDisplayCacheable( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1079 : const GraphicObject& rObj, const GraphicAttr& rAttr ) const
1080 : {
1081 2 : return( GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) <=
1082 2 : GetMaxObjDisplayCacheSize() );
1083 : }
1084 :
1085 14 : sal_Bool GraphicCache::IsInDisplayCache( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1086 : const GraphicObject& rObj, const GraphicAttr& rAttr ) const
1087 : {
1088 14 : const Point aPtPixel( pOut->LogicToPixel( rPt ) );
1089 14 : const Size aSzPixel( pOut->LogicToPixel( rSz ) );
1090 14 : const GraphicCacheEntry* pCacheEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
1091 14 : sal_Bool bFound = sal_False;
1092 :
1093 14 : if( pCacheEntry )
1094 : {
1095 42 : for( GraphicDisplayCacheEntryList::const_iterator it = maDisplayCache.begin();
1096 42 : !bFound && ( it != maDisplayCache.end() ); ++it )
1097 : {
1098 0 : if( (*it)->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) )
1099 0 : bFound = sal_True;
1100 : }
1101 : }
1102 :
1103 14 : return bFound;
1104 : }
1105 :
1106 444 : OString GraphicCache::GetUniqueID( const GraphicObject& rObj ) const
1107 : {
1108 444 : OString aRet;
1109 444 : GraphicCacheEntry* pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
1110 :
1111 : // ensure that the entry is correctly initialized (it has to be read at least once)
1112 444 : if( pEntry && pEntry->GetID().IsEmpty() )
1113 6 : pEntry->TryToSwapIn();
1114 :
1115 : // do another call to ImplGetCacheEntry in case of modified entry list
1116 444 : pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
1117 :
1118 444 : if( pEntry )
1119 444 : aRet = pEntry->GetID().GetIDString();
1120 :
1121 444 : return aRet;
1122 : }
1123 :
1124 1 : sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1125 : const GraphicObject& rObj, const GraphicAttr& rAttr,
1126 : const BitmapEx& rBmpEx )
1127 : {
1128 1 : const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr );
1129 1 : sal_Bool bRet = sal_False;
1130 :
1131 1 : if( nNeededSize <= GetMaxObjDisplayCacheSize() )
1132 : {
1133 1 : if( nNeededSize > GetFreeDisplayCacheSize() )
1134 0 : ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() );
1135 :
1136 : GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ),
1137 1 : pOut, rPt, rSz, rObj, rAttr, rBmpEx );
1138 :
1139 1 : if( GetCacheTimeout() )
1140 : {
1141 1 : ::salhelper::TTimeValue aReleaseTime;
1142 :
1143 1 : osl_getSystemTime( &aReleaseTime );
1144 1 : aReleaseTime.addTime( ::salhelper::TTimeValue( GetCacheTimeout(), 0 ) );
1145 1 : pNewEntry->SetReleaseTime( aReleaseTime );
1146 : }
1147 :
1148 1 : maDisplayCache.push_back( pNewEntry );
1149 1 : mnUsedDisplaySize += pNewEntry->GetCacheSize();
1150 1 : bRet = sal_True;
1151 : }
1152 :
1153 1 : return bRet;
1154 : }
1155 :
1156 0 : sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1157 : const GraphicObject& rObj, const GraphicAttr& rAttr,
1158 : const GDIMetaFile& rMtf )
1159 : {
1160 0 : const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr );
1161 0 : sal_Bool bRet = sal_False;
1162 :
1163 0 : if( nNeededSize <= GetMaxObjDisplayCacheSize() )
1164 : {
1165 0 : if( nNeededSize > GetFreeDisplayCacheSize() )
1166 0 : ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() );
1167 :
1168 : GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ),
1169 0 : pOut, rPt, rSz, rObj, rAttr, rMtf );
1170 :
1171 0 : if( GetCacheTimeout() )
1172 : {
1173 0 : ::salhelper::TTimeValue aReleaseTime;
1174 :
1175 0 : osl_getSystemTime( &aReleaseTime );
1176 0 : aReleaseTime.addTime( ::salhelper::TTimeValue( GetCacheTimeout(), 0 ) );
1177 0 : pNewEntry->SetReleaseTime( aReleaseTime );
1178 : }
1179 :
1180 0 : maDisplayCache.push_back( pNewEntry );
1181 0 : mnUsedDisplaySize += pNewEntry->GetCacheSize();
1182 0 : bRet = sal_True;
1183 : }
1184 :
1185 0 : return bRet;
1186 : }
1187 :
1188 1 : sal_Bool GraphicCache::DrawDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1189 : const GraphicObject& rObj, const GraphicAttr& rAttr )
1190 : {
1191 1 : const Point aPtPixel( pOut->LogicToPixel( rPt ) );
1192 1 : const Size aSzPixel( pOut->LogicToPixel( rSz ) );
1193 1 : const GraphicCacheEntry* pCacheEntry = ImplGetCacheEntry( rObj );
1194 1 : GraphicDisplayCacheEntry* pDisplayCacheEntry = NULL;
1195 1 : GraphicDisplayCacheEntryList::iterator it = maDisplayCache.begin();
1196 1 : sal_Bool bRet = sal_False;
1197 :
1198 2 : while( !bRet && it != maDisplayCache.end() )
1199 : {
1200 0 : pDisplayCacheEntry = *it;
1201 0 : if( pDisplayCacheEntry->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) )
1202 : {
1203 0 : ::salhelper::TTimeValue aReleaseTime;
1204 :
1205 : // put found object at last used position
1206 0 : it = maDisplayCache.erase( it );
1207 0 : maDisplayCache.push_back( pDisplayCacheEntry );
1208 :
1209 0 : if( GetCacheTimeout() )
1210 : {
1211 0 : osl_getSystemTime( &aReleaseTime );
1212 0 : aReleaseTime.addTime( ::salhelper::TTimeValue( GetCacheTimeout(), 0 ) );
1213 : }
1214 :
1215 0 : pDisplayCacheEntry->SetReleaseTime( aReleaseTime );
1216 0 : bRet = sal_True;
1217 : }
1218 : else
1219 0 : ++it;
1220 : }
1221 :
1222 1 : if( bRet )
1223 0 : pDisplayCacheEntry->Draw( pOut, rPt, rSz );
1224 :
1225 1 : return bRet;
1226 : }
1227 :
1228 0 : sal_Bool GraphicCache::ImplFreeDisplayCacheSpace( sal_uLong nSizeToFree )
1229 : {
1230 0 : sal_uLong nFreedSize = 0UL;
1231 :
1232 0 : if( nSizeToFree )
1233 : {
1234 0 : GraphicDisplayCacheEntryList::iterator it = maDisplayCache.begin();
1235 :
1236 0 : if( nSizeToFree > mnUsedDisplaySize )
1237 0 : nSizeToFree = mnUsedDisplaySize;
1238 :
1239 0 : while( it != maDisplayCache.end() )
1240 : {
1241 0 : GraphicDisplayCacheEntry* pCacheObj = *it;
1242 :
1243 0 : nFreedSize += pCacheObj->GetCacheSize();
1244 0 : mnUsedDisplaySize -= pCacheObj->GetCacheSize();
1245 0 : it = maDisplayCache.erase( it );
1246 0 : delete pCacheObj;
1247 :
1248 0 : if( nFreedSize >= nSizeToFree )
1249 0 : break;
1250 : }
1251 : }
1252 :
1253 0 : return( nFreedSize >= nSizeToFree );
1254 : }
1255 :
1256 942 : GraphicCacheEntry* GraphicCache::ImplGetCacheEntry( const GraphicObject& rObj )
1257 : {
1258 942 : GraphicCacheEntry* pRet = NULL;
1259 :
1260 20610 : for(
1261 942 : GraphicCacheEntryList::iterator it = maGraphicCache.begin();
1262 18726 : !pRet && it != maGraphicCache.end();
1263 : ++it
1264 : ) {
1265 5614 : if( (*it)->HasGraphicObjectReference( rObj ) ) {
1266 942 : pRet = *it;
1267 : }
1268 : }
1269 :
1270 942 : return pRet;
1271 : }
1272 :
1273 708 : IMPL_LINK( GraphicCache, ReleaseTimeoutHdl, Timer*, pTimer )
1274 : {
1275 354 : pTimer->Stop();
1276 :
1277 354 : ::salhelper::TTimeValue aCurTime;
1278 354 : GraphicDisplayCacheEntryList::iterator it = maDisplayCache.begin();
1279 :
1280 354 : osl_getSystemTime( &aCurTime );
1281 :
1282 708 : while( it != maDisplayCache.end() )
1283 : {
1284 0 : GraphicDisplayCacheEntry* pDisplayEntry = *it;
1285 0 : const ::salhelper::TTimeValue& rReleaseTime = pDisplayEntry->GetReleaseTime();
1286 :
1287 0 : if( !rReleaseTime.isEmpty() && ( rReleaseTime < aCurTime ) )
1288 : {
1289 0 : mnUsedDisplaySize -= pDisplayEntry->GetCacheSize();
1290 0 : it = maDisplayCache.erase( it );
1291 0 : delete pDisplayEntry;
1292 : }
1293 : else
1294 0 : ++it;
1295 : }
1296 :
1297 354 : pTimer->Start();
1298 :
1299 354 : return 0;
1300 465 : }
1301 :
1302 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|