1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26
27 #include <vos/timer.hxx>
28 #include <tools/debug.hxx>
29 #include <vcl/outdev.hxx>
30 #include <tools/poly.hxx>
31 #include "grfcache.hxx"
32 #include <rtl/crc.h>
33 #include <memory>
34
35 // -----------
36 // - Defines -
37 // -----------
38
39 #define RELEASE_TIMEOUT 10000
40 #define MAX_BMP_EXTENT 4096
41
42 // -----------
43 // - statics -
44 // -----------
45
46 static const char aHexData[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
47
48 // -------------
49 // - GraphicID -
50 // -------------
51
52 class GraphicID
53 {
54 private:
55
56 sal_uInt32 mnID1;
57 sal_uInt32 mnID2;
58 sal_uInt32 mnID3;
59 sal_uInt32 mnID4;
60
61 GraphicID();
62
63 public:
64
65
66 GraphicID( const GraphicObject& rObj );
~GraphicID()67 ~GraphicID() {}
68
operator ==(const GraphicID & rID) const69 sal_Bool operator==( const GraphicID& rID ) const
70 {
71 return( rID.mnID1 == mnID1 && rID.mnID2 == mnID2 &&
72 rID.mnID3 == mnID3 && rID.mnID4 == mnID4 );
73 }
74
75 ByteString GetIDString() const;
IsEmpty() const76 sal_Bool IsEmpty() const { return( 0 == mnID4 ); }
77 };
78
79 // -----------------------------------------------------------------------------
80
GraphicID(const GraphicObject & rObj)81 GraphicID::GraphicID( const GraphicObject& rObj )
82 {
83 const Graphic& rGraphic = rObj.GetGraphic();
84
85 mnID1 = ( (sal_uLong) rGraphic.GetType() ) << 28;
86
87 switch( rGraphic.GetType() )
88 {
89 case( GRAPHIC_BITMAP ):
90 {
91 if(rGraphic.getSvgData().get())
92 {
93 const SvgDataPtr& rSvgDataPtr = rGraphic.getSvgData();
94 const basegfx::B2DRange& rRange = rSvgDataPtr->getRange();
95
96 mnID1 |= rSvgDataPtr->getSvgDataArrayLength();
97 mnID2 = basegfx::fround(rRange.getWidth());
98 mnID3 = basegfx::fround(rRange.getHeight());
99 mnID4 = rtl_crc32(0, rSvgDataPtr->getSvgDataArray().get(), rSvgDataPtr->getSvgDataArrayLength());
100 }
101 else if( rGraphic.IsAnimated() )
102 {
103 const Animation aAnimation( rGraphic.GetAnimation() );
104
105 mnID1 |= ( aAnimation.Count() & 0x0fffffff );
106 mnID2 = aAnimation.GetDisplaySizePixel().Width();
107 mnID3 = aAnimation.GetDisplaySizePixel().Height();
108 mnID4 = rGraphic.GetChecksum();
109 }
110 else
111 {
112 const BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
113
114 mnID1 |= ( ( ( (sal_uLong) aBmpEx.GetTransparentType() << 8 ) | ( aBmpEx.IsAlpha() ? 1 : 0 ) ) & 0x0fffffff );
115 mnID2 = aBmpEx.GetSizePixel().Width();
116 mnID3 = aBmpEx.GetSizePixel().Height();
117 mnID4 = rGraphic.GetChecksum();
118 }
119 }
120 break;
121
122 case( GRAPHIC_GDIMETAFILE ):
123 {
124 const GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() );
125
126 mnID1 |= ( aMtf.GetActionCount() & 0x0fffffff );
127 mnID2 = aMtf.GetPrefSize().Width();
128 mnID3 = aMtf.GetPrefSize().Height();
129 mnID4 = rGraphic.GetChecksum();
130 }
131 break;
132
133 default:
134 mnID2 = mnID3 = mnID4 = 0;
135 break;
136 }
137 }
138
139 // -----------------------------------------------------------------------------
140
GetIDString() const141 ByteString GraphicID::GetIDString() const
142 {
143 ByteString aHexStr;
144 sal_Char* pStr = aHexStr.AllocBuffer( 32 );
145 sal_Int32 nShift;
146
147 for( nShift = 28; nShift >= 0; nShift -= 4 )
148 *pStr++ = aHexData[ ( mnID1 >> (sal_uInt32) nShift ) & 0xf ];
149
150 for( nShift = 28; nShift >= 0; nShift -= 4 )
151 *pStr++ = aHexData[ ( mnID2 >> (sal_uInt32) nShift ) & 0xf ];
152
153 for( nShift = 28; nShift >= 0; nShift -= 4 )
154 *pStr++ = aHexData[ ( mnID3 >> (sal_uInt32) nShift ) & 0xf ];
155
156 for( nShift = 28; nShift >= 0; nShift -= 4 )
157 *pStr++ = aHexData[ ( mnID4 >> (sal_uInt32) nShift ) & 0xf ];
158
159 return aHexStr;
160 }
161
162 // ---------------------
163 // - GraphicCacheEntry -
164 // ---------------------
165
166 class GraphicCacheEntry
167 {
168 private:
169
170 List maGraphicObjectList;
171 GraphicID maID;
172 GfxLink maGfxLink;
173 BitmapEx* mpBmpEx;
174 GDIMetaFile* mpMtf;
175 Animation* mpAnimation;
176 sal_Bool mbSwappedAll;
177
178 // SvgData support
179 SvgDataPtr maSvgData;
180
181 sal_Bool ImplInit( const GraphicObject& rObj );
ImplMatches(const GraphicObject & rObj) const182 sal_Bool ImplMatches( const GraphicObject& rObj ) const { return( GraphicID( rObj ) == maID ); }
183 void ImplFillSubstitute( Graphic& rSubstitute );
184
185 public:
186
187 GraphicCacheEntry( const GraphicObject& rObj );
188 ~GraphicCacheEntry();
189
GetID() const190 const GraphicID& GetID() const { return maID; }
191
192 void AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute );
193 sal_Bool ReleaseGraphicObjectReference( const GraphicObject& rObj );
GetGraphicObjectReferenceCount()194 sal_uLong GetGraphicObjectReferenceCount() { return maGraphicObjectList.Count(); }
195 sal_Bool HasGraphicObjectReference( const GraphicObject& rObj );
196
197 void TryToSwapIn();
198 void GraphicObjectWasSwappedOut( const GraphicObject& rObj );
199 sal_Bool FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute );
200 void GraphicObjectWasSwappedIn( const GraphicObject& rObj );
201 };
202
203 // -----------------------------------------------------------------------------
204
GraphicCacheEntry(const GraphicObject & rObj)205 GraphicCacheEntry::GraphicCacheEntry( const GraphicObject& rObj ) :
206 maID ( rObj ),
207 mpBmpEx ( NULL ),
208 mpMtf ( NULL ),
209 mpAnimation ( NULL ),
210 mbSwappedAll ( true )
211 {
212 mbSwappedAll = !ImplInit(rObj);
213 maGraphicObjectList.Insert( (void*) &rObj, LIST_APPEND );
214 }
215
216 // -----------------------------------------------------------------------------
217
~GraphicCacheEntry()218 GraphicCacheEntry::~GraphicCacheEntry()
219 {
220 DBG_ASSERT( !maGraphicObjectList.Count(), "GraphicCacheEntry::~GraphicCacheEntry(): Not all GraphicObjects are removed from this entry" );
221
222 delete mpBmpEx;
223 delete mpMtf;
224 delete mpAnimation;
225 }
226
227 // -----------------------------------------------------------------------------
228
ImplInit(const GraphicObject & rObj)229 sal_Bool GraphicCacheEntry::ImplInit( const GraphicObject& rObj )
230 {
231 sal_Bool bRet;
232
233 if( !rObj.IsSwappedOut() )
234 {
235 const Graphic& rGraphic = rObj.GetGraphic();
236
237 if( mpBmpEx )
238 delete mpBmpEx, mpBmpEx = NULL;
239
240 if( mpMtf )
241 delete mpMtf, mpMtf = NULL;
242
243 if( mpAnimation )
244 delete mpAnimation, mpAnimation = NULL;
245
246 switch( rGraphic.GetType() )
247 {
248 case( GRAPHIC_BITMAP ):
249 {
250 if(rGraphic.getSvgData().get())
251 {
252 maSvgData = rGraphic.getSvgData();
253 }
254 else if( rGraphic.IsAnimated() )
255 {
256 mpAnimation = new Animation( rGraphic.GetAnimation() );
257 }
258 else
259 {
260 mpBmpEx = new BitmapEx( rGraphic.GetBitmapEx() );
261 }
262 }
263 break;
264
265 case( GRAPHIC_GDIMETAFILE ):
266 {
267 mpMtf = new GDIMetaFile( rGraphic.GetGDIMetaFile() );
268 }
269 break;
270
271 default:
272 DBG_ASSERT( GetID().IsEmpty(), "GraphicCacheEntry::ImplInit: Could not initialize graphic! (=>KA)" );
273 break;
274 }
275
276 if( rGraphic.IsLink() )
277 maGfxLink = ( (Graphic&) rGraphic ).GetLink();
278 else
279 maGfxLink = GfxLink();
280
281 bRet = sal_True;
282 }
283 else
284 bRet = sal_False;
285
286 return bRet;
287 }
288
289 // -----------------------------------------------------------------------------
290
ImplFillSubstitute(Graphic & rSubstitute)291 void GraphicCacheEntry::ImplFillSubstitute( Graphic& rSubstitute )
292 {
293 // create substitute for graphic;
294 const Size aPrefSize( rSubstitute.GetPrefSize() );
295 const MapMode aPrefMapMode( rSubstitute.GetPrefMapMode() );
296 const Link aAnimationNotifyHdl( rSubstitute.GetAnimationNotifyHdl() );
297 const String aDocFileName( rSubstitute.GetDocFileName() );
298 const sal_uLong nDocFilePos = rSubstitute.GetDocFilePos();
299 const GraphicType eOldType = rSubstitute.GetType();
300 const sal_Bool bDefaultType = ( rSubstitute.GetType() == GRAPHIC_DEFAULT );
301
302 if( rSubstitute.IsLink() && ( GFX_LINK_TYPE_NONE == maGfxLink.GetType() ) )
303 maGfxLink = rSubstitute.GetLink();
304
305 if(maSvgData.get())
306 {
307 rSubstitute = maSvgData;
308 }
309 else if( mpBmpEx )
310 {
311 rSubstitute = *mpBmpEx;
312 }
313 else if( mpAnimation )
314 {
315 rSubstitute = *mpAnimation;
316 }
317 else if( mpMtf )
318 {
319 rSubstitute = *mpMtf;
320 }
321 else
322 {
323 rSubstitute.Clear();
324 }
325
326 if( eOldType != GRAPHIC_NONE )
327 {
328 rSubstitute.SetPrefSize( aPrefSize );
329 rSubstitute.SetPrefMapMode( aPrefMapMode );
330 rSubstitute.SetAnimationNotifyHdl( aAnimationNotifyHdl );
331 rSubstitute.SetDocFileName( aDocFileName, nDocFilePos );
332 }
333
334 if( GFX_LINK_TYPE_NONE != maGfxLink.GetType() )
335 {
336 rSubstitute.SetLink( maGfxLink );
337 }
338
339 if( bDefaultType )
340 {
341 rSubstitute.SetDefaultType();
342 }
343 }
344
345 // -----------------------------------------------------------------------------
346
AddGraphicObjectReference(const GraphicObject & rObj,Graphic & rSubstitute)347 void GraphicCacheEntry::AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute )
348 {
349 if( mbSwappedAll )
350 mbSwappedAll = !ImplInit( rObj );
351
352 ImplFillSubstitute( rSubstitute );
353 maGraphicObjectList.Insert( (void*) &rObj, LIST_APPEND );
354 }
355
356 // -----------------------------------------------------------------------------
357
ReleaseGraphicObjectReference(const GraphicObject & rObj)358 sal_Bool GraphicCacheEntry::ReleaseGraphicObjectReference( const GraphicObject& rObj )
359 {
360 sal_Bool bRet = sal_False;
361
362 for( void* pObj = maGraphicObjectList.First(); !bRet && pObj; pObj = maGraphicObjectList.Next() )
363 {
364 if( &rObj == (GraphicObject*) pObj )
365 {
366 maGraphicObjectList.Remove( pObj );
367 bRet = sal_True;
368 }
369 }
370
371 return bRet;
372 }
373
374 // -----------------------------------------------------------------------------
375
HasGraphicObjectReference(const GraphicObject & rObj)376 sal_Bool GraphicCacheEntry::HasGraphicObjectReference( const GraphicObject& rObj )
377 {
378 sal_Bool bRet = sal_False;
379
380 for( void* pObj = maGraphicObjectList.First(); !bRet && pObj; pObj = maGraphicObjectList.Next() )
381 if( &rObj == (GraphicObject*) pObj )
382 bRet = sal_True;
383
384 return bRet;
385 }
386
387 // -----------------------------------------------------------------------------
388
TryToSwapIn()389 void GraphicCacheEntry::TryToSwapIn()
390 {
391 if( mbSwappedAll && maGraphicObjectList.Count() )
392 ( (GraphicObject*) maGraphicObjectList.First() )->FireSwapInRequest();
393 }
394
395 // -----------------------------------------------------------------------------
396
GraphicObjectWasSwappedOut(const GraphicObject &)397 void GraphicCacheEntry::GraphicObjectWasSwappedOut( const GraphicObject& /*rObj*/ )
398 {
399 mbSwappedAll = sal_True;
400
401 for( void* pObj = maGraphicObjectList.First(); mbSwappedAll && pObj; pObj = maGraphicObjectList.Next() )
402 if( !( (GraphicObject*) pObj )->IsSwappedOut() )
403 mbSwappedAll = sal_False;
404
405 if( mbSwappedAll )
406 {
407 delete mpBmpEx, mpBmpEx = NULL;
408 delete mpMtf, mpMtf = NULL;
409 delete mpAnimation, mpAnimation = NULL;
410
411 // #119176# also reset SvgData
412 maSvgData.reset();
413 }
414 }
415
416 // -----------------------------------------------------------------------------
417
FillSwappedGraphicObject(const GraphicObject & rObj,Graphic & rSubstitute)418 sal_Bool GraphicCacheEntry::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
419 {
420 sal_Bool bRet;
421
422 if( !mbSwappedAll && rObj.IsSwappedOut() )
423 {
424 ImplFillSubstitute( rSubstitute );
425 bRet = sal_True;
426 }
427 else
428 bRet = sal_False;
429
430 return bRet;
431 }
432
433 // -----------------------------------------------------------------------------
434
GraphicObjectWasSwappedIn(const GraphicObject & rObj)435 void GraphicCacheEntry::GraphicObjectWasSwappedIn( const GraphicObject& rObj )
436 {
437 if( mbSwappedAll )
438 mbSwappedAll = !ImplInit( rObj );
439 }
440
441 // ----------------------------
442 // - GraphicDisplayCacheEntry -
443 // ----------------------------
444
445 class GraphicDisplayCacheEntry
446 {
447 private:
448
449 ::vos::TTimeValue maReleaseTime;
450 const GraphicCacheEntry* mpRefCacheEntry;
451 GDIMetaFile* mpMtf;
452 BitmapEx* mpBmpEx;
453 GraphicAttr maAttr;
454 Size maOutSizePix;
455 sal_uLong mnCacheSize;
456 sal_uLong mnOutDevDrawMode;
457 sal_uInt16 mnOutDevBitCount;
458
459 public:
460
461 static sal_uLong GetNeededSize( OutputDevice* pOut, const Point& rPt, const Size& rSz,
462 const GraphicObject& rObj, const GraphicAttr& rAttr );
463
464 public:
465
GraphicDisplayCacheEntry(const GraphicCacheEntry * pRefCacheEntry,OutputDevice * pOut,const Point & rPt,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr,const BitmapEx & rBmpEx)466 GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry,
467 OutputDevice* pOut, const Point& rPt, const Size& rSz,
468 const GraphicObject& rObj, const GraphicAttr& rAttr,
469 const BitmapEx& rBmpEx ) :
470 mpRefCacheEntry( pRefCacheEntry ),
471 mpMtf( NULL ), mpBmpEx( new BitmapEx( rBmpEx ) ),
472 maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ),
473 mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ),
474 mnOutDevDrawMode( pOut->GetDrawMode() ),
475 mnOutDevBitCount( pOut->GetBitCount() )
476 {
477 }
478
GraphicDisplayCacheEntry(const GraphicCacheEntry * pRefCacheEntry,OutputDevice * pOut,const Point & rPt,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr,const GDIMetaFile & rMtf)479 GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry,
480 OutputDevice* pOut, const Point& rPt, const Size& rSz,
481 const GraphicObject& rObj, const GraphicAttr& rAttr,
482 const GDIMetaFile& rMtf ) :
483 mpRefCacheEntry( pRefCacheEntry ),
484 mpMtf( new GDIMetaFile( rMtf ) ), mpBmpEx( NULL ),
485 maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ),
486 mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ),
487 mnOutDevDrawMode( pOut->GetDrawMode() ),
488 mnOutDevBitCount( pOut->GetBitCount() )
489 {
490 }
491
492
493 ~GraphicDisplayCacheEntry();
494
GetAttr() const495 const GraphicAttr& GetAttr() const { return maAttr; }
GetOutputSizePixel() const496 const Size& GetOutputSizePixel() const { return maOutSizePix; }
GetCacheSize() const497 sal_uLong GetCacheSize() const { return mnCacheSize; }
GetReferencedCacheEntry() const498 const GraphicCacheEntry* GetReferencedCacheEntry() const { return mpRefCacheEntry; }
GetOutDevDrawMode() const499 sal_uLong GetOutDevDrawMode() const { return mnOutDevDrawMode; }
GetOutDevBitCount() const500 sal_uInt16 GetOutDevBitCount() const { return mnOutDevBitCount; }
501
SetReleaseTime(const::vos::TTimeValue & rReleaseTime)502 void SetReleaseTime( const ::vos::TTimeValue& rReleaseTime ) { maReleaseTime = rReleaseTime; }
GetReleaseTime() const503 const ::vos::TTimeValue& GetReleaseTime() const { return maReleaseTime; }
504
Matches(OutputDevice * pOut,const Point &,const Size & rSzPixel,const GraphicCacheEntry * pCacheEntry,const GraphicAttr & rAttr) const505 sal_Bool Matches( OutputDevice* pOut, const Point& /*rPtPixel*/, const Size& rSzPixel,
506 const GraphicCacheEntry* pCacheEntry, const GraphicAttr& rAttr ) const
507 {
508 // #i46805# Additional match
509 // criteria: outdev draw mode and
510 // bit count. One cannot reuse
511 // this cache object, if it's
512 // e.g. generated for
513 // DRAWMODE_GRAYBITMAP.
514 return( ( pCacheEntry == mpRefCacheEntry ) &&
515 ( maAttr == rAttr ) &&
516 ( ( maOutSizePix == rSzPixel ) || ( !maOutSizePix.Width() && !maOutSizePix.Height() ) ) &&
517 ( pOut->GetBitCount() == mnOutDevBitCount ) &&
518 ( pOut->GetDrawMode() == mnOutDevDrawMode ) );
519 }
520
521 void Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const;
522 };
523
524 // -----------------------------------------------------------------------------
525
GetNeededSize(OutputDevice * pOut,const Point &,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr)526 sal_uLong GraphicDisplayCacheEntry::GetNeededSize( OutputDevice* pOut, const Point& /*rPt*/, const Size& rSz,
527 const GraphicObject& rObj, const GraphicAttr& rAttr )
528 {
529 const Graphic& rGraphic = rObj.GetGraphic();
530 const GraphicType eType = rGraphic.GetType();
531 sal_uLong nNeededSize;
532
533 if( GRAPHIC_BITMAP == eType )
534 {
535 const Size aOutSizePix( pOut->LogicToPixel( rSz ) );
536 const long nBitCount = pOut->GetBitCount();
537
538 if( ( aOutSizePix.Width() > MAX_BMP_EXTENT ) ||
539 ( aOutSizePix.Height() > MAX_BMP_EXTENT ) )
540 {
541 nNeededSize = ULONG_MAX;
542 }
543 else if( nBitCount )
544 {
545 nNeededSize = aOutSizePix.Width() * aOutSizePix.Height() * nBitCount / 8;
546
547 if( rObj.IsTransparent() || ( rAttr.GetRotation() % 3600 ) )
548 nNeededSize += nNeededSize / nBitCount;
549 }
550 else
551 {
552 DBG_ERROR( "GraphicDisplayCacheEntry::GetNeededSize(): pOut->GetBitCount() == 0" );
553 nNeededSize = 256000;
554 }
555 }
556 else if( GRAPHIC_GDIMETAFILE == eType )
557 nNeededSize = rGraphic.GetSizeBytes();
558 else
559 nNeededSize = 0;
560
561 return nNeededSize;
562 }
563
564 // -----------------------------------------------------------------------------
565
~GraphicDisplayCacheEntry()566 GraphicDisplayCacheEntry::~GraphicDisplayCacheEntry()
567 {
568 if( mpMtf )
569 delete mpMtf;
570
571 if( mpBmpEx )
572 delete mpBmpEx;
573 }
574
575 // -----------------------------------------------------------------------------
576
Draw(OutputDevice * pOut,const Point & rPt,const Size & rSz) const577 void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const
578 {
579 if( mpMtf )
580 GraphicManager::ImplDraw( pOut, rPt, rSz, *mpMtf, maAttr );
581 else if( mpBmpEx )
582 {
583 if( maAttr.IsRotated() )
584 {
585 Polygon aPoly( Rectangle( rPt, rSz ) );
586
587 aPoly.Rotate( rPt, maAttr.GetRotation() % 3600 );
588 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
589 pOut->DrawBitmapEx( aRotBoundRect.TopLeft(), aRotBoundRect.GetSize(), *mpBmpEx );
590 }
591 else
592 pOut->DrawBitmapEx( rPt, rSz, *mpBmpEx );
593 }
594 }
595
596 // -----------------------
597 // - GraphicCache -
598 // -----------------------
599
GraphicCache(GraphicManager & rMgr,sal_uLong nDisplayCacheSize,sal_uLong nMaxObjDisplayCacheSize)600 GraphicCache::GraphicCache( GraphicManager& rMgr, sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) :
601 mrMgr ( rMgr ),
602 mnReleaseTimeoutSeconds ( 0UL ),
603 mnMaxDisplaySize ( nDisplayCacheSize ),
604 mnMaxObjDisplaySize ( nMaxObjDisplayCacheSize ),
605 mnUsedDisplaySize ( 0UL )
606 {
607 maReleaseTimer.SetTimeoutHdl( LINK( this, GraphicCache, ReleaseTimeoutHdl ) );
608 maReleaseTimer.SetTimeout( RELEASE_TIMEOUT );
609 maReleaseTimer.Start();
610 }
611
612 // -----------------------------------------------------------------------------
613
~GraphicCache()614 GraphicCache::~GraphicCache()
615 {
616 DBG_ASSERT( !maGraphicCache.Count(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in cache" );
617 DBG_ASSERT( !maDisplayCache.Count(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in display cache" );
618 }
619
620 // -----------------------------------------------------------------------------
621
AddGraphicObject(const GraphicObject & rObj,Graphic & rSubstitute,const ByteString * pID,const GraphicObject * pCopyObj)622 void GraphicCache::AddGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute,
623 const ByteString* pID, const GraphicObject* pCopyObj )
624 {
625 sal_Bool bInserted = sal_False;
626
627 if( !rObj.IsSwappedOut() &&
628 ( pID || ( pCopyObj && ( pCopyObj->GetType() != GRAPHIC_NONE ) ) || ( rObj.GetType() != GRAPHIC_NONE ) ) )
629 {
630 if( pCopyObj )
631 {
632 GraphicCacheEntry* pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() );
633
634 while( !bInserted && pEntry )
635 {
636 if( pEntry->HasGraphicObjectReference( *pCopyObj ) )
637 {
638 pEntry->AddGraphicObjectReference( rObj, rSubstitute );
639 bInserted = sal_True;
640 }
641 else
642 {
643 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() );
644 }
645 }
646 }
647
648 if( !bInserted )
649 {
650 GraphicCacheEntry* pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() );
651 ::std::auto_ptr< GraphicID > apID;
652
653 if( !pID )
654 {
655 apID.reset( new GraphicID( rObj ) );
656 }
657
658 while( !bInserted && pEntry )
659 {
660 const GraphicID& rEntryID = pEntry->GetID();
661
662 if( pID )
663 {
664 if( rEntryID.GetIDString() == *pID )
665 {
666 pEntry->TryToSwapIn();
667
668 // since pEntry->TryToSwapIn can modify our current list, we have to
669 // iterate from beginning to add a reference to the appropriate
670 // CacheEntry object; after this, quickly jump out of the outer iteration
671 for( pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() );
672 !bInserted && pEntry;
673 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ) )
674 {
675 const GraphicID& rID = pEntry->GetID();
676
677 if( rID.GetIDString() == *pID )
678 {
679 pEntry->AddGraphicObjectReference( rObj, rSubstitute );
680 bInserted = sal_True;
681 }
682 }
683
684 if( !bInserted )
685 {
686 maGraphicCache.Insert( new GraphicCacheEntry( rObj ), LIST_APPEND );
687 bInserted = sal_True;
688 }
689 }
690 }
691 else
692 {
693 if( rEntryID == *apID )
694 {
695 pEntry->AddGraphicObjectReference( rObj, rSubstitute );
696 bInserted = sal_True;
697 }
698 }
699
700 if( !bInserted )
701 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() );
702 }
703 }
704 }
705
706 if( !bInserted )
707 maGraphicCache.Insert( new GraphicCacheEntry( rObj ), LIST_APPEND );
708 }
709
710 // -----------------------------------------------------------------------------
711
ReleaseGraphicObject(const GraphicObject & rObj)712 void GraphicCache::ReleaseGraphicObject( const GraphicObject& rObj )
713 {
714 // Release cached object
715 GraphicCacheEntry* pEntry = (GraphicCacheEntry*) maGraphicCache.First();
716 sal_Bool bRemoved = sal_False;
717
718 while( !bRemoved && pEntry )
719 {
720 bRemoved = pEntry->ReleaseGraphicObjectReference( rObj );
721
722 if( bRemoved )
723 {
724 if( 0 == pEntry->GetGraphicObjectReferenceCount() )
725 {
726 // if graphic cache entry has no more references,
727 // the corresponding display cache object can be removed
728 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First();
729
730 while( pDisplayEntry )
731 {
732 if( pDisplayEntry->GetReferencedCacheEntry() == pEntry )
733 {
734 mnUsedDisplaySize -= pDisplayEntry->GetCacheSize();
735 maDisplayCache.Remove( pDisplayEntry );
736 delete pDisplayEntry;
737 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject();
738 }
739 else
740 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next();
741 }
742
743 // delete graphic cache entry
744 maGraphicCache.Remove( (void*) pEntry );
745 delete pEntry;
746 }
747 }
748 else
749 pEntry = (GraphicCacheEntry*) maGraphicCache.Next();
750 }
751
752 DBG_ASSERT( bRemoved, "GraphicCache::ReleaseGraphicObject(...): GraphicObject not found in cache" );
753 }
754
755 // -----------------------------------------------------------------------------
756
GraphicObjectWasSwappedOut(const GraphicObject & rObj)757 void GraphicCache::GraphicObjectWasSwappedOut( const GraphicObject& rObj )
758 {
759 // notify cache that rObj is swapped out (and can thus be pruned
760 // from the cache)
761 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
762
763 if( pEntry )
764 pEntry->GraphicObjectWasSwappedOut( rObj );
765 }
766
767 // -----------------------------------------------------------------------------
768
FillSwappedGraphicObject(const GraphicObject & rObj,Graphic & rSubstitute)769 sal_Bool GraphicCache::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
770 {
771 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
772
773 if( !pEntry )
774 return sal_False;
775
776 return pEntry->FillSwappedGraphicObject( rObj, rSubstitute );
777 }
778
779 // -----------------------------------------------------------------------------
780
GraphicObjectWasSwappedIn(const GraphicObject & rObj)781 void GraphicCache::GraphicObjectWasSwappedIn( const GraphicObject& rObj )
782 {
783 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
784
785 if( pEntry )
786 {
787 if( pEntry->GetID().IsEmpty() )
788 {
789 ReleaseGraphicObject( rObj );
790 AddGraphicObject( rObj, (Graphic&) rObj.GetGraphic(), NULL, NULL );
791 }
792 else
793 pEntry->GraphicObjectWasSwappedIn( rObj );
794 }
795 }
796
797 // -----------------------------------------------------------------------------
798
SetMaxDisplayCacheSize(sal_uLong nNewCacheSize)799 void GraphicCache::SetMaxDisplayCacheSize( sal_uLong nNewCacheSize )
800 {
801 mnMaxDisplaySize = nNewCacheSize;
802
803 if( GetMaxDisplayCacheSize() < GetUsedDisplayCacheSize() )
804 ImplFreeDisplayCacheSpace( GetUsedDisplayCacheSize() - GetMaxDisplayCacheSize() );
805 }
806
807 // -----------------------------------------------------------------------------
808
SetMaxObjDisplayCacheSize(sal_uLong nNewMaxObjSize,sal_Bool bDestroyGreaterCached)809 void GraphicCache::SetMaxObjDisplayCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached )
810 {
811 const sal_Bool bDestroy = ( bDestroyGreaterCached && ( nNewMaxObjSize < mnMaxObjDisplaySize ) );
812
813 mnMaxObjDisplaySize = Min( nNewMaxObjSize, mnMaxDisplaySize );
814
815 if( bDestroy )
816 {
817 GraphicDisplayCacheEntry* pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.First();
818
819 while( pCacheObj )
820 {
821 if( pCacheObj->GetCacheSize() > mnMaxObjDisplaySize )
822 {
823 mnUsedDisplaySize -= pCacheObj->GetCacheSize();
824 maDisplayCache.Remove( pCacheObj );
825 delete pCacheObj;
826 pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject();
827 }
828 else
829 pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.Next();
830 }
831 }
832 }
833
834 // -----------------------------------------------------------------------------
835
SetCacheTimeout(sal_uLong nTimeoutSeconds)836 void GraphicCache::SetCacheTimeout( sal_uLong nTimeoutSeconds )
837 {
838 if( mnReleaseTimeoutSeconds != nTimeoutSeconds )
839 {
840 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First();
841 ::vos::TTimeValue aReleaseTime;
842
843 if( ( mnReleaseTimeoutSeconds = nTimeoutSeconds ) != 0 )
844 {
845 osl_getSystemTime( &aReleaseTime );
846 aReleaseTime.addTime( ::vos::TTimeValue( nTimeoutSeconds, 0 ) );
847 }
848
849 while( pDisplayEntry )
850 {
851 pDisplayEntry->SetReleaseTime( aReleaseTime );
852 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next();
853 }
854 }
855 }
856
857 // -----------------------------------------------------------------------------
858
ClearDisplayCache()859 void GraphicCache::ClearDisplayCache()
860 {
861 for( void* pObj = maDisplayCache.First(); pObj; pObj = maDisplayCache.Next() )
862 delete (GraphicDisplayCacheEntry*) pObj;
863
864 maDisplayCache.Clear();
865 mnUsedDisplaySize = 0UL;
866 }
867
868 // -----------------------------------------------------------------------------
869
IsDisplayCacheable(OutputDevice * pOut,const Point & rPt,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr) const870 sal_Bool GraphicCache::IsDisplayCacheable( OutputDevice* pOut, const Point& rPt, const Size& rSz,
871 const GraphicObject& rObj, const GraphicAttr& rAttr ) const
872 {
873 return( GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) <=
874 GetMaxObjDisplayCacheSize() );
875 }
876
877 // -----------------------------------------------------------------------------
878
IsInDisplayCache(OutputDevice * pOut,const Point & rPt,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr) const879 sal_Bool GraphicCache::IsInDisplayCache( OutputDevice* pOut, const Point& rPt, const Size& rSz,
880 const GraphicObject& rObj, const GraphicAttr& rAttr ) const
881 {
882 const Point aPtPixel( pOut->LogicToPixel( rPt ) );
883 const Size aSzPixel( pOut->LogicToPixel( rSz ) );
884 const GraphicCacheEntry* pCacheEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
885 //GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) ( (GraphicCache*) this )->maDisplayCache.First(); // -Wall removed ....
886 sal_Bool bFound = sal_False;
887
888 if( pCacheEntry )
889 {
890 for( long i = 0, nCount = maDisplayCache.Count(); !bFound && ( i < nCount ); i++ )
891 if( ( (GraphicDisplayCacheEntry*) maDisplayCache.GetObject( i ) )->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) )
892 bFound = sal_True;
893 }
894
895 return bFound;
896 }
897
898 // -----------------------------------------------------------------------------
899
GetUniqueID(const GraphicObject & rObj) const900 ByteString GraphicCache::GetUniqueID( const GraphicObject& rObj ) const
901 {
902 ByteString aRet;
903 GraphicCacheEntry* pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
904
905 // ensure that the entry is correctly initialized (it has to be read at least once)
906 if( pEntry && pEntry->GetID().IsEmpty() )
907 pEntry->TryToSwapIn();
908
909 // do another call to ImplGetCacheEntry in case of modified entry list
910 pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
911
912 if( pEntry )
913 aRet = pEntry->GetID().GetIDString();
914
915 return aRet;
916 }
917
918 // -----------------------------------------------------------------------------
919
CreateDisplayCacheObj(OutputDevice * pOut,const Point & rPt,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr,const BitmapEx & rBmpEx)920 sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
921 const GraphicObject& rObj, const GraphicAttr& rAttr,
922 const BitmapEx& rBmpEx )
923 {
924 const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr );
925 sal_Bool bRet = sal_False;
926
927 if( nNeededSize <= GetMaxObjDisplayCacheSize() )
928 {
929 if( nNeededSize > GetFreeDisplayCacheSize() )
930 ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() );
931
932 GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ),
933 pOut, rPt, rSz, rObj, rAttr, rBmpEx );
934
935 if( GetCacheTimeout() )
936 {
937 ::vos::TTimeValue aReleaseTime;
938
939 osl_getSystemTime( &aReleaseTime );
940 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) );
941 pNewEntry->SetReleaseTime( aReleaseTime );
942 }
943
944 maDisplayCache.Insert( pNewEntry, LIST_APPEND );
945 mnUsedDisplaySize += pNewEntry->GetCacheSize();
946 bRet = sal_True;
947 }
948
949 return bRet;
950 }
951
952 // -----------------------------------------------------------------------------
953
CreateDisplayCacheObj(OutputDevice * pOut,const Point & rPt,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr,const GDIMetaFile & rMtf)954 sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
955 const GraphicObject& rObj, const GraphicAttr& rAttr,
956 const GDIMetaFile& rMtf )
957 {
958 const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr );
959 sal_Bool bRet = sal_False;
960
961 if( nNeededSize <= GetMaxObjDisplayCacheSize() )
962 {
963 if( nNeededSize > GetFreeDisplayCacheSize() )
964 ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() );
965
966 GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ),
967 pOut, rPt, rSz, rObj, rAttr, rMtf );
968
969 if( GetCacheTimeout() )
970 {
971 ::vos::TTimeValue aReleaseTime;
972
973 osl_getSystemTime( &aReleaseTime );
974 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) );
975 pNewEntry->SetReleaseTime( aReleaseTime );
976 }
977
978 maDisplayCache.Insert( pNewEntry, LIST_APPEND );
979 mnUsedDisplaySize += pNewEntry->GetCacheSize();
980 bRet = sal_True;
981 }
982
983 return bRet;
984 }
985
986 // -----------------------------------------------------------------------------
987
DrawDisplayCacheObj(OutputDevice * pOut,const Point & rPt,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr)988 sal_Bool GraphicCache::DrawDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
989 const GraphicObject& rObj, const GraphicAttr& rAttr )
990 {
991 const Point aPtPixel( pOut->LogicToPixel( rPt ) );
992 const Size aSzPixel( pOut->LogicToPixel( rSz ) );
993 const GraphicCacheEntry* pCacheEntry = ImplGetCacheEntry( rObj );
994 GraphicDisplayCacheEntry* pDisplayCacheEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First();
995 sal_Bool bRet = sal_False;
996
997 while( !bRet && pDisplayCacheEntry )
998 {
999 if( pDisplayCacheEntry->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) )
1000 {
1001 ::vos::TTimeValue aReleaseTime;
1002
1003 // put found object at last used position
1004 maDisplayCache.Insert( maDisplayCache.Remove( pDisplayCacheEntry ), LIST_APPEND );
1005
1006 if( GetCacheTimeout() )
1007 {
1008 osl_getSystemTime( &aReleaseTime );
1009 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) );
1010 }
1011
1012 pDisplayCacheEntry->SetReleaseTime( aReleaseTime );
1013 bRet = sal_True;
1014 }
1015 else
1016 pDisplayCacheEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next();
1017 }
1018
1019 if( bRet )
1020 pDisplayCacheEntry->Draw( pOut, rPt, rSz );
1021
1022 return bRet;
1023 }
1024
1025 // -----------------------------------------------------------------------------
1026
ImplFreeDisplayCacheSpace(sal_uLong nSizeToFree)1027 sal_Bool GraphicCache::ImplFreeDisplayCacheSpace( sal_uLong nSizeToFree )
1028 {
1029 sal_uLong nFreedSize = 0UL;
1030
1031 if( nSizeToFree )
1032 {
1033 void* pObj = maDisplayCache.First();
1034
1035 if( nSizeToFree > mnUsedDisplaySize )
1036 nSizeToFree = mnUsedDisplaySize;
1037
1038 while( pObj )
1039 {
1040 GraphicDisplayCacheEntry* pCacheObj = (GraphicDisplayCacheEntry*) pObj;
1041
1042 nFreedSize += pCacheObj->GetCacheSize();
1043 mnUsedDisplaySize -= pCacheObj->GetCacheSize();
1044 maDisplayCache.Remove( pObj );
1045 delete pCacheObj;
1046
1047 if( nFreedSize >= nSizeToFree )
1048 break;
1049 else
1050 pObj = maDisplayCache.GetCurObject();
1051 }
1052 }
1053
1054 return( nFreedSize >= nSizeToFree );
1055 }
1056
1057 // -----------------------------------------------------------------------------
1058
ImplGetCacheEntry(const GraphicObject & rObj)1059 GraphicCacheEntry* GraphicCache::ImplGetCacheEntry( const GraphicObject& rObj )
1060 {
1061 GraphicCacheEntry* pRet = NULL;
1062
1063 for( void* pObj = maGraphicCache.First(); !pRet && pObj; pObj = maGraphicCache.Next() )
1064 if( ( (GraphicCacheEntry*) pObj )->HasGraphicObjectReference( rObj ) )
1065 pRet = (GraphicCacheEntry*) pObj;
1066
1067 return pRet;
1068 }
1069
1070 // -----------------------------------------------------------------------------
1071
IMPL_LINK(GraphicCache,ReleaseTimeoutHdl,Timer *,pTimer)1072 IMPL_LINK( GraphicCache, ReleaseTimeoutHdl, Timer*, pTimer )
1073 {
1074 pTimer->Stop();
1075
1076 ::vos::TTimeValue aCurTime;
1077 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First();
1078
1079 osl_getSystemTime( &aCurTime );
1080
1081 while( pDisplayEntry )
1082 {
1083 const ::vos::TTimeValue& rReleaseTime = pDisplayEntry->GetReleaseTime();
1084
1085 if( !rReleaseTime.isEmpty() && ( rReleaseTime < aCurTime ) )
1086 {
1087 mnUsedDisplaySize -= pDisplayEntry->GetCacheSize();
1088 maDisplayCache.Remove( pDisplayEntry );
1089 delete pDisplayEntry;
1090 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject();
1091 }
1092 else
1093 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next();
1094 }
1095
1096 pTimer->Start();
1097
1098 return 0;
1099 }
1100