bump product version to 4.2.0.1
[LibreOffice.git] / svtools / source / graphic / grfmgr.cxx
blobf1c59552f29c72fa833ef7e633e43935d489e450
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 maLink (),
63 maUserData ()
65 ImplConstruct();
66 ImplAssignGraphicData();
67 ImplSetGraphicManager( pMgr );
70 GraphicObject::GraphicObject( const Graphic& rGraphic, const GraphicManager* pMgr ) :
71 maGraphic ( rGraphic ),
72 maLink (),
73 maUserData ()
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 maLink ( rGraphicObj.maLink ),
85 maUserData ( rGraphicObj.maUserData )
87 ImplConstruct();
88 ImplAssignGraphicData();
89 ImplSetGraphicManager( pMgr, NULL, &rGraphicObj );
92 GraphicObject::GraphicObject( const OString& rUniqueID, const GraphicManager* pMgr ) :
93 maLink (),
94 maUserData ()
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 mpSimpleCache;
122 void GraphicObject::ImplConstruct()
124 mpMgr = NULL;
125 mpSwapStreamHdl = NULL;
126 mpSwapOutTimer = NULL;
127 mpSimpleCache = NULL;
128 mnAnimationLoopCount = 0;
129 mbAutoSwapped = sal_False;
130 mbIsInSwapIn = sal_False;
131 mbIsInSwapOut = sal_False;
134 void GraphicObject::ImplAssignGraphicData()
136 maPrefSize = maGraphic.GetPrefSize();
137 maPrefMapMode = maGraphic.GetPrefMapMode();
138 mnSizeBytes = maGraphic.GetSizeBytes();
139 meType = maGraphic.GetType();
140 mbTransparent = maGraphic.IsTransparent();
141 mbAlpha = maGraphic.IsAlpha();
142 mbAnimated = maGraphic.IsAnimated();
143 mbEPS = maGraphic.IsEPS();
144 mnAnimationLoopCount = ( mbAnimated ? maGraphic.GetAnimationLoopCount() : 0 );
147 void GraphicObject::ImplSetGraphicManager( const GraphicManager* pMgr, const OString* pID, const GraphicObject* pCopyObj )
149 if( !mpMgr || ( pMgr != mpMgr ) )
151 if( !pMgr && mpMgr && ( mpMgr == mpGlobalMgr ) )
152 return;
153 else
155 if( mpMgr )
157 mpMgr->ImplUnregisterObj( *this );
159 if( ( mpMgr == mpGlobalMgr ) && !mpGlobalMgr->ImplHasObjects() )
160 delete mpGlobalMgr, mpGlobalMgr = NULL;
163 if( !pMgr )
165 if( !mpGlobalMgr )
167 mpGlobalMgr = new GraphicManager(
168 (officecfg::Office::Common::Cache::GraphicManager::
169 TotalCacheSize::get()),
170 (officecfg::Office::Common::Cache::GraphicManager::
171 ObjectCacheSize::get()));
172 mpGlobalMgr->SetCacheTimeout(
173 officecfg::Office::Common::Cache::GraphicManager::
174 ObjectReleaseTime::get());
177 mpMgr = mpGlobalMgr;
179 else
180 mpMgr = (GraphicManager*) pMgr;
182 mpMgr->ImplRegisterObj( *this, maGraphic, pID, pCopyObj );
187 void GraphicObject::ImplAutoSwapIn()
189 if( IsSwappedOut() )
191 if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) )
192 mbAutoSwapped = sal_False;
193 else
195 mbIsInSwapIn = sal_True;
197 if( maGraphic.SwapIn() )
198 mbAutoSwapped = sal_False;
199 else
201 SvStream* pStream = GetSwapStream();
203 if( GRFMGR_AUTOSWAPSTREAM_NONE != pStream )
205 if( GRFMGR_AUTOSWAPSTREAM_LINK == pStream )
207 if( HasLink() )
209 OUString aURLStr;
211 if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( GetLink(), aURLStr ) )
213 SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( aURLStr, STREAM_READ );
215 if( pIStm )
217 (*pIStm) >> maGraphic;
218 mbAutoSwapped = ( maGraphic.GetType() != GRAPHIC_NONE );
219 delete pIStm;
224 else if( GRFMGR_AUTOSWAPSTREAM_TEMP == pStream )
225 mbAutoSwapped = !maGraphic.SwapIn();
226 else if( GRFMGR_AUTOSWAPSTREAM_LOADED == pStream )
227 mbAutoSwapped = maGraphic.IsSwapOut();
228 else
230 mbAutoSwapped = !maGraphic.SwapIn( pStream );
231 delete pStream;
234 else
236 DBG_ASSERT( ( GRAPHIC_NONE == meType ) || ( GRAPHIC_DEFAULT == meType ),
237 "GraphicObject::ImplAutoSwapIn: could not get stream to swap in graphic! (=>KA)" );
241 mbIsInSwapIn = sal_False;
243 if( !mbAutoSwapped && mpMgr )
244 mpMgr->ImplGraphicObjectWasSwappedIn( *this );
249 sal_Bool GraphicObject::ImplGetCropParams( OutputDevice* pOut, Point& rPt, Size& rSz, const GraphicAttr* pAttr,
250 PolyPolygon& rClipPolyPoly, sal_Bool& bRectClipRegion ) const
252 sal_Bool bRet = sal_False;
254 if( GetType() != GRAPHIC_NONE )
256 Polygon aClipPoly( Rectangle( rPt, rSz ) );
257 const sal_uInt16 nRot10 = pAttr->GetRotation() % 3600;
258 const Point aOldOrigin( rPt );
259 const MapMode aMap100( MAP_100TH_MM );
260 Size aSize100;
261 long nTotalWidth, nTotalHeight;
263 if( nRot10 )
265 aClipPoly.Rotate( rPt, nRot10 );
266 bRectClipRegion = sal_False;
268 else
269 bRectClipRegion = sal_True;
271 rClipPolyPoly = aClipPoly;
273 if( maGraphic.GetPrefMapMode() == MAP_PIXEL )
274 aSize100 = Application::GetDefaultDevice()->PixelToLogic( maGraphic.GetPrefSize(), aMap100 );
275 else
277 MapMode m(maGraphic.GetPrefMapMode());
278 aSize100 = pOut->LogicToLogic( maGraphic.GetPrefSize(), &m, &aMap100 );
281 nTotalWidth = aSize100.Width() - pAttr->GetLeftCrop() - pAttr->GetRightCrop();
282 nTotalHeight = aSize100.Height() - pAttr->GetTopCrop() - pAttr->GetBottomCrop();
284 if( aSize100.Width() > 0 && aSize100.Height() > 0 && nTotalWidth > 0 && nTotalHeight > 0 )
286 double fScale = (double) aSize100.Width() / nTotalWidth;
287 const long nNewLeft = -FRound( ( ( pAttr->GetMirrorFlags() & BMP_MIRROR_HORZ ) ? pAttr->GetRightCrop() : pAttr->GetLeftCrop() ) * fScale );
288 const long nNewRight = nNewLeft + FRound( aSize100.Width() * fScale ) - 1;
290 fScale = (double) rSz.Width() / aSize100.Width();
291 rPt.X() += FRound( nNewLeft * fScale );
292 rSz.Width() = FRound( ( nNewRight - nNewLeft + 1 ) * fScale );
294 fScale = (double) aSize100.Height() / nTotalHeight;
295 const long nNewTop = -FRound( ( ( pAttr->GetMirrorFlags() & BMP_MIRROR_VERT ) ? pAttr->GetBottomCrop() : pAttr->GetTopCrop() ) * fScale );
296 const long nNewBottom = nNewTop + FRound( aSize100.Height() * fScale ) - 1;
298 fScale = (double) rSz.Height() / aSize100.Height();
299 rPt.Y() += FRound( nNewTop * fScale );
300 rSz.Height() = FRound( ( nNewBottom - nNewTop + 1 ) * fScale );
302 if( nRot10 )
304 Polygon aOriginPoly( 1 );
306 aOriginPoly[ 0 ] = rPt;
307 aOriginPoly.Rotate( aOldOrigin, nRot10 );
308 rPt = aOriginPoly[ 0 ];
311 bRet = sal_True;
315 return bRet;
318 GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj )
320 if( &rGraphicObj != this )
322 mpMgr->ImplUnregisterObj( *this );
324 delete mpSwapStreamHdl, mpSwapStreamHdl = NULL;
325 delete mpSimpleCache, mpSimpleCache = NULL;
327 maGraphic = rGraphicObj.GetGraphic();
328 maAttr = rGraphicObj.maAttr;
329 maLink = rGraphicObj.maLink;
330 maUserData = rGraphicObj.maUserData;
331 ImplAssignGraphicData();
332 mbAutoSwapped = sal_False;
333 mpMgr = rGraphicObj.mpMgr;
335 mpMgr->ImplRegisterObj( *this, maGraphic, NULL, &rGraphicObj );
338 return *this;
341 sal_Bool GraphicObject::operator==( const GraphicObject& rGraphicObj ) const
343 return( ( rGraphicObj.maGraphic == maGraphic ) &&
344 ( rGraphicObj.maAttr == maAttr ) &&
345 ( rGraphicObj.GetLink() == GetLink() ) );
348 void GraphicObject::Load( SvStream& rIStm )
350 rIStm >> *this;
353 void GraphicObject::Save( SvStream& rOStm )
355 rOStm << *this;
358 void GraphicObject::Assign( const SvDataCopyStream& rCopyStream )
360 *this = (const GraphicObject& ) rCopyStream;
363 OString GraphicObject::GetUniqueID() const
365 if ( !IsInSwapIn() && IsEPS() )
366 const_cast<GraphicObject*>(this)->FireSwapInRequest();
368 OString aRet;
370 if( mpMgr )
371 aRet = mpMgr->ImplGetUniqueID( *this );
373 return aRet;
376 SvStream* GraphicObject::GetSwapStream() const
378 return( HasSwapStreamHdl() ? (SvStream*) mpSwapStreamHdl->Call( (void*) this ) : GRFMGR_AUTOSWAPSTREAM_NONE );
381 void GraphicObject::SetAttr( const GraphicAttr& rAttr )
383 maAttr = rAttr;
385 if( mpSimpleCache && ( mpSimpleCache->maAttr != rAttr ) )
386 delete mpSimpleCache, mpSimpleCache = NULL;
389 void GraphicObject::SetLink()
391 maLink = "";
394 void GraphicObject::SetLink( const OUString& rLink )
396 maLink = rLink;
399 void GraphicObject::SetUserData()
401 maUserData = "";
404 void GraphicObject::SetUserData( const OUString& rUserData )
406 maUserData = rUserData;
409 void GraphicObject::SetSwapStreamHdl()
411 if( mpSwapStreamHdl )
413 delete mpSwapOutTimer, mpSwapOutTimer = NULL;
414 delete mpSwapStreamHdl, mpSwapStreamHdl = NULL;
418 void GraphicObject::SetSwapStreamHdl( const Link& rHdl, const sal_uLong nSwapOutTimeout )
420 delete mpSwapStreamHdl, mpSwapStreamHdl = new Link( rHdl );
422 if( nSwapOutTimeout )
424 if( !mpSwapOutTimer )
426 mpSwapOutTimer = new Timer;
427 mpSwapOutTimer->SetTimeoutHdl( LINK( this, GraphicObject, ImplAutoSwapOutHdl ) );
430 mpSwapOutTimer->SetTimeout( nSwapOutTimeout );
431 mpSwapOutTimer->Start();
433 else
434 delete mpSwapOutTimer, mpSwapOutTimer = NULL;
437 void GraphicObject::FireSwapInRequest()
439 ImplAutoSwapIn();
442 void GraphicObject::FireSwapOutRequest()
444 ImplAutoSwapOutHdl( NULL );
447 void GraphicObject::GraphicManagerDestroyed()
449 // we're alive, but our manager doesn't live anymore ==> connect to default manager
450 mpMgr = NULL;
451 ImplSetGraphicManager( NULL );
454 sal_Bool GraphicObject::IsCached( OutputDevice* pOut, const Point& rPt, const Size& rSz,
455 const GraphicAttr* pAttr, sal_uLong nFlags ) const
457 sal_Bool bRet;
459 if( nFlags & GRFMGR_DRAW_CACHED )
461 Point aPt( rPt );
462 Size aSz( rSz );
463 if ( pAttr->IsCropped() )
465 PolyPolygon aClipPolyPoly;
466 sal_Bool bRectClip;
467 ImplGetCropParams( pOut, aPt, aSz, pAttr, aClipPolyPoly, bRectClip );
469 bRet = mpMgr->IsInCache( pOut, aPt, aSz, *this, ( pAttr ? *pAttr : GetAttr() ) );
471 else
472 bRet = sal_False;
474 return bRet;
477 void GraphicObject::ReleaseFromCache()
480 mpMgr->ReleaseFromCache( *this );
483 bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
484 const GraphicAttr* pAttr, sal_uLong nFlags )
486 GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() );
487 Point aPt( rPt );
488 Size aSz( rSz );
489 const sal_uInt32 nOldDrawMode = pOut->GetDrawMode();
490 sal_Bool bCropped = aAttr.IsCropped();
491 sal_Bool bCached = sal_False;
492 bool bRet;
494 // #i29534# Provide output rects for PDF writer
495 Rectangle aCropRect;
497 if( !( GRFMGR_DRAW_USE_DRAWMODE_SETTINGS & nFlags ) )
498 pOut->SetDrawMode( nOldDrawMode & ( ~( DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT ) ) );
500 // mirrored horizontically
501 if( aSz.Width() < 0L )
503 aPt.X() += aSz.Width() + 1;
504 aSz.Width() = -aSz.Width();
505 aAttr.SetMirrorFlags( aAttr.GetMirrorFlags() ^ BMP_MIRROR_HORZ );
508 // mirrored vertically
509 if( aSz.Height() < 0L )
511 aPt.Y() += aSz.Height() + 1;
512 aSz.Height() = -aSz.Height();
513 aAttr.SetMirrorFlags( aAttr.GetMirrorFlags() ^ BMP_MIRROR_VERT );
516 if( bCropped )
518 PolyPolygon aClipPolyPoly;
519 sal_Bool bRectClip;
520 const sal_Bool bCrop = ImplGetCropParams( pOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip );
522 pOut->Push( PUSH_CLIPREGION );
524 if( bCrop )
526 if( bRectClip )
528 // #i29534# Store crop rect for later forwarding to
529 // PDF writer
530 aCropRect = aClipPolyPoly.GetBoundRect();
531 pOut->IntersectClipRegion( aCropRect );
533 else
535 pOut->IntersectClipRegion(Region(aClipPolyPoly));
540 bRet = mpMgr->DrawObj( pOut, aPt, aSz, *this, aAttr, nFlags, bCached );
542 if( bCropped )
543 pOut->Pop();
545 pOut->SetDrawMode( nOldDrawMode );
547 // #i29534# Moved below OutDev restoration, to avoid multiple swap-ins
548 // (code above needs to call GetGraphic twice)
549 if( bCached )
551 if( mpSwapOutTimer )
552 mpSwapOutTimer->Start();
553 else
554 FireSwapOutRequest();
557 return bRet;
560 // #i105243#
561 sal_Bool GraphicObject::DrawWithPDFHandling( OutputDevice& rOutDev,
562 const Point& rPt, const Size& rSz,
563 const GraphicAttr* pGrfAttr,
564 const sal_uLong nFlags )
566 const GraphicAttr aGrfAttr( pGrfAttr ? *pGrfAttr : GetAttr() );
568 // Notify PDF writer about linked graphic (if any)
569 sal_Bool bWritingPdfLinkedGraphic( sal_False );
570 Point aPt( rPt );
571 Size aSz( rSz );
572 Rectangle aCropRect;
573 vcl::PDFExtOutDevData* pPDFExtOutDevData =
574 dynamic_cast<vcl::PDFExtOutDevData*>(rOutDev.GetExtOutDevData());
575 if( pPDFExtOutDevData )
577 // only delegate image handling to PDF, if no special treatment is necessary
578 if( GetGraphic().IsLink() &&
579 rSz.Width() > 0L &&
580 rSz.Height() > 0L &&
581 !aGrfAttr.IsSpecialDrawMode() &&
582 !aGrfAttr.IsMirrored() &&
583 !aGrfAttr.IsRotated() &&
584 !aGrfAttr.IsAdjusted() )
586 bWritingPdfLinkedGraphic = true;
588 if( aGrfAttr.IsCropped() )
590 PolyPolygon aClipPolyPoly;
591 sal_Bool bRectClip;
592 const sal_Bool bCrop = ImplGetCropParams( &rOutDev,
593 aPt, aSz,
594 &aGrfAttr,
595 aClipPolyPoly,
596 bRectClip );
597 if ( bCrop && bRectClip )
599 aCropRect = aClipPolyPoly.GetBoundRect();
603 pPDFExtOutDevData->BeginGroup();
607 sal_Bool bRet = Draw( &rOutDev, rPt, rSz, &aGrfAttr, nFlags );
609 // Notify PDF writer about linked graphic (if any)
610 if( bWritingPdfLinkedGraphic )
612 pPDFExtOutDevData->EndGroup( const_cast< Graphic& >(GetGraphic()),
613 aGrfAttr.GetTransparency(),
614 Rectangle( aPt, aSz ),
615 aCropRect );
618 return bRet;
621 sal_Bool GraphicObject::DrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSize,
622 const Size& rOffset, const GraphicAttr* pAttr, sal_uLong nFlags, int nTileCacheSize1D )
624 if( pOut == NULL || rSize.Width() == 0 || rSize.Height() == 0 )
625 return sal_False;
627 const MapMode aOutMapMode( pOut->GetMapMode() );
628 const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
629 // #106258# Clamp size to 1 for zero values. This is okay, since
630 // logical size of zero is handled above already
631 const Size aOutTileSize( ::std::max( 1L, pOut->LogicToPixel( rSize, aOutMapMode ).Width() ),
632 ::std::max( 1L, pOut->LogicToPixel( rSize, aOutMapMode ).Height() ) );
634 //#i69780 clip final tile size to a sane max size
635 while (((sal_Int64)rSize.Width() * nTileCacheSize1D) > SAL_MAX_UINT16)
636 nTileCacheSize1D /= 2;
637 while (((sal_Int64)rSize.Height() * nTileCacheSize1D) > SAL_MAX_UINT16)
638 nTileCacheSize1D /= 2;
640 return ImplDrawTiled( pOut, rArea, aOutTileSize, rOffset, pAttr, nFlags, nTileCacheSize1D );
643 sal_Bool GraphicObject::StartAnimation( OutputDevice* pOut, const Point& rPt, const Size& rSz,
644 long nExtraData, const GraphicAttr* pAttr, sal_uLong /*nFlags*/,
645 OutputDevice* pFirstFrameOutDev )
647 sal_Bool bRet = sal_False;
649 GetGraphic();
651 if( !IsSwappedOut() )
653 const GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() );
655 if( mbAnimated )
657 Point aPt( rPt );
658 Size aSz( rSz );
659 sal_Bool bCropped = aAttr.IsCropped();
661 if( bCropped )
663 PolyPolygon aClipPolyPoly;
664 sal_Bool bRectClip;
665 const sal_Bool bCrop = ImplGetCropParams( pOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip );
667 pOut->Push( PUSH_CLIPREGION );
669 if( bCrop )
671 if( bRectClip )
672 pOut->IntersectClipRegion( aClipPolyPoly.GetBoundRect() );
673 else
674 pOut->IntersectClipRegion(Region(aClipPolyPoly));
678 if( !mpSimpleCache || ( mpSimpleCache->maAttr != aAttr ) || pFirstFrameOutDev )
680 if( mpSimpleCache )
681 delete mpSimpleCache;
683 mpSimpleCache = new GrfSimpleCacheObj( GetTransformedGraphic( &aAttr ), aAttr );
684 mpSimpleCache->maGraphic.SetAnimationNotifyHdl( GetAnimationNotifyHdl() );
687 mpSimpleCache->maGraphic.StartAnimation( pOut, aPt, aSz, nExtraData, pFirstFrameOutDev );
689 if( bCropped )
690 pOut->Pop();
692 bRet = sal_True;
694 else
695 bRet = Draw( pOut, rPt, rSz, &aAttr, GRFMGR_DRAW_STANDARD );
698 return bRet;
701 void GraphicObject::StopAnimation( OutputDevice* pOut, long nExtraData )
703 if( mpSimpleCache )
704 mpSimpleCache->maGraphic.StopAnimation( pOut, nExtraData );
707 const Graphic& GraphicObject::GetGraphic() const
709 if( mbAutoSwapped )
710 ( (GraphicObject*) this )->ImplAutoSwapIn();
712 return maGraphic;
715 void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pCopyObj )
717 mpMgr->ImplUnregisterObj( *this );
719 if( mpSwapOutTimer )
720 mpSwapOutTimer->Stop();
722 maGraphic = rGraphic;
723 mbAutoSwapped = sal_False;
724 ImplAssignGraphicData();
725 maLink = "";
726 delete mpSimpleCache, mpSimpleCache = NULL;
728 mpMgr->ImplRegisterObj( *this, maGraphic, 0, pCopyObj);
730 if( mpSwapOutTimer )
731 mpSwapOutTimer->Start();
734 void GraphicObject::SetGraphic( const Graphic& rGraphic, const OUString& rLink )
736 SetGraphic( rGraphic );
737 maLink = rLink;
740 Graphic GraphicObject::GetTransformedGraphic( const Size& rDestSize, const MapMode& rDestMap, const GraphicAttr& rAttr ) const
742 // #104550# Extracted from svx/source/svdraw/svdograf.cxx
743 Graphic aTransGraphic( maGraphic );
744 const GraphicType eType = GetType();
745 const Size aSrcSize( aTransGraphic.GetPrefSize() );
747 // #104115# Convert the crop margins to graphic object mapmode
748 const MapMode aMapGraph( aTransGraphic.GetPrefMapMode() );
749 const MapMode aMap100( MAP_100TH_MM );
751 Size aCropLeftTop;
752 Size aCropRightBottom;
754 if( GRAPHIC_GDIMETAFILE == eType )
756 GDIMetaFile aMtf( aTransGraphic.GetGDIMetaFile() );
758 if( aMapGraph == MAP_PIXEL )
760 // crops are in 1/100th mm -> to aMapGraph -> to MAP_PIXEL
761 aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel(
762 Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()),
763 aMap100);
764 aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel(
765 Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()),
766 aMap100);
768 else
770 // crops are in GraphicObject units -> to aMapGraph
771 aCropLeftTop = OutputDevice::LogicToLogic(
772 Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()),
773 aMap100,
774 aMapGraph);
775 aCropRightBottom = OutputDevice::LogicToLogic(
776 Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()),
777 aMap100,
778 aMapGraph);
781 // #104115# If the metafile is cropped, give it a special
782 // treatment: clip against the remaining area, scale up such
783 // that this area later fills the desired size, and move the
784 // origin to the upper left edge of that area.
785 if( rAttr.IsCropped() )
787 const MapMode aMtfMapMode( aMtf.GetPrefMapMode() );
789 Rectangle aClipRect( aMtfMapMode.GetOrigin().X() + aCropLeftTop.Width(),
790 aMtfMapMode.GetOrigin().Y() + aCropLeftTop.Height(),
791 aMtfMapMode.GetOrigin().X() + aSrcSize.Width() - aCropRightBottom.Width(),
792 aMtfMapMode.GetOrigin().Y() + aSrcSize.Height() - aCropRightBottom.Height() );
794 // #104115# To correctly crop rotated metafiles, clip by view rectangle
795 aMtf.AddAction( new MetaISectRectClipRegionAction( aClipRect ), 0 );
797 // #104115# To crop the metafile, scale larger than the output rectangle
798 aMtf.Scale( (double)rDestSize.Width() / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()),
799 (double)rDestSize.Height() / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) );
801 // #104115# Adapt the pref size by hand (scale changes it
802 // proportionally, but we want it to be smaller than the
803 // former size, to crop the excess out)
804 aMtf.SetPrefSize( Size( (long)((double)rDestSize.Width() * (1.0 + (aCropLeftTop.Width() + aCropRightBottom.Width()) / aSrcSize.Width()) + .5),
805 (long)((double)rDestSize.Height() * (1.0 + (aCropLeftTop.Height() + aCropRightBottom.Height()) / aSrcSize.Height()) + .5) ) );
807 // #104115# Adapt the origin of the new mapmode, such that it
808 // is shifted to the place where the cropped output starts
809 Point aNewOrigin( (long)((double)aMtfMapMode.GetOrigin().X() + rDestSize.Width() * aCropLeftTop.Width() / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()) + .5),
810 (long)((double)aMtfMapMode.GetOrigin().Y() + rDestSize.Height() * aCropLeftTop.Height() / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) + .5) );
811 MapMode aNewMap( rDestMap );
812 aNewMap.SetOrigin( OutputDevice::LogicToLogic(aNewOrigin, aMtfMapMode, rDestMap) );
813 aMtf.SetPrefMapMode( aNewMap );
815 else
817 aMtf.Scale( Fraction( rDestSize.Width(), aSrcSize.Width() ), Fraction( rDestSize.Height(), aSrcSize.Height() ) );
818 aMtf.SetPrefMapMode( rDestMap );
821 aTransGraphic = aMtf;
823 else if( GRAPHIC_BITMAP == eType )
825 BitmapEx aBitmapEx( aTransGraphic.GetBitmapEx() );
826 Rectangle aCropRect;
828 // convert crops to pixel
829 if(rAttr.IsCropped())
831 if( aMapGraph == MAP_PIXEL )
833 // crops are in 1/100th mm -> to MAP_PIXEL
834 aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel(
835 Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()),
836 aMap100);
837 aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel(
838 Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()),
839 aMap100);
841 else
843 // crops are in GraphicObject units -> to MAP_PIXEL
844 aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel(
845 Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()),
846 aMapGraph);
847 aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel(
848 Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()),
849 aMapGraph);
852 // convert from prefmapmode to pixel
853 Size aSrcSizePixel(
854 Application::GetDefaultDevice()->LogicToPixel(
855 aSrcSize,
856 aMapGraph));
858 if(rAttr.IsCropped()
859 && (aSrcSizePixel.Width() != aBitmapEx.GetSizePixel().Width() || aSrcSizePixel.Height() != aBitmapEx.GetSizePixel().Height())
860 && aSrcSizePixel.Width())
862 // the size in pixels calculated from Graphic's internal MapMode (aTransGraphic.GetPrefMapMode())
863 // and it's internal size (aTransGraphic.GetPrefSize()) is different from it's real pixel size.
864 // This can be interpreted as this values to be set wrong, but needs to be corrected since e.g.
865 // existing cropping is calculated based on this logic values already.
866 // aBitmapEx.Scale(aSrcSizePixel);
868 // another possibility is to adapt the values created so far with a factor; this
869 // will keep the original Bitmap untouched and thus quality will not change
870 // caution: convert to double first, else pretty big errors may occurr
871 const double fFactorX((double)aBitmapEx.GetSizePixel().Width() / aSrcSizePixel.Width());
872 const double fFactorY((double)aBitmapEx.GetSizePixel().Height() / aSrcSizePixel.Height());
874 aCropLeftTop.Width() = basegfx::fround(aCropLeftTop.Width() * fFactorX);
875 aCropLeftTop.Height() = basegfx::fround(aCropLeftTop.Height() * fFactorY);
876 aCropRightBottom.Width() = basegfx::fround(aCropRightBottom.Width() * fFactorX);
877 aCropRightBottom.Height() = basegfx::fround(aCropRightBottom.Height() * fFactorY);
879 aSrcSizePixel = aBitmapEx.GetSizePixel();
882 // setup crop rectangle in pixel
883 aCropRect = Rectangle( aCropLeftTop.Width(), aCropLeftTop.Height(),
884 aSrcSizePixel.Width() - aCropRightBottom.Width(),
885 aSrcSizePixel.Height() - aCropRightBottom.Height() );
888 // #105641# Also crop animations
889 if( aTransGraphic.IsAnimated() )
891 sal_uInt16 nFrame;
892 Animation aAnim( aTransGraphic.GetAnimation() );
894 for( nFrame=0; nFrame<aAnim.Count(); ++nFrame )
896 AnimationBitmap aAnimBmp( aAnim.Get( nFrame ) );
898 if( !aCropRect.IsInside( Rectangle(aAnimBmp.aPosPix, aAnimBmp.aSizePix) ) )
900 // setup actual cropping (relative to frame position)
901 Rectangle aCropRectRel( aCropRect );
902 aCropRectRel.Move( -aAnimBmp.aPosPix.X(),
903 -aAnimBmp.aPosPix.Y() );
905 // cropping affects this frame, apply it then
906 // do _not_ apply enlargement, this is done below
907 ImplTransformBitmap( aAnimBmp.aBmpEx, rAttr, Size(), Size(),
908 aCropRectRel, rDestSize, sal_False );
910 aAnim.Replace( aAnimBmp, nFrame );
912 // else: bitmap completely within crop area,
913 // i.e. nothing is cropped away
916 // now, apply enlargement (if any) through global animation size
917 if( aCropLeftTop.Width() < 0 ||
918 aCropLeftTop.Height() < 0 ||
919 aCropRightBottom.Width() < 0 ||
920 aCropRightBottom.Height() < 0 )
922 Size aNewSize( aAnim.GetDisplaySizePixel() );
923 aNewSize.Width() += aCropRightBottom.Width() < 0 ? -aCropRightBottom.Width() : 0;
924 aNewSize.Width() += aCropLeftTop.Width() < 0 ? -aCropLeftTop.Width() : 0;
925 aNewSize.Height() += aCropRightBottom.Height() < 0 ? -aCropRightBottom.Height() : 0;
926 aNewSize.Height() += aCropLeftTop.Height() < 0 ? -aCropLeftTop.Height() : 0;
927 aAnim.SetDisplaySizePixel( aNewSize );
930 // if topleft has changed, we must move all frames to the
931 // right and bottom, resp.
932 if( aCropLeftTop.Width() < 0 ||
933 aCropLeftTop.Height() < 0 )
935 Point aPosOffset( aCropLeftTop.Width() < 0 ? -aCropLeftTop.Width() : 0,
936 aCropLeftTop.Height() < 0 ? -aCropLeftTop.Height() : 0 );
938 for( nFrame=0; nFrame<aAnim.Count(); ++nFrame )
940 AnimationBitmap aAnimBmp( aAnim.Get( nFrame ) );
942 aAnimBmp.aPosPix += aPosOffset;
944 aAnim.Replace( aAnimBmp, nFrame );
948 aTransGraphic = aAnim;
950 else
952 ImplTransformBitmap( aBitmapEx, rAttr, aCropLeftTop, aCropRightBottom,
953 aCropRect, rDestSize, sal_True );
955 aTransGraphic = aBitmapEx;
958 aTransGraphic.SetPrefSize( rDestSize );
959 aTransGraphic.SetPrefMapMode( rDestMap );
962 GraphicObject aGrfObj( aTransGraphic );
963 aTransGraphic = aGrfObj.GetTransformedGraphic( &rAttr );
965 return aTransGraphic;
968 Graphic GraphicObject::GetTransformedGraphic( const GraphicAttr* pAttr ) const // TODO: Change to Impl
970 GetGraphic();
972 Graphic aGraphic;
973 GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() );
975 if( maGraphic.IsSupportedGraphic() && !maGraphic.IsSwapOut() )
977 if( aAttr.IsSpecialDrawMode() || aAttr.IsAdjusted() || aAttr.IsMirrored() || aAttr.IsRotated() || aAttr.IsTransparent() )
979 if( GetType() == GRAPHIC_BITMAP )
981 if( IsAnimated() )
983 Animation aAnimation( maGraphic.GetAnimation() );
984 GraphicManager::ImplAdjust( aAnimation, aAttr, ADJUSTMENT_ALL );
985 aAnimation.SetLoopCount( mnAnimationLoopCount );
986 aGraphic = aAnimation;
988 else
990 BitmapEx aBmpEx( maGraphic.GetBitmapEx() );
991 GraphicManager::ImplAdjust( aBmpEx, aAttr, ADJUSTMENT_ALL );
992 aGraphic = aBmpEx;
995 else
997 GDIMetaFile aMtf( maGraphic.GetGDIMetaFile() );
998 GraphicManager::ImplAdjust( aMtf, aAttr, ADJUSTMENT_ALL );
999 aGraphic = aMtf;
1002 else
1004 if( ( GetType() == GRAPHIC_BITMAP ) && IsAnimated() )
1006 Animation aAnimation( maGraphic.GetAnimation() );
1007 aAnimation.SetLoopCount( mnAnimationLoopCount );
1008 aGraphic = aAnimation;
1010 else
1011 aGraphic = maGraphic;
1015 return aGraphic;
1018 sal_Bool GraphicObject::SwapOut()
1020 sal_Bool bRet = ( !mbAutoSwapped ? maGraphic.SwapOut() : sal_False );
1022 if( bRet && mpMgr )
1023 mpMgr->ImplGraphicObjectWasSwappedOut( *this );
1025 return bRet;
1028 sal_Bool GraphicObject::SwapOut( SvStream* pOStm )
1030 sal_Bool bRet = ( !mbAutoSwapped ? maGraphic.SwapOut( pOStm ) : sal_False );
1032 if( bRet && mpMgr )
1033 mpMgr->ImplGraphicObjectWasSwappedOut( *this );
1035 return bRet;
1038 sal_Bool GraphicObject::SwapIn()
1040 sal_Bool bRet;
1042 if( mbAutoSwapped )
1044 ImplAutoSwapIn();
1045 bRet = sal_True;
1047 else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) )
1048 bRet = sal_True;
1049 else
1051 bRet = maGraphic.SwapIn();
1053 if( bRet && mpMgr )
1054 mpMgr->ImplGraphicObjectWasSwappedIn( *this );
1057 if( bRet )
1058 ImplAssignGraphicData();
1060 return bRet;
1063 void GraphicObject::SetSwapState()
1065 if( !IsSwappedOut() )
1067 mbAutoSwapped = sal_True;
1069 if( mpMgr )
1070 mpMgr->ImplGraphicObjectWasSwappedOut( *this );
1074 IMPL_LINK_NOARG(GraphicObject, ImplAutoSwapOutHdl)
1076 if( !IsSwappedOut() )
1078 mbIsInSwapOut = sal_True;
1080 SvStream* pStream = GetSwapStream();
1082 if( GRFMGR_AUTOSWAPSTREAM_NONE != pStream )
1084 if( GRFMGR_AUTOSWAPSTREAM_LINK == pStream )
1085 mbAutoSwapped = SwapOut( NULL );
1086 else
1088 if( GRFMGR_AUTOSWAPSTREAM_TEMP == pStream )
1089 mbAutoSwapped = SwapOut();
1090 else
1092 mbAutoSwapped = SwapOut( pStream );
1093 delete pStream;
1098 mbIsInSwapOut = sal_False;
1101 if( mpSwapOutTimer )
1102 mpSwapOutTimer->Start();
1104 return 0L;
1107 SvStream& operator>>( SvStream& rIStm, GraphicObject& rGraphicObj )
1109 VersionCompat aCompat( rIStm, STREAM_READ );
1110 Graphic aGraphic;
1111 GraphicAttr aAttr;
1112 sal_Bool bLink;
1114 rIStm >> aGraphic >> aAttr >> bLink;
1116 rGraphicObj.SetGraphic( aGraphic );
1117 rGraphicObj.SetAttr( aAttr );
1119 if( bLink )
1121 OUString aLink = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(rIStm, RTL_TEXTENCODING_UTF8);
1122 rGraphicObj.SetLink(aLink);
1124 else
1125 rGraphicObj.SetLink();
1127 rGraphicObj.SetSwapStreamHdl();
1129 return rIStm;
1132 SvStream& operator<<( SvStream& rOStm, const GraphicObject& rGraphicObj )
1134 VersionCompat aCompat( rOStm, STREAM_WRITE, 1 );
1135 const sal_Bool bLink = rGraphicObj.HasLink();
1137 rOStm << rGraphicObj.GetGraphic() << rGraphicObj.GetAttr() << bLink;
1139 if( bLink )
1140 write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(rOStm, rGraphicObj.GetLink(), RTL_TEXTENCODING_UTF8);
1142 return rOStm;
1145 #define UNO_NAME_GRAPHOBJ_URLPREFIX "vnd.sun.star.GraphicObject:"
1147 GraphicObject GraphicObject::CreateGraphicObjectFromURL( const OUString &rURL )
1149 const OUString aURL( rURL ), aPrefix( UNO_NAME_GRAPHOBJ_URLPREFIX );
1150 if( aURL.startsWith( aPrefix ) )
1152 // graphic manager url
1153 OString aUniqueID(OUStringToOString(rURL.copy(sizeof(UNO_NAME_GRAPHOBJ_URLPREFIX) - 1), RTL_TEXTENCODING_UTF8));
1154 return GraphicObject( aUniqueID );
1156 else
1158 Graphic aGraphic;
1159 if ( !aURL.isEmpty() )
1161 SvStream* pStream = utl::UcbStreamHelper::CreateStream( aURL, STREAM_READ );
1162 if( pStream )
1164 GraphicConverter::Import( *pStream, aGraphic );
1165 delete pStream;
1169 return GraphicObject( aGraphic );
1173 void
1174 GraphicObject::InspectForGraphicObjectImageURL( const Reference< XInterface >& xIf, std::vector< OUString >& rvEmbedImgUrls )
1176 static OUString sImageURL( "ImageURL" );
1177 Reference< XPropertySet > xProps( xIf, UNO_QUERY );
1178 if ( xProps.is() )
1181 if ( xProps->getPropertySetInfo()->hasPropertyByName( sImageURL ) )
1183 OUString sURL;
1184 xProps->getPropertyValue( sImageURL ) >>= sURL;
1185 if ( !sURL.isEmpty() && sURL.startsWith( UNO_NAME_GRAPHOBJ_URLPREFIX ) )
1186 rvEmbedImgUrls.push_back( sURL );
1189 Reference< XNameContainer > xContainer( xIf, UNO_QUERY );
1190 if ( xContainer.is() )
1192 Sequence< OUString > sNames = xContainer->getElementNames();
1193 sal_Int32 nContainees = sNames.getLength();
1194 for ( sal_Int32 index = 0; index < nContainees; ++index )
1196 Reference< XInterface > xCtrl;
1197 xContainer->getByName( sNames[ index ] ) >>= xCtrl;
1198 InspectForGraphicObjectImageURL( xCtrl, rvEmbedImgUrls );
1203 // calculate scalings between real image size and logic object size. This
1204 // is necessary since the crop values are relative to original bitmap size
1205 basegfx::B2DVector GraphicObject::calculateCropScaling(
1206 double fWidth,
1207 double fHeight,
1208 double fLeftCrop,
1209 double fTopCrop,
1210 double fRightCrop,
1211 double fBottomCrop) const
1213 const MapMode aMapMode100thmm(MAP_100TH_MM);
1214 Size aBitmapSize(GetPrefSize());
1215 double fFactorX(1.0);
1216 double fFactorY(1.0);
1218 if(MAP_PIXEL == GetPrefMapMode().GetMapUnit())
1220 aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm);
1222 else
1224 aBitmapSize = Application::GetDefaultDevice()->LogicToLogic(aBitmapSize, GetPrefMapMode(), aMapMode100thmm);
1227 const double fDivX(aBitmapSize.Width() - fLeftCrop - fRightCrop);
1228 const double fDivY(aBitmapSize.Height() - fTopCrop - fBottomCrop);
1230 if(!basegfx::fTools::equalZero(fDivX))
1232 fFactorX = fabs(fWidth) / fDivX;
1235 if(!basegfx::fTools::equalZero(fDivY))
1237 fFactorY = fabs(fHeight) / fDivY;
1240 return basegfx::B2DVector(fFactorX,fFactorY);
1243 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */