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