1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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
55 GrfSimpleCacheObj( const Graphic
& rGraphic
, const GraphicAttr
& rAttr
) :
56 maGraphic( rGraphic
), maAttr( rAttr
) {}
59 TYPEINIT1_AUTOFACTORY( GraphicObject
, SvDataCopyStream
);
61 GraphicObject::GraphicObject( const GraphicManager
* pMgr
) :
66 ImplAssignGraphicData();
67 ImplSetGraphicManager( pMgr
);
70 GraphicObject::GraphicObject( const Graphic
& rGraphic
, const GraphicManager
* pMgr
) :
71 maGraphic ( rGraphic
),
76 ImplAssignGraphicData();
77 ImplSetGraphicManager( pMgr
);
80 GraphicObject::GraphicObject( const GraphicObject
& rGraphicObj
, const GraphicManager
* pMgr
) :
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
)
88 ImplAssignGraphicData();
89 ImplSetGraphicManager( pMgr
, NULL
, &rGraphicObj
);
92 GraphicObject::GraphicObject( const OString
& rUniqueID
, const GraphicManager
* pMgr
) :
98 // assign default properties
99 ImplAssignGraphicData();
101 ImplSetGraphicManager( pMgr
, &rUniqueID
);
104 ImplAssignGraphicData();
107 GraphicObject::~GraphicObject()
111 mpMgr
->ImplUnregisterObj( *this );
113 if( ( mpMgr
== mpGlobalMgr
) && !mpGlobalMgr
->ImplHasObjects() )
114 delete mpGlobalMgr
, mpGlobalMgr
= NULL
;
117 delete mpSwapOutTimer
;
118 delete mpSwapStreamHdl
;
121 delete mpSimpleCache
;
124 void GraphicObject::ImplConstruct()
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
) )
159 mpMgr
->ImplUnregisterObj( *this );
161 if( ( mpMgr
== mpGlobalMgr
) && !mpGlobalMgr
->ImplHasObjects() )
162 delete mpGlobalMgr
, mpGlobalMgr
= NULL
;
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());
182 mpMgr
= (GraphicManager
*) pMgr
;
184 mpMgr
->ImplRegisterObj( *this, maGraphic
, pID
, pCopyObj
);
189 void GraphicObject::ImplAutoSwapIn()
193 if( mpMgr
&& mpMgr
->ImplFillSwappedGraphicObject( *this, maGraphic
) )
194 mbAutoSwapped
= sal_False
;
197 mbIsInSwapIn
= sal_True
;
199 if( maGraphic
.SwapIn() )
200 mbAutoSwapped
= sal_False
;
203 SvStream
* pStream
= GetSwapStream();
205 if( GRFMGR_AUTOSWAPSTREAM_NONE
!= pStream
)
207 if( GRFMGR_AUTOSWAPSTREAM_LINK
== pStream
)
213 if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( GetLink(), aURLStr
) )
215 SvStream
* pIStm
= ::utl::UcbStreamHelper::CreateStream( aURLStr
, STREAM_READ
);
219 (*pIStm
) >> maGraphic
;
220 mbAutoSwapped
= ( maGraphic
.GetType() != GRAPHIC_NONE
);
226 else if( GRFMGR_AUTOSWAPSTREAM_TEMP
== pStream
)
227 mbAutoSwapped
= !maGraphic
.SwapIn();
228 else if( GRFMGR_AUTOSWAPSTREAM_LOADED
== pStream
)
229 mbAutoSwapped
= maGraphic
.IsSwapOut();
232 mbAutoSwapped
= !maGraphic
.SwapIn( pStream
);
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
);
263 long nTotalWidth
, nTotalHeight
;
267 aClipPoly
.Rotate( rPt
, nRot10
);
268 bRectClipRegion
= sal_False
;
271 bRectClipRegion
= sal_True
;
273 rClipPolyPoly
= aClipPoly
;
275 if( maGraphic
.GetPrefMapMode() == MAP_PIXEL
)
276 aSize100
= Application::GetDefaultDevice()->PixelToLogic( maGraphic
.GetPrefSize(), aMap100
);
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
);
306 Polygon
aOriginPoly( 1 );
308 aOriginPoly
[ 0 ] = rPt
;
309 aOriginPoly
.Rotate( aOldOrigin
, nRot10
);
310 rPt
= aOriginPoly
[ 0 ];
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
;
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
);
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
)
357 void GraphicObject::Save( SvStream
& rOStm
)
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();
375 aRet
= mpMgr
->ImplGetUniqueID( *this );
380 SvStream
* GraphicObject::GetSwapStream() const
382 return( HasSwapStreamHdl() ? (SvStream
*) mpSwapStreamHdl
->Call( (void*) this ) : GRFMGR_AUTOSWAPSTREAM_NONE
);
385 void GraphicObject::SetAttr( const GraphicAttr
& rAttr
)
389 if( mpSimpleCache
&& ( mpSimpleCache
->maAttr
!= rAttr
) )
390 delete mpSimpleCache
, mpSimpleCache
= NULL
;
393 void GraphicObject::SetLink()
396 delete mpLink
, mpLink
= NULL
;
399 void GraphicObject::SetLink( const String
& rLink
)
401 delete mpLink
, mpLink
= new String( rLink
);
404 String
GraphicObject::GetLink() const
412 void GraphicObject::SetUserData()
415 delete mpUserData
, mpUserData
= NULL
;
418 void GraphicObject::SetUserData( const String
& rUserData
)
420 delete mpUserData
, mpUserData
= new String( rUserData
);
423 String
GraphicObject::GetUserData() const
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();
456 delete mpSwapOutTimer
, mpSwapOutTimer
= NULL
;
459 void GraphicObject::FireSwapInRequest()
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
473 ImplSetGraphicManager( NULL
);
476 sal_Bool
GraphicObject::IsCached( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
477 const GraphicAttr
* pAttr
, sal_uLong nFlags
) const
481 if( nFlags
& GRFMGR_DRAW_CACHED
)
485 if ( pAttr
->IsCropped() )
487 PolyPolygon aClipPolyPoly
;
489 ImplGetCropParams( pOut
, aPt
, aSz
, pAttr
, aClipPolyPoly
, bRectClip
);
491 bRet
= mpMgr
->IsInCache( pOut
, aPt
, aSz
, *this, ( pAttr
? *pAttr
: GetAttr() ) );
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() );
511 const sal_uInt32 nOldDrawMode
= pOut
->GetDrawMode();
512 sal_Bool bCropped
= aAttr
.IsCropped();
513 sal_Bool bCached
= sal_False
;
516 // #i29534# Provide output rects for PDF writer
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
);
540 PolyPolygon aClipPolyPoly
;
542 const sal_Bool bCrop
= ImplGetCropParams( pOut
, aPt
, aSz
, &aAttr
, aClipPolyPoly
, bRectClip
);
544 pOut
->Push( PUSH_CLIPREGION
);
550 // #i29534# Store crop rect for later forwarding to
552 aCropRect
= aClipPolyPoly
.GetBoundRect();
553 pOut
->IntersectClipRegion( aCropRect
);
557 pOut
->IntersectClipRegion(Region(aClipPolyPoly
));
562 bRet
= mpMgr
->DrawObj( pOut
, aPt
, aSz
, *this, aAttr
, nFlags
, bCached
);
567 pOut
->SetDrawMode( nOldDrawMode
);
569 // #i29534# Moved below OutDev restoration, to avoid multiple swap-ins
570 // (code above needs to call GetGraphic twice)
574 mpSwapOutTimer
->Start();
576 FireSwapOutRequest();
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
);
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() &&
603 !aGrfAttr
.IsSpecialDrawMode() &&
604 !aGrfAttr
.IsMirrored() &&
605 !aGrfAttr
.IsRotated() &&
606 !aGrfAttr
.IsAdjusted() )
608 bWritingPdfLinkedGraphic
= true;
610 if( aGrfAttr
.IsCropped() )
612 PolyPolygon aClipPolyPoly
;
614 const sal_Bool bCrop
= ImplGetCropParams( &rOutDev
,
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
),
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 )
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
;
673 if( !IsSwappedOut() )
675 const GraphicAttr
aAttr( pAttr
? *pAttr
: GetAttr() );
681 sal_Bool bCropped
= aAttr
.IsCropped();
685 PolyPolygon aClipPolyPoly
;
687 const sal_Bool bCrop
= ImplGetCropParams( pOut
, aPt
, aSz
, &aAttr
, aClipPolyPoly
, bRectClip
);
689 pOut
->Push( PUSH_CLIPREGION
);
694 pOut
->IntersectClipRegion( aClipPolyPoly
.GetBoundRect() );
696 pOut
->IntersectClipRegion(Region(aClipPolyPoly
));
700 if( !mpSimpleCache
|| ( mpSimpleCache
->maAttr
!= aAttr
) || pFirstFrameOutDev
)
703 delete mpSimpleCache
;
705 mpSimpleCache
= new GrfSimpleCacheObj( GetTransformedGraphic( &aAttr
), aAttr
);
706 mpSimpleCache
->maGraphic
.SetAnimationNotifyHdl( GetAnimationNotifyHdl() );
709 mpSimpleCache
->maGraphic
.StartAnimation( pOut
, aPt
, aSz
, nExtraData
, pFirstFrameOutDev
);
717 bRet
= Draw( pOut
, rPt
, rSz
, &aAttr
, GRFMGR_DRAW_STANDARD
);
723 void GraphicObject::StopAnimation( OutputDevice
* pOut
, long nExtraData
)
726 mpSimpleCache
->maGraphic
.StopAnimation( pOut
, nExtraData
);
729 const Graphic
& GraphicObject::GetGraphic() const
732 ( (GraphicObject
*) this )->ImplAutoSwapIn();
737 void GraphicObject::SetGraphic( const Graphic
& rGraphic
, const GraphicObject
* pCopyObj
)
739 mpMgr
->ImplUnregisterObj( *this );
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
);
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
);
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() ),
785 aCropRightBottom
= Application::GetDefaultDevice()->LogicToPixel( Size( rAttr
.GetRightCrop(),
786 rAttr
.GetBottomCrop() ),
791 aCropLeftTop
= OutputDevice::LogicToLogic( Size( rAttr
.GetLeftCrop(),
792 rAttr
.GetTopCrop() ),
795 aCropRightBottom
= OutputDevice::LogicToLogic( Size( rAttr
.GetRightCrop(),
796 rAttr
.GetBottomCrop() ),
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
);
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() ),
851 aCropRightBottom
= Application::GetDefaultDevice()->LogicToPixel( Size( rAttr
.GetRightCrop(),
852 rAttr
.GetBottomCrop() ),
855 // convert from prefmapmode to pixel
856 const Size
aSrcSizePixel( Application::GetDefaultDevice()->LogicToPixel( aSrcSize
,
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() )
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
;
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
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
)
961 Animation
aAnimation( maGraphic
.GetAnimation() );
962 GraphicManager::ImplAdjust( aAnimation
, aAttr
, ADJUSTMENT_ALL
);
963 aAnimation
.SetLoopCount( mnAnimationLoopCount
);
964 aGraphic
= aAnimation
;
968 BitmapEx
aBmpEx( maGraphic
.GetBitmapEx() );
969 GraphicManager::ImplAdjust( aBmpEx
, aAttr
, ADJUSTMENT_ALL
);
975 GDIMetaFile
aMtf( maGraphic
.GetGDIMetaFile() );
976 GraphicManager::ImplAdjust( aMtf
, aAttr
, ADJUSTMENT_ALL
);
982 if( ( GetType() == GRAPHIC_BITMAP
) && IsAnimated() )
984 Animation
aAnimation( maGraphic
.GetAnimation() );
985 aAnimation
.SetLoopCount( mnAnimationLoopCount
);
986 aGraphic
= aAnimation
;
989 aGraphic
= maGraphic
;
996 sal_Bool
GraphicObject::SwapOut()
998 sal_Bool bRet
= ( !mbAutoSwapped
? maGraphic
.SwapOut() : sal_False
);
1001 mpMgr
->ImplGraphicObjectWasSwappedOut( *this );
1006 sal_Bool
GraphicObject::SwapOut( SvStream
* pOStm
)
1008 sal_Bool bRet
= ( !mbAutoSwapped
? maGraphic
.SwapOut( pOStm
) : sal_False
);
1011 mpMgr
->ImplGraphicObjectWasSwappedOut( *this );
1016 sal_Bool
GraphicObject::SwapIn()
1025 else if( mpMgr
&& mpMgr
->ImplFillSwappedGraphicObject( *this, maGraphic
) )
1029 bRet
= maGraphic
.SwapIn();
1032 mpMgr
->ImplGraphicObjectWasSwappedIn( *this );
1036 ImplAssignGraphicData();
1041 void GraphicObject::SetSwapState()
1043 if( !IsSwappedOut() )
1045 mbAutoSwapped
= sal_True
;
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
);
1066 if( GRFMGR_AUTOSWAPSTREAM_TEMP
== pStream
)
1067 mbAutoSwapped
= SwapOut();
1070 mbAutoSwapped
= SwapOut( pStream
);
1076 mbIsInSwapOut
= sal_False
;
1079 if( mpSwapOutTimer
)
1080 mpSwapOutTimer
->Start();
1085 SvStream
& operator>>( SvStream
& rIStm
, GraphicObject
& rGraphicObj
)
1087 VersionCompat
aCompat( rIStm
, STREAM_READ
);
1092 rIStm
>> aGraphic
>> aAttr
>> bLink
;
1094 rGraphicObj
.SetGraphic( aGraphic
);
1095 rGraphicObj
.SetAttr( aAttr
);
1099 OUString aLink
= read_lenPrefixed_uInt8s_ToOUString
<sal_uInt16
>(rIStm
, RTL_TEXTENCODING_UTF8
);
1100 rGraphicObj
.SetLink(aLink
);
1103 rGraphicObj
.SetLink();
1105 rGraphicObj
.SetSwapStreamHdl();
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
;
1118 write_lenPrefixed_uInt8s_FromOUString
<sal_uInt16
>(rOStm
, rGraphicObj
.GetLink(), RTL_TEXTENCODING_UTF8
);
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
);
1139 SvStream
* pStream
= utl::UcbStreamHelper::CreateStream( aURL
, STREAM_READ
);
1142 GraphicConverter::Import( *pStream
, aGraphic
);
1147 return GraphicObject( aGraphic
);
1152 GraphicObject::InspectForGraphicObjectImageURL( const Reference
< XInterface
>& xIf
, std::vector
< OUString
>& rvEmbedImgUrls
)
1154 static OUString
sImageURL( "ImageURL" );
1155 Reference
< XPropertySet
> xProps( xIf
, UNO_QUERY
);
1159 if ( xProps
->getPropertySetInfo()->hasPropertyByName( sImageURL
) )
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: */