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 maLink ( rGraphicObj
.maLink
),
85 maUserData ( rGraphicObj
.maUserData
)
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
;
119 delete mpSimpleCache
;
122 void GraphicObject::ImplConstruct()
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
) )
157 mpMgr
->ImplUnregisterObj( *this );
159 if( ( mpMgr
== mpGlobalMgr
) && !mpGlobalMgr
->ImplHasObjects() )
160 delete mpGlobalMgr
, mpGlobalMgr
= NULL
;
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());
180 mpMgr
= (GraphicManager
*) pMgr
;
182 mpMgr
->ImplRegisterObj( *this, maGraphic
, pID
, pCopyObj
);
187 void GraphicObject::ImplAutoSwapIn()
191 if( mpMgr
&& mpMgr
->ImplFillSwappedGraphicObject( *this, maGraphic
) )
192 mbAutoSwapped
= sal_False
;
195 mbIsInSwapIn
= sal_True
;
197 if( maGraphic
.SwapIn() )
198 mbAutoSwapped
= sal_False
;
201 SvStream
* pStream
= GetSwapStream();
203 if( GRFMGR_AUTOSWAPSTREAM_NONE
!= pStream
)
205 if( GRFMGR_AUTOSWAPSTREAM_LINK
== pStream
)
211 if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( GetLink(), aURLStr
) )
213 SvStream
* pIStm
= ::utl::UcbStreamHelper::CreateStream( aURLStr
, STREAM_READ
);
217 (*pIStm
) >> maGraphic
;
218 mbAutoSwapped
= ( maGraphic
.GetType() != GRAPHIC_NONE
);
224 else if( GRFMGR_AUTOSWAPSTREAM_TEMP
== pStream
)
225 mbAutoSwapped
= !maGraphic
.SwapIn();
226 else if( GRFMGR_AUTOSWAPSTREAM_LOADED
== pStream
)
227 mbAutoSwapped
= maGraphic
.IsSwapOut();
230 mbAutoSwapped
= !maGraphic
.SwapIn( pStream
);
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
);
261 long nTotalWidth
, nTotalHeight
;
265 aClipPoly
.Rotate( rPt
, nRot10
);
266 bRectClipRegion
= sal_False
;
269 bRectClipRegion
= sal_True
;
271 rClipPolyPoly
= aClipPoly
;
273 if( maGraphic
.GetPrefMapMode() == MAP_PIXEL
)
274 aSize100
= Application::GetDefaultDevice()->PixelToLogic( maGraphic
.GetPrefSize(), aMap100
);
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
);
304 Polygon
aOriginPoly( 1 );
306 aOriginPoly
[ 0 ] = rPt
;
307 aOriginPoly
.Rotate( aOldOrigin
, nRot10
);
308 rPt
= aOriginPoly
[ 0 ];
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
);
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
)
353 void GraphicObject::Save( SvStream
& rOStm
)
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();
371 aRet
= mpMgr
->ImplGetUniqueID( *this );
376 SvStream
* GraphicObject::GetSwapStream() const
378 return( HasSwapStreamHdl() ? (SvStream
*) mpSwapStreamHdl
->Call( (void*) this ) : GRFMGR_AUTOSWAPSTREAM_NONE
);
381 void GraphicObject::SetAttr( const GraphicAttr
& rAttr
)
385 if( mpSimpleCache
&& ( mpSimpleCache
->maAttr
!= rAttr
) )
386 delete mpSimpleCache
, mpSimpleCache
= NULL
;
389 void GraphicObject::SetLink()
394 void GraphicObject::SetLink( const OUString
& rLink
)
399 void GraphicObject::SetUserData()
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();
434 delete mpSwapOutTimer
, mpSwapOutTimer
= NULL
;
437 void GraphicObject::FireSwapInRequest()
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
451 ImplSetGraphicManager( NULL
);
454 sal_Bool
GraphicObject::IsCached( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
455 const GraphicAttr
* pAttr
, sal_uLong nFlags
) const
459 if( nFlags
& GRFMGR_DRAW_CACHED
)
463 if ( pAttr
->IsCropped() )
465 PolyPolygon aClipPolyPoly
;
467 ImplGetCropParams( pOut
, aPt
, aSz
, pAttr
, aClipPolyPoly
, bRectClip
);
469 bRet
= mpMgr
->IsInCache( pOut
, aPt
, aSz
, *this, ( pAttr
? *pAttr
: GetAttr() ) );
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() );
489 const sal_uInt32 nOldDrawMode
= pOut
->GetDrawMode();
490 sal_Bool bCropped
= aAttr
.IsCropped();
491 sal_Bool bCached
= sal_False
;
494 // #i29534# Provide output rects for PDF writer
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
);
518 PolyPolygon aClipPolyPoly
;
520 const sal_Bool bCrop
= ImplGetCropParams( pOut
, aPt
, aSz
, &aAttr
, aClipPolyPoly
, bRectClip
);
522 pOut
->Push( PUSH_CLIPREGION
);
528 // #i29534# Store crop rect for later forwarding to
530 aCropRect
= aClipPolyPoly
.GetBoundRect();
531 pOut
->IntersectClipRegion( aCropRect
);
535 pOut
->IntersectClipRegion(Region(aClipPolyPoly
));
540 bRet
= mpMgr
->DrawObj( pOut
, aPt
, aSz
, *this, aAttr
, nFlags
, bCached
);
545 pOut
->SetDrawMode( nOldDrawMode
);
547 // #i29534# Moved below OutDev restoration, to avoid multiple swap-ins
548 // (code above needs to call GetGraphic twice)
552 mpSwapOutTimer
->Start();
554 FireSwapOutRequest();
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
);
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() &&
581 !aGrfAttr
.IsSpecialDrawMode() &&
582 !aGrfAttr
.IsMirrored() &&
583 !aGrfAttr
.IsRotated() &&
584 !aGrfAttr
.IsAdjusted() )
586 bWritingPdfLinkedGraphic
= true;
588 if( aGrfAttr
.IsCropped() )
590 PolyPolygon aClipPolyPoly
;
592 const sal_Bool bCrop
= ImplGetCropParams( &rOutDev
,
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
),
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 )
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
;
651 if( !IsSwappedOut() )
653 const GraphicAttr
aAttr( pAttr
? *pAttr
: GetAttr() );
659 sal_Bool bCropped
= aAttr
.IsCropped();
663 PolyPolygon aClipPolyPoly
;
665 const sal_Bool bCrop
= ImplGetCropParams( pOut
, aPt
, aSz
, &aAttr
, aClipPolyPoly
, bRectClip
);
667 pOut
->Push( PUSH_CLIPREGION
);
672 pOut
->IntersectClipRegion( aClipPolyPoly
.GetBoundRect() );
674 pOut
->IntersectClipRegion(Region(aClipPolyPoly
));
678 if( !mpSimpleCache
|| ( mpSimpleCache
->maAttr
!= aAttr
) || pFirstFrameOutDev
)
681 delete mpSimpleCache
;
683 mpSimpleCache
= new GrfSimpleCacheObj( GetTransformedGraphic( &aAttr
), aAttr
);
684 mpSimpleCache
->maGraphic
.SetAnimationNotifyHdl( GetAnimationNotifyHdl() );
687 mpSimpleCache
->maGraphic
.StartAnimation( pOut
, aPt
, aSz
, nExtraData
, pFirstFrameOutDev
);
695 bRet
= Draw( pOut
, rPt
, rSz
, &aAttr
, GRFMGR_DRAW_STANDARD
);
701 void GraphicObject::StopAnimation( OutputDevice
* pOut
, long nExtraData
)
704 mpSimpleCache
->maGraphic
.StopAnimation( pOut
, nExtraData
);
707 const Graphic
& GraphicObject::GetGraphic() const
710 ( (GraphicObject
*) this )->ImplAutoSwapIn();
715 void GraphicObject::SetGraphic( const Graphic
& rGraphic
, const GraphicObject
* pCopyObj
)
717 mpMgr
->ImplUnregisterObj( *this );
720 mpSwapOutTimer
->Stop();
722 maGraphic
= rGraphic
;
723 mbAutoSwapped
= sal_False
;
724 ImplAssignGraphicData();
726 delete mpSimpleCache
, mpSimpleCache
= NULL
;
728 mpMgr
->ImplRegisterObj( *this, maGraphic
, 0, pCopyObj
);
731 mpSwapOutTimer
->Start();
734 void GraphicObject::SetGraphic( const Graphic
& rGraphic
, const OUString
& rLink
)
736 SetGraphic( rGraphic
);
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
);
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()),
764 aCropRightBottom
= Application::GetDefaultDevice()->LogicToPixel(
765 Size(rAttr
.GetRightCrop(), rAttr
.GetBottomCrop()),
770 // crops are in GraphicObject units -> to aMapGraph
771 aCropLeftTop
= OutputDevice::LogicToLogic(
772 Size(rAttr
.GetLeftCrop(), rAttr
.GetTopCrop()),
775 aCropRightBottom
= OutputDevice::LogicToLogic(
776 Size(rAttr
.GetRightCrop(), rAttr
.GetBottomCrop()),
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
);
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() );
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()),
837 aCropRightBottom
= Application::GetDefaultDevice()->LogicToPixel(
838 Size(rAttr
.GetRightCrop(), rAttr
.GetBottomCrop()),
843 // crops are in GraphicObject units -> to MAP_PIXEL
844 aCropLeftTop
= Application::GetDefaultDevice()->LogicToPixel(
845 Size(rAttr
.GetLeftCrop(), rAttr
.GetTopCrop()),
847 aCropRightBottom
= Application::GetDefaultDevice()->LogicToPixel(
848 Size(rAttr
.GetRightCrop(), rAttr
.GetBottomCrop()),
852 // convert from prefmapmode to pixel
854 Application::GetDefaultDevice()->LogicToPixel(
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() )
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
;
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
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
)
983 Animation
aAnimation( maGraphic
.GetAnimation() );
984 GraphicManager::ImplAdjust( aAnimation
, aAttr
, ADJUSTMENT_ALL
);
985 aAnimation
.SetLoopCount( mnAnimationLoopCount
);
986 aGraphic
= aAnimation
;
990 BitmapEx
aBmpEx( maGraphic
.GetBitmapEx() );
991 GraphicManager::ImplAdjust( aBmpEx
, aAttr
, ADJUSTMENT_ALL
);
997 GDIMetaFile
aMtf( maGraphic
.GetGDIMetaFile() );
998 GraphicManager::ImplAdjust( aMtf
, aAttr
, ADJUSTMENT_ALL
);
1004 if( ( GetType() == GRAPHIC_BITMAP
) && IsAnimated() )
1006 Animation
aAnimation( maGraphic
.GetAnimation() );
1007 aAnimation
.SetLoopCount( mnAnimationLoopCount
);
1008 aGraphic
= aAnimation
;
1011 aGraphic
= maGraphic
;
1018 sal_Bool
GraphicObject::SwapOut()
1020 sal_Bool bRet
= ( !mbAutoSwapped
? maGraphic
.SwapOut() : sal_False
);
1023 mpMgr
->ImplGraphicObjectWasSwappedOut( *this );
1028 sal_Bool
GraphicObject::SwapOut( SvStream
* pOStm
)
1030 sal_Bool bRet
= ( !mbAutoSwapped
? maGraphic
.SwapOut( pOStm
) : sal_False
);
1033 mpMgr
->ImplGraphicObjectWasSwappedOut( *this );
1038 sal_Bool
GraphicObject::SwapIn()
1047 else if( mpMgr
&& mpMgr
->ImplFillSwappedGraphicObject( *this, maGraphic
) )
1051 bRet
= maGraphic
.SwapIn();
1054 mpMgr
->ImplGraphicObjectWasSwappedIn( *this );
1058 ImplAssignGraphicData();
1063 void GraphicObject::SetSwapState()
1065 if( !IsSwappedOut() )
1067 mbAutoSwapped
= sal_True
;
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
);
1088 if( GRFMGR_AUTOSWAPSTREAM_TEMP
== pStream
)
1089 mbAutoSwapped
= SwapOut();
1092 mbAutoSwapped
= SwapOut( pStream
);
1098 mbIsInSwapOut
= sal_False
;
1101 if( mpSwapOutTimer
)
1102 mpSwapOutTimer
->Start();
1107 SvStream
& operator>>( SvStream
& rIStm
, GraphicObject
& rGraphicObj
)
1109 VersionCompat
aCompat( rIStm
, STREAM_READ
);
1114 rIStm
>> aGraphic
>> aAttr
>> bLink
;
1116 rGraphicObj
.SetGraphic( aGraphic
);
1117 rGraphicObj
.SetAttr( aAttr
);
1121 OUString aLink
= read_lenPrefixed_uInt8s_ToOUString
<sal_uInt16
>(rIStm
, RTL_TEXTENCODING_UTF8
);
1122 rGraphicObj
.SetLink(aLink
);
1125 rGraphicObj
.SetLink();
1127 rGraphicObj
.SetSwapStreamHdl();
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
;
1140 write_lenPrefixed_uInt8s_FromOUString
<sal_uInt16
>(rOStm
, rGraphicObj
.GetLink(), RTL_TEXTENCODING_UTF8
);
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
);
1159 if ( !aURL
.isEmpty() )
1161 SvStream
* pStream
= utl::UcbStreamHelper::CreateStream( aURL
, STREAM_READ
);
1164 GraphicConverter::Import( *pStream
, aGraphic
);
1169 return GraphicObject( aGraphic
);
1174 GraphicObject::InspectForGraphicObjectImageURL( const Reference
< XInterface
>& xIf
, std::vector
< OUString
>& rvEmbedImgUrls
)
1176 static OUString
sImageURL( "ImageURL" );
1177 Reference
< XPropertySet
> xProps( xIf
, UNO_QUERY
);
1181 if ( xProps
->getPropertySetInfo()->hasPropertyByName( sImageURL
) )
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(
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
);
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: */