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