update credits
[LibreOffice.git] / svtools / source / graphic / grfmgr.cxx
blob9f14f3da3877ed18ba7da9580e8919f432466b20
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "sal/config.h"
22 #include <algorithm>
24 #include <officecfg/Office/Common.hxx>
25 #include <tools/vcompat.hxx>
26 #include <tools/helpers.hxx>
27 #include <unotools/ucbstreamhelper.hxx>
28 #include <unotools/localfilehelper.hxx>
29 #include <unotools/tempfile.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/cvtgrf.hxx>
32 #include <vcl/metaact.hxx>
33 #include <vcl/virdev.hxx>
34 #include <svtools/grfmgr.hxx>
36 #include <vcl/pdfextoutdevdata.hxx>
38 #include <com/sun/star/container/XNameContainer.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
41 using com::sun::star::uno::Reference;
42 using com::sun::star::uno::XInterface;
43 using com::sun::star::uno::UNO_QUERY;
44 using com::sun::star::uno::Sequence;
45 using com::sun::star::container::XNameContainer;
46 using com::sun::star::beans::XPropertySet;
48 GraphicManager* GraphicObject::mpGlobalMgr = NULL;
50 struct GrfSimpleCacheObj
52 Graphic maGraphic;
53 GraphicAttr maAttr;
55 GrfSimpleCacheObj( const Graphic& rGraphic, const GraphicAttr& rAttr ) :
56 maGraphic( rGraphic ), maAttr( rAttr ) {}
59 TYPEINIT1_AUTOFACTORY( GraphicObject, SvDataCopyStream );
61 GraphicObject::GraphicObject( const GraphicManager* pMgr ) :
62 mpLink ( NULL ),
63 mpUserData ( NULL )
65 ImplConstruct();
66 ImplAssignGraphicData();
67 ImplSetGraphicManager( pMgr );
70 GraphicObject::GraphicObject( const Graphic& rGraphic, const GraphicManager* pMgr ) :
71 maGraphic ( rGraphic ),
72 mpLink ( NULL ),
73 mpUserData ( NULL )
75 ImplConstruct();
76 ImplAssignGraphicData();
77 ImplSetGraphicManager( pMgr );
80 GraphicObject::GraphicObject( const GraphicObject& rGraphicObj, const GraphicManager* pMgr ) :
81 SvDataCopyStream(),
82 maGraphic ( rGraphicObj.GetGraphic() ),
83 maAttr ( rGraphicObj.maAttr ),
84 mpLink ( rGraphicObj.mpLink ? ( new String( *rGraphicObj.mpLink ) ) : NULL ),
85 mpUserData ( rGraphicObj.mpUserData ? ( new String( *rGraphicObj.mpUserData ) ) : NULL )
87 ImplConstruct();
88 ImplAssignGraphicData();
89 ImplSetGraphicManager( pMgr, NULL, &rGraphicObj );
92 GraphicObject::GraphicObject( const OString& rUniqueID, const GraphicManager* pMgr ) :
93 mpLink ( NULL ),
94 mpUserData ( NULL )
96 ImplConstruct();
98 // assign default properties
99 ImplAssignGraphicData();
101 ImplSetGraphicManager( pMgr, &rUniqueID );
103 // update properties
104 ImplAssignGraphicData();
107 GraphicObject::~GraphicObject()
109 if( mpMgr )
111 mpMgr->ImplUnregisterObj( *this );
113 if( ( mpMgr == mpGlobalMgr ) && !mpGlobalMgr->ImplHasObjects() )
114 delete mpGlobalMgr, mpGlobalMgr = NULL;
117 delete mpSwapOutTimer;
118 delete mpSwapStreamHdl;
119 delete mpLink;
120 delete mpUserData;
121 delete mpSimpleCache;
124 void GraphicObject::ImplConstruct()
126 mpMgr = NULL;
127 mpSwapStreamHdl = NULL;
128 mpSwapOutTimer = NULL;
129 mpSimpleCache = NULL;
130 mnAnimationLoopCount = 0;
131 mbAutoSwapped = sal_False;
132 mbIsInSwapIn = sal_False;
133 mbIsInSwapOut = sal_False;
136 void GraphicObject::ImplAssignGraphicData()
138 maPrefSize = maGraphic.GetPrefSize();
139 maPrefMapMode = maGraphic.GetPrefMapMode();
140 mnSizeBytes = maGraphic.GetSizeBytes();
141 meType = maGraphic.GetType();
142 mbTransparent = maGraphic.IsTransparent();
143 mbAlpha = maGraphic.IsAlpha();
144 mbAnimated = maGraphic.IsAnimated();
145 mbEPS = maGraphic.IsEPS();
146 mnAnimationLoopCount = ( mbAnimated ? maGraphic.GetAnimationLoopCount() : 0 );
149 void GraphicObject::ImplSetGraphicManager( const GraphicManager* pMgr, const OString* pID, const GraphicObject* pCopyObj )
151 if( !mpMgr || ( pMgr != mpMgr ) )
153 if( !pMgr && mpMgr && ( mpMgr == mpGlobalMgr ) )
154 return;
155 else
157 if( mpMgr )
159 mpMgr->ImplUnregisterObj( *this );
161 if( ( mpMgr == mpGlobalMgr ) && !mpGlobalMgr->ImplHasObjects() )
162 delete mpGlobalMgr, mpGlobalMgr = NULL;
165 if( !pMgr )
167 if( !mpGlobalMgr )
169 mpGlobalMgr = new GraphicManager(
170 (officecfg::Office::Common::Cache::GraphicManager::
171 TotalCacheSize::get()),
172 (officecfg::Office::Common::Cache::GraphicManager::
173 ObjectCacheSize::get()));
174 mpGlobalMgr->SetCacheTimeout(
175 officecfg::Office::Common::Cache::GraphicManager::
176 ObjectReleaseTime::get());
179 mpMgr = mpGlobalMgr;
181 else
182 mpMgr = (GraphicManager*) pMgr;
184 mpMgr->ImplRegisterObj( *this, maGraphic, pID, pCopyObj );
189 void GraphicObject::ImplAutoSwapIn()
191 if( IsSwappedOut() )
193 if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) )
194 mbAutoSwapped = sal_False;
195 else
197 mbIsInSwapIn = sal_True;
199 if( maGraphic.SwapIn() )
200 mbAutoSwapped = sal_False;
201 else
203 SvStream* pStream = GetSwapStream();
205 if( GRFMGR_AUTOSWAPSTREAM_NONE != pStream )
207 if( GRFMGR_AUTOSWAPSTREAM_LINK == pStream )
209 if( HasLink() )
211 OUString aURLStr;
213 if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( GetLink(), aURLStr ) )
215 SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( aURLStr, STREAM_READ );
217 if( pIStm )
219 (*pIStm) >> maGraphic;
220 mbAutoSwapped = ( maGraphic.GetType() != GRAPHIC_NONE );
221 delete pIStm;
226 else if( GRFMGR_AUTOSWAPSTREAM_TEMP == pStream )
227 mbAutoSwapped = !maGraphic.SwapIn();
228 else if( GRFMGR_AUTOSWAPSTREAM_LOADED == pStream )
229 mbAutoSwapped = maGraphic.IsSwapOut();
230 else
232 mbAutoSwapped = !maGraphic.SwapIn( pStream );
233 delete pStream;
236 else
238 DBG_ASSERT( ( GRAPHIC_NONE == meType ) || ( GRAPHIC_DEFAULT == meType ),
239 "GraphicObject::ImplAutoSwapIn: could not get stream to swap in graphic! (=>KA)" );
243 mbIsInSwapIn = sal_False;
245 if( !mbAutoSwapped && mpMgr )
246 mpMgr->ImplGraphicObjectWasSwappedIn( *this );
251 sal_Bool GraphicObject::ImplGetCropParams( OutputDevice* pOut, Point& rPt, Size& rSz, const GraphicAttr* pAttr,
252 PolyPolygon& rClipPolyPoly, sal_Bool& bRectClipRegion ) const
254 sal_Bool bRet = sal_False;
256 if( GetType() != GRAPHIC_NONE )
258 Polygon aClipPoly( Rectangle( rPt, rSz ) );
259 const sal_uInt16 nRot10 = pAttr->GetRotation() % 3600;
260 const Point aOldOrigin( rPt );
261 const MapMode aMap100( MAP_100TH_MM );
262 Size aSize100;
263 long nTotalWidth, nTotalHeight;
265 if( nRot10 )
267 aClipPoly.Rotate( rPt, nRot10 );
268 bRectClipRegion = sal_False;
270 else
271 bRectClipRegion = sal_True;
273 rClipPolyPoly = aClipPoly;
275 if( maGraphic.GetPrefMapMode() == MAP_PIXEL )
276 aSize100 = Application::GetDefaultDevice()->PixelToLogic( maGraphic.GetPrefSize(), aMap100 );
277 else
279 MapMode m(maGraphic.GetPrefMapMode());
280 aSize100 = pOut->LogicToLogic( maGraphic.GetPrefSize(), &m, &aMap100 );
283 nTotalWidth = aSize100.Width() - pAttr->GetLeftCrop() - pAttr->GetRightCrop();
284 nTotalHeight = aSize100.Height() - pAttr->GetTopCrop() - pAttr->GetBottomCrop();
286 if( aSize100.Width() > 0 && aSize100.Height() > 0 && nTotalWidth > 0 && nTotalHeight > 0 )
288 double fScale = (double) aSize100.Width() / nTotalWidth;
289 const long nNewLeft = -FRound( ( ( pAttr->GetMirrorFlags() & BMP_MIRROR_HORZ ) ? pAttr->GetRightCrop() : pAttr->GetLeftCrop() ) * fScale );
290 const long nNewRight = nNewLeft + FRound( aSize100.Width() * fScale ) - 1;
292 fScale = (double) rSz.Width() / aSize100.Width();
293 rPt.X() += FRound( nNewLeft * fScale );
294 rSz.Width() = FRound( ( nNewRight - nNewLeft + 1 ) * fScale );
296 fScale = (double) aSize100.Height() / nTotalHeight;
297 const long nNewTop = -FRound( ( ( pAttr->GetMirrorFlags() & BMP_MIRROR_VERT ) ? pAttr->GetBottomCrop() : pAttr->GetTopCrop() ) * fScale );
298 const long nNewBottom = nNewTop + FRound( aSize100.Height() * fScale ) - 1;
300 fScale = (double) rSz.Height() / aSize100.Height();
301 rPt.Y() += FRound( nNewTop * fScale );
302 rSz.Height() = FRound( ( nNewBottom - nNewTop + 1 ) * fScale );
304 if( nRot10 )
306 Polygon aOriginPoly( 1 );
308 aOriginPoly[ 0 ] = rPt;
309 aOriginPoly.Rotate( aOldOrigin, nRot10 );
310 rPt = aOriginPoly[ 0 ];
313 bRet = sal_True;
317 return bRet;
320 GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj )
322 if( &rGraphicObj != this )
324 mpMgr->ImplUnregisterObj( *this );
326 delete mpSwapStreamHdl, mpSwapStreamHdl = NULL;
327 delete mpSimpleCache, mpSimpleCache = NULL;
328 delete mpLink;
329 delete mpUserData;
331 maGraphic = rGraphicObj.GetGraphic();
332 maAttr = rGraphicObj.maAttr;
333 mpLink = rGraphicObj.mpLink ? new String( *rGraphicObj.mpLink ) : NULL;
334 mpUserData = rGraphicObj.mpUserData ? new String( *rGraphicObj.mpUserData ) : NULL;
335 ImplAssignGraphicData();
336 mbAutoSwapped = sal_False;
337 mpMgr = rGraphicObj.mpMgr;
339 mpMgr->ImplRegisterObj( *this, maGraphic, NULL, &rGraphicObj );
342 return *this;
345 sal_Bool GraphicObject::operator==( const GraphicObject& rGraphicObj ) const
347 return( ( rGraphicObj.maGraphic == maGraphic ) &&
348 ( rGraphicObj.maAttr == maAttr ) &&
349 ( rGraphicObj.GetLink() == GetLink() ) );
352 void GraphicObject::Load( SvStream& rIStm )
354 rIStm >> *this;
357 void GraphicObject::Save( SvStream& rOStm )
359 rOStm << *this;
362 void GraphicObject::Assign( const SvDataCopyStream& rCopyStream )
364 *this = (const GraphicObject& ) rCopyStream;
367 OString GraphicObject::GetUniqueID() const
369 if ( !IsInSwapIn() && IsEPS() )
370 const_cast<GraphicObject*>(this)->FireSwapInRequest();
372 OString aRet;
374 if( mpMgr )
375 aRet = mpMgr->ImplGetUniqueID( *this );
377 return aRet;
380 SvStream* GraphicObject::GetSwapStream() const
382 return( HasSwapStreamHdl() ? (SvStream*) mpSwapStreamHdl->Call( (void*) this ) : GRFMGR_AUTOSWAPSTREAM_NONE );
385 void GraphicObject::SetAttr( const GraphicAttr& rAttr )
387 maAttr = rAttr;
389 if( mpSimpleCache && ( mpSimpleCache->maAttr != rAttr ) )
390 delete mpSimpleCache, mpSimpleCache = NULL;
393 void GraphicObject::SetLink()
395 if( mpLink )
396 delete mpLink, mpLink = NULL;
399 void GraphicObject::SetLink( const String& rLink )
401 delete mpLink, mpLink = new String( rLink );
404 String GraphicObject::GetLink() const
406 if( mpLink )
407 return *mpLink;
408 else
409 return String();
412 void GraphicObject::SetUserData()
414 if( mpUserData )
415 delete mpUserData, mpUserData = NULL;
418 void GraphicObject::SetUserData( const String& rUserData )
420 delete mpUserData, mpUserData = new String( rUserData );
423 String GraphicObject::GetUserData() const
425 if( mpUserData )
426 return *mpUserData;
427 else
428 return String();
431 void GraphicObject::SetSwapStreamHdl()
433 if( mpSwapStreamHdl )
435 delete mpSwapOutTimer, mpSwapOutTimer = NULL;
436 delete mpSwapStreamHdl, mpSwapStreamHdl = NULL;
440 void GraphicObject::SetSwapStreamHdl( const Link& rHdl, const sal_uLong nSwapOutTimeout )
442 delete mpSwapStreamHdl, mpSwapStreamHdl = new Link( rHdl );
444 if( nSwapOutTimeout )
446 if( !mpSwapOutTimer )
448 mpSwapOutTimer = new Timer;
449 mpSwapOutTimer->SetTimeoutHdl( LINK( this, GraphicObject, ImplAutoSwapOutHdl ) );
452 mpSwapOutTimer->SetTimeout( nSwapOutTimeout );
453 mpSwapOutTimer->Start();
455 else
456 delete mpSwapOutTimer, mpSwapOutTimer = NULL;
459 void GraphicObject::FireSwapInRequest()
461 ImplAutoSwapIn();
464 void GraphicObject::FireSwapOutRequest()
466 ImplAutoSwapOutHdl( NULL );
469 void GraphicObject::GraphicManagerDestroyed()
471 // we're alive, but our manager doesn't live anymore ==> connect to default manager
472 mpMgr = NULL;
473 ImplSetGraphicManager( NULL );
476 sal_Bool GraphicObject::IsCached( OutputDevice* pOut, const Point& rPt, const Size& rSz,
477 const GraphicAttr* pAttr, sal_uLong nFlags ) const
479 sal_Bool bRet;
481 if( nFlags & GRFMGR_DRAW_CACHED )
483 Point aPt( rPt );
484 Size aSz( rSz );
485 if ( pAttr->IsCropped() )
487 PolyPolygon aClipPolyPoly;
488 sal_Bool bRectClip;
489 ImplGetCropParams( pOut, aPt, aSz, pAttr, aClipPolyPoly, bRectClip );
491 bRet = mpMgr->IsInCache( pOut, aPt, aSz, *this, ( pAttr ? *pAttr : GetAttr() ) );
493 else
494 bRet = sal_False;
496 return bRet;
499 void GraphicObject::ReleaseFromCache()
502 mpMgr->ReleaseFromCache( *this );
505 bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
506 const GraphicAttr* pAttr, sal_uLong nFlags )
508 GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() );
509 Point aPt( rPt );
510 Size aSz( rSz );
511 const sal_uInt32 nOldDrawMode = pOut->GetDrawMode();
512 sal_Bool bCropped = aAttr.IsCropped();
513 sal_Bool bCached = sal_False;
514 bool bRet;
516 // #i29534# Provide output rects for PDF writer
517 Rectangle aCropRect;
519 if( !( GRFMGR_DRAW_USE_DRAWMODE_SETTINGS & nFlags ) )
520 pOut->SetDrawMode( nOldDrawMode & ( ~( DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT ) ) );
522 // mirrored horizontically
523 if( aSz.Width() < 0L )
525 aPt.X() += aSz.Width() + 1;
526 aSz.Width() = -aSz.Width();
527 aAttr.SetMirrorFlags( aAttr.GetMirrorFlags() ^ BMP_MIRROR_HORZ );
530 // mirrored vertically
531 if( aSz.Height() < 0L )
533 aPt.Y() += aSz.Height() + 1;
534 aSz.Height() = -aSz.Height();
535 aAttr.SetMirrorFlags( aAttr.GetMirrorFlags() ^ BMP_MIRROR_VERT );
538 if( bCropped )
540 PolyPolygon aClipPolyPoly;
541 sal_Bool bRectClip;
542 const sal_Bool bCrop = ImplGetCropParams( pOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip );
544 pOut->Push( PUSH_CLIPREGION );
546 if( bCrop )
548 if( bRectClip )
550 // #i29534# Store crop rect for later forwarding to
551 // PDF writer
552 aCropRect = aClipPolyPoly.GetBoundRect();
553 pOut->IntersectClipRegion( aCropRect );
555 else
557 pOut->IntersectClipRegion(Region(aClipPolyPoly));
562 bRet = mpMgr->DrawObj( pOut, aPt, aSz, *this, aAttr, nFlags, bCached );
564 if( bCropped )
565 pOut->Pop();
567 pOut->SetDrawMode( nOldDrawMode );
569 // #i29534# Moved below OutDev restoration, to avoid multiple swap-ins
570 // (code above needs to call GetGraphic twice)
571 if( bCached )
573 if( mpSwapOutTimer )
574 mpSwapOutTimer->Start();
575 else
576 FireSwapOutRequest();
579 return bRet;
582 // #i105243#
583 sal_Bool GraphicObject::DrawWithPDFHandling( OutputDevice& rOutDev,
584 const Point& rPt, const Size& rSz,
585 const GraphicAttr* pGrfAttr,
586 const sal_uLong nFlags )
588 const GraphicAttr aGrfAttr( pGrfAttr ? *pGrfAttr : GetAttr() );
590 // Notify PDF writer about linked graphic (if any)
591 sal_Bool bWritingPdfLinkedGraphic( sal_False );
592 Point aPt( rPt );
593 Size aSz( rSz );
594 Rectangle aCropRect;
595 vcl::PDFExtOutDevData* pPDFExtOutDevData =
596 dynamic_cast<vcl::PDFExtOutDevData*>(rOutDev.GetExtOutDevData());
597 if( pPDFExtOutDevData )
599 // only delegate image handling to PDF, if no special treatment is necessary
600 if( GetGraphic().IsLink() &&
601 rSz.Width() > 0L &&
602 rSz.Height() > 0L &&
603 !aGrfAttr.IsSpecialDrawMode() &&
604 !aGrfAttr.IsMirrored() &&
605 !aGrfAttr.IsRotated() &&
606 !aGrfAttr.IsAdjusted() )
608 bWritingPdfLinkedGraphic = true;
610 if( aGrfAttr.IsCropped() )
612 PolyPolygon aClipPolyPoly;
613 sal_Bool bRectClip;
614 const sal_Bool bCrop = ImplGetCropParams( &rOutDev,
615 aPt, aSz,
616 &aGrfAttr,
617 aClipPolyPoly,
618 bRectClip );
619 if ( bCrop && bRectClip )
621 aCropRect = aClipPolyPoly.GetBoundRect();
625 pPDFExtOutDevData->BeginGroup();
629 sal_Bool bRet = Draw( &rOutDev, rPt, rSz, &aGrfAttr, nFlags );
631 // Notify PDF writer about linked graphic (if any)
632 if( bWritingPdfLinkedGraphic )
634 pPDFExtOutDevData->EndGroup( const_cast< Graphic& >(GetGraphic()),
635 aGrfAttr.GetTransparency(),
636 Rectangle( aPt, aSz ),
637 aCropRect );
640 return bRet;
643 sal_Bool GraphicObject::DrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSize,
644 const Size& rOffset, const GraphicAttr* pAttr, sal_uLong nFlags, int nTileCacheSize1D )
646 if( pOut == NULL || rSize.Width() == 0 || rSize.Height() == 0 )
647 return sal_False;
649 const MapMode aOutMapMode( pOut->GetMapMode() );
650 const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
651 // #106258# Clamp size to 1 for zero values. This is okay, since
652 // logical size of zero is handled above already
653 const Size aOutTileSize( ::std::max( 1L, pOut->LogicToPixel( rSize, aOutMapMode ).Width() ),
654 ::std::max( 1L, pOut->LogicToPixel( rSize, aOutMapMode ).Height() ) );
656 //#i69780 clip final tile size to a sane max size
657 while (((sal_Int64)rSize.Width() * nTileCacheSize1D) > SAL_MAX_UINT16)
658 nTileCacheSize1D /= 2;
659 while (((sal_Int64)rSize.Height() * nTileCacheSize1D) > SAL_MAX_UINT16)
660 nTileCacheSize1D /= 2;
662 return ImplDrawTiled( pOut, rArea, aOutTileSize, rOffset, pAttr, nFlags, nTileCacheSize1D );
665 sal_Bool GraphicObject::StartAnimation( OutputDevice* pOut, const Point& rPt, const Size& rSz,
666 long nExtraData, const GraphicAttr* pAttr, sal_uLong /*nFlags*/,
667 OutputDevice* pFirstFrameOutDev )
669 sal_Bool bRet = sal_False;
671 GetGraphic();
673 if( !IsSwappedOut() )
675 const GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() );
677 if( mbAnimated )
679 Point aPt( rPt );
680 Size aSz( rSz );
681 sal_Bool bCropped = aAttr.IsCropped();
683 if( bCropped )
685 PolyPolygon aClipPolyPoly;
686 sal_Bool bRectClip;
687 const sal_Bool bCrop = ImplGetCropParams( pOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip );
689 pOut->Push( PUSH_CLIPREGION );
691 if( bCrop )
693 if( bRectClip )
694 pOut->IntersectClipRegion( aClipPolyPoly.GetBoundRect() );
695 else
696 pOut->IntersectClipRegion(Region(aClipPolyPoly));
700 if( !mpSimpleCache || ( mpSimpleCache->maAttr != aAttr ) || pFirstFrameOutDev )
702 if( mpSimpleCache )
703 delete mpSimpleCache;
705 mpSimpleCache = new GrfSimpleCacheObj( GetTransformedGraphic( &aAttr ), aAttr );
706 mpSimpleCache->maGraphic.SetAnimationNotifyHdl( GetAnimationNotifyHdl() );
709 mpSimpleCache->maGraphic.StartAnimation( pOut, aPt, aSz, nExtraData, pFirstFrameOutDev );
711 if( bCropped )
712 pOut->Pop();
714 bRet = sal_True;
716 else
717 bRet = Draw( pOut, rPt, rSz, &aAttr, GRFMGR_DRAW_STANDARD );
720 return bRet;
723 void GraphicObject::StopAnimation( OutputDevice* pOut, long nExtraData )
725 if( mpSimpleCache )
726 mpSimpleCache->maGraphic.StopAnimation( pOut, nExtraData );
729 const Graphic& GraphicObject::GetGraphic() const
731 if( mbAutoSwapped )
732 ( (GraphicObject*) this )->ImplAutoSwapIn();
734 return maGraphic;
737 void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pCopyObj )
739 mpMgr->ImplUnregisterObj( *this );
741 if( mpSwapOutTimer )
742 mpSwapOutTimer->Stop();
744 maGraphic = rGraphic;
745 mbAutoSwapped = sal_False;
746 ImplAssignGraphicData();
747 delete mpLink, mpLink = NULL;
748 delete mpSimpleCache, mpSimpleCache = NULL;
750 mpMgr->ImplRegisterObj( *this, maGraphic, 0, pCopyObj);
752 if( mpSwapOutTimer )
753 mpSwapOutTimer->Start();
756 void GraphicObject::SetGraphic( const Graphic& rGraphic, const String& rLink )
758 SetGraphic( rGraphic );
759 mpLink = new String( rLink );
762 Graphic GraphicObject::GetTransformedGraphic( const Size& rDestSize, const MapMode& rDestMap, const GraphicAttr& rAttr ) const
764 // #104550# Extracted from svx/source/svdraw/svdograf.cxx
765 Graphic aTransGraphic( maGraphic );
766 const GraphicType eType = GetType();
767 const Size aSrcSize( aTransGraphic.GetPrefSize() );
769 // #104115# Convert the crop margins to graphic object mapmode
770 const MapMode aMapGraph( aTransGraphic.GetPrefMapMode() );
771 const MapMode aMap100( MAP_100TH_MM );
773 Size aCropLeftTop;
774 Size aCropRightBottom;
776 if( GRAPHIC_GDIMETAFILE == eType )
778 GDIMetaFile aMtf( aTransGraphic.GetGDIMetaFile() );
780 if( aMapGraph == MAP_PIXEL )
782 aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel( Size( rAttr.GetLeftCrop(),
783 rAttr.GetTopCrop() ),
784 aMap100 );
785 aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel( Size( rAttr.GetRightCrop(),
786 rAttr.GetBottomCrop() ),
787 aMap100 );
789 else
791 aCropLeftTop = OutputDevice::LogicToLogic( Size( rAttr.GetLeftCrop(),
792 rAttr.GetTopCrop() ),
793 aMap100,
794 aMapGraph );
795 aCropRightBottom = OutputDevice::LogicToLogic( Size( rAttr.GetRightCrop(),
796 rAttr.GetBottomCrop() ),
797 aMap100,
798 aMapGraph );
801 // #104115# If the metafile is cropped, give it a special
802 // treatment: clip against the remaining area, scale up such
803 // that this area later fills the desired size, and move the
804 // origin to the upper left edge of that area.
805 if( rAttr.IsCropped() )
807 const MapMode aMtfMapMode( aMtf.GetPrefMapMode() );
809 Rectangle aClipRect( aMtfMapMode.GetOrigin().X() + aCropLeftTop.Width(),
810 aMtfMapMode.GetOrigin().Y() + aCropLeftTop.Height(),
811 aMtfMapMode.GetOrigin().X() + aSrcSize.Width() - aCropRightBottom.Width(),
812 aMtfMapMode.GetOrigin().Y() + aSrcSize.Height() - aCropRightBottom.Height() );
814 // #104115# To correctly crop rotated metafiles, clip by view rectangle
815 aMtf.AddAction( new MetaISectRectClipRegionAction( aClipRect ), 0 );
817 // #104115# To crop the metafile, scale larger than the output rectangle
818 aMtf.Scale( (double)rDestSize.Width() / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()),
819 (double)rDestSize.Height() / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) );
821 // #104115# Adapt the pref size by hand (scale changes it
822 // proportionally, but we want it to be smaller than the
823 // former size, to crop the excess out)
824 aMtf.SetPrefSize( Size( (long)((double)rDestSize.Width() * (1.0 + (aCropLeftTop.Width() + aCropRightBottom.Width()) / aSrcSize.Width()) + .5),
825 (long)((double)rDestSize.Height() * (1.0 + (aCropLeftTop.Height() + aCropRightBottom.Height()) / aSrcSize.Height()) + .5) ) );
827 // #104115# Adapt the origin of the new mapmode, such that it
828 // is shifted to the place where the cropped output starts
829 Point aNewOrigin( (long)((double)aMtfMapMode.GetOrigin().X() + rDestSize.Width() * aCropLeftTop.Width() / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()) + .5),
830 (long)((double)aMtfMapMode.GetOrigin().Y() + rDestSize.Height() * aCropLeftTop.Height() / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) + .5) );
831 MapMode aNewMap( rDestMap );
832 aNewMap.SetOrigin( OutputDevice::LogicToLogic(aNewOrigin, aMtfMapMode, rDestMap) );
833 aMtf.SetPrefMapMode( aNewMap );
835 else
837 aMtf.Scale( Fraction( rDestSize.Width(), aSrcSize.Width() ), Fraction( rDestSize.Height(), aSrcSize.Height() ) );
838 aMtf.SetPrefMapMode( rDestMap );
841 aTransGraphic = aMtf;
843 else if( GRAPHIC_BITMAP == eType )
845 BitmapEx aBitmapEx( aTransGraphic.GetBitmapEx() );
847 // convert crops to pixel
848 aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel( Size( rAttr.GetLeftCrop(),
849 rAttr.GetTopCrop() ),
850 aMap100 );
851 aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel( Size( rAttr.GetRightCrop(),
852 rAttr.GetBottomCrop() ),
853 aMap100 );
855 // convert from prefmapmode to pixel
856 const Size aSrcSizePixel( Application::GetDefaultDevice()->LogicToPixel( aSrcSize,
857 aMapGraph ) );
859 // setup crop rectangle in pixel
860 Rectangle aCropRect( aCropLeftTop.Width(), aCropLeftTop.Height(),
861 aSrcSizePixel.Width() - aCropRightBottom.Width(),
862 aSrcSizePixel.Height() - aCropRightBottom.Height() );
864 // #105641# Also crop animations
865 if( aTransGraphic.IsAnimated() )
867 sal_uInt16 nFrame;
868 Animation aAnim( aTransGraphic.GetAnimation() );
870 for( nFrame=0; nFrame<aAnim.Count(); ++nFrame )
872 AnimationBitmap aAnimBmp( aAnim.Get( nFrame ) );
874 if( !aCropRect.IsInside( Rectangle(aAnimBmp.aPosPix, aAnimBmp.aSizePix) ) )
876 // setup actual cropping (relative to frame position)
877 Rectangle aCropRectRel( aCropRect );
878 aCropRectRel.Move( -aAnimBmp.aPosPix.X(),
879 -aAnimBmp.aPosPix.Y() );
881 // cropping affects this frame, apply it then
882 // do _not_ apply enlargement, this is done below
883 ImplTransformBitmap( aAnimBmp.aBmpEx, rAttr, Size(), Size(),
884 aCropRectRel, rDestSize, sal_False );
886 aAnim.Replace( aAnimBmp, nFrame );
888 // else: bitmap completely within crop area,
889 // i.e. nothing is cropped away
892 // now, apply enlargement (if any) through global animation size
893 if( aCropLeftTop.Width() < 0 ||
894 aCropLeftTop.Height() < 0 ||
895 aCropRightBottom.Width() < 0 ||
896 aCropRightBottom.Height() < 0 )
898 Size aNewSize( aAnim.GetDisplaySizePixel() );
899 aNewSize.Width() += aCropRightBottom.Width() < 0 ? -aCropRightBottom.Width() : 0;
900 aNewSize.Width() += aCropLeftTop.Width() < 0 ? -aCropLeftTop.Width() : 0;
901 aNewSize.Height() += aCropRightBottom.Height() < 0 ? -aCropRightBottom.Height() : 0;
902 aNewSize.Height() += aCropLeftTop.Height() < 0 ? -aCropLeftTop.Height() : 0;
903 aAnim.SetDisplaySizePixel( aNewSize );
906 // if topleft has changed, we must move all frames to the
907 // right and bottom, resp.
908 if( aCropLeftTop.Width() < 0 ||
909 aCropLeftTop.Height() < 0 )
911 Point aPosOffset( aCropLeftTop.Width() < 0 ? -aCropLeftTop.Width() : 0,
912 aCropLeftTop.Height() < 0 ? -aCropLeftTop.Height() : 0 );
914 for( nFrame=0; nFrame<aAnim.Count(); ++nFrame )
916 AnimationBitmap aAnimBmp( aAnim.Get( nFrame ) );
918 aAnimBmp.aPosPix += aPosOffset;
920 aAnim.Replace( aAnimBmp, nFrame );
924 aTransGraphic = aAnim;
926 else
928 BitmapEx aBmpEx( aTransGraphic.GetBitmapEx() );
930 ImplTransformBitmap( aBmpEx, rAttr, aCropLeftTop, aCropRightBottom,
931 aCropRect, rDestSize, sal_True );
933 aTransGraphic = aBmpEx;
936 aTransGraphic.SetPrefSize( rDestSize );
937 aTransGraphic.SetPrefMapMode( rDestMap );
940 GraphicObject aGrfObj( aTransGraphic );
941 aTransGraphic = aGrfObj.GetTransformedGraphic( &rAttr );
943 return aTransGraphic;
946 Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const // TODO: Change to Impl
948 GetGraphic();
950 Graphic aGraphic;
951 GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() );
953 if( maGraphic.IsSupportedGraphic() && !maGraphic.IsSwapOut() )
955 if( aAttr.IsSpecialDrawMode() || aAttr.IsAdjusted() || aAttr.IsMirrored() || aAttr.IsRotated() || aAttr.IsTransparent() )
957 if( GetType() == GRAPHIC_BITMAP )
959 if( IsAnimated() )
961 Animation aAnimation( maGraphic.GetAnimation() );
962 GraphicManager::ImplAdjust( aAnimation, aAttr, ADJUSTMENT_ALL );
963 aAnimation.SetLoopCount( mnAnimationLoopCount );
964 aGraphic = aAnimation;
966 else
968 BitmapEx aBmpEx( maGraphic.GetBitmapEx() );
969 GraphicManager::ImplAdjust( aBmpEx, aAttr, ADJUSTMENT_ALL );
970 aGraphic = aBmpEx;
973 else
975 GDIMetaFile aMtf( maGraphic.GetGDIMetaFile() );
976 GraphicManager::ImplAdjust( aMtf, aAttr, ADJUSTMENT_ALL );
977 aGraphic = aMtf;
980 else
982 if( ( GetType() == GRAPHIC_BITMAP ) && IsAnimated() )
984 Animation aAnimation( maGraphic.GetAnimation() );
985 aAnimation.SetLoopCount( mnAnimationLoopCount );
986 aGraphic = aAnimation;
988 else
989 aGraphic = maGraphic;
993 return aGraphic;
996 sal_Bool GraphicObject::SwapOut()
998 sal_Bool bRet = ( !mbAutoSwapped ? maGraphic.SwapOut() : sal_False );
1000 if( bRet && mpMgr )
1001 mpMgr->ImplGraphicObjectWasSwappedOut( *this );
1003 return bRet;
1006 sal_Bool GraphicObject::SwapOut( SvStream* pOStm )
1008 sal_Bool bRet = ( !mbAutoSwapped ? maGraphic.SwapOut( pOStm ) : sal_False );
1010 if( bRet && mpMgr )
1011 mpMgr->ImplGraphicObjectWasSwappedOut( *this );
1013 return bRet;
1016 sal_Bool GraphicObject::SwapIn()
1018 sal_Bool bRet;
1020 if( mbAutoSwapped )
1022 ImplAutoSwapIn();
1023 bRet = sal_True;
1025 else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) )
1026 bRet = sal_True;
1027 else
1029 bRet = maGraphic.SwapIn();
1031 if( bRet && mpMgr )
1032 mpMgr->ImplGraphicObjectWasSwappedIn( *this );
1035 if( bRet )
1036 ImplAssignGraphicData();
1038 return bRet;
1041 void GraphicObject::SetSwapState()
1043 if( !IsSwappedOut() )
1045 mbAutoSwapped = sal_True;
1047 if( mpMgr )
1048 mpMgr->ImplGraphicObjectWasSwappedOut( *this );
1052 IMPL_LINK_NOARG(GraphicObject, ImplAutoSwapOutHdl)
1054 if( !IsSwappedOut() )
1056 mbIsInSwapOut = sal_True;
1058 SvStream* pStream = GetSwapStream();
1060 if( GRFMGR_AUTOSWAPSTREAM_NONE != pStream )
1062 if( GRFMGR_AUTOSWAPSTREAM_LINK == pStream )
1063 mbAutoSwapped = SwapOut( NULL );
1064 else
1066 if( GRFMGR_AUTOSWAPSTREAM_TEMP == pStream )
1067 mbAutoSwapped = SwapOut();
1068 else
1070 mbAutoSwapped = SwapOut( pStream );
1071 delete pStream;
1076 mbIsInSwapOut = sal_False;
1079 if( mpSwapOutTimer )
1080 mpSwapOutTimer->Start();
1082 return 0L;
1085 SvStream& operator>>( SvStream& rIStm, GraphicObject& rGraphicObj )
1087 VersionCompat aCompat( rIStm, STREAM_READ );
1088 Graphic aGraphic;
1089 GraphicAttr aAttr;
1090 sal_Bool bLink;
1092 rIStm >> aGraphic >> aAttr >> bLink;
1094 rGraphicObj.SetGraphic( aGraphic );
1095 rGraphicObj.SetAttr( aAttr );
1097 if( bLink )
1099 OUString aLink = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(rIStm, RTL_TEXTENCODING_UTF8);
1100 rGraphicObj.SetLink(aLink);
1102 else
1103 rGraphicObj.SetLink();
1105 rGraphicObj.SetSwapStreamHdl();
1107 return rIStm;
1110 SvStream& operator<<( SvStream& rOStm, const GraphicObject& rGraphicObj )
1112 VersionCompat aCompat( rOStm, STREAM_WRITE, 1 );
1113 const sal_Bool bLink = rGraphicObj.HasLink();
1115 rOStm << rGraphicObj.GetGraphic() << rGraphicObj.GetAttr() << bLink;
1117 if( bLink )
1118 write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(rOStm, rGraphicObj.GetLink(), RTL_TEXTENCODING_UTF8);
1120 return rOStm;
1123 #define UNO_NAME_GRAPHOBJ_URLPREFIX "vnd.sun.star.GraphicObject:"
1125 GraphicObject GraphicObject::CreateGraphicObjectFromURL( const OUString &rURL )
1127 const String aURL( rURL ), aPrefix( RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_GRAPHOBJ_URLPREFIX) );
1128 if( aURL.Search( aPrefix ) == 0 )
1130 // graphic manager url
1131 OString aUniqueID(OUStringToOString(rURL.copy(sizeof(UNO_NAME_GRAPHOBJ_URLPREFIX) - 1), RTL_TEXTENCODING_UTF8));
1132 return GraphicObject( aUniqueID );
1134 else
1136 Graphic aGraphic;
1137 if ( aURL.Len() )
1139 SvStream* pStream = utl::UcbStreamHelper::CreateStream( aURL, STREAM_READ );
1140 if( pStream )
1142 GraphicConverter::Import( *pStream, aGraphic );
1143 delete pStream;
1147 return GraphicObject( aGraphic );
1151 void
1152 GraphicObject::InspectForGraphicObjectImageURL( const Reference< XInterface >& xIf, std::vector< OUString >& rvEmbedImgUrls )
1154 static OUString sImageURL( "ImageURL" );
1155 Reference< XPropertySet > xProps( xIf, UNO_QUERY );
1156 if ( xProps.is() )
1159 if ( xProps->getPropertySetInfo()->hasPropertyByName( sImageURL ) )
1161 OUString sURL;
1162 xProps->getPropertyValue( sImageURL ) >>= sURL;
1163 if ( !sURL.isEmpty() && sURL.startsWith( UNO_NAME_GRAPHOBJ_URLPREFIX ) )
1164 rvEmbedImgUrls.push_back( sURL );
1167 Reference< XNameContainer > xContainer( xIf, UNO_QUERY );
1168 if ( xContainer.is() )
1170 Sequence< OUString > sNames = xContainer->getElementNames();
1171 sal_Int32 nContainees = sNames.getLength();
1172 for ( sal_Int32 index = 0; index < nContainees; ++index )
1174 Reference< XInterface > xCtrl;
1175 xContainer->getByName( sNames[ index ] ) >>= xCtrl;
1176 InspectForGraphicObjectImageURL( xCtrl, rvEmbedImgUrls );
1181 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */