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