1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: graphicprimitive2d.cxx,v $
9 * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34 ************************************************************************/
36 // MARKER(update_precomp.py): autogen include statement, do not remove
37 #include "precompiled_drawinglayer.hxx"
39 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
40 #include <drawinglayer/animation/animationtiming.hxx>
41 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
42 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
43 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
44 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
45 #include <basegfx/polygon/b2dpolygon.hxx>
46 #include <basegfx/polygon/b2dpolygontools.hxx>
47 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
48 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
50 //////////////////////////////////////////////////////////////////////////////
51 // helper class for animated graphics
53 #include <vcl/animate.hxx>
54 #include <vcl/graph.hxx>
55 #include <vcl/virdev.hxx>
56 #include <vcl/svapp.hxx>
58 //////////////////////////////////////////////////////////////////////////////
68 class animatedBitmapExPreparator
70 ::Animation maAnimation
;
71 ::std::vector
< animationStep
> maSteps
;
73 sal_uInt32
generateStepTime(sal_uInt32 nIndex
) const;
76 animatedBitmapExPreparator(const Graphic
& rGraphic
);
78 sal_uInt32
count() const { return maSteps
.size(); }
79 sal_uInt32
loopCount() const { return (sal_uInt32
)maAnimation
.GetLoopCount(); }
80 sal_uInt32
stepTime(sal_uInt32 a
) const { return maSteps
[a
].mnTime
; }
81 const BitmapEx
& stepBitmapEx(sal_uInt32 a
) const { return maSteps
[a
].maBitmapEx
; }
84 sal_uInt32
animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex
) const
86 const AnimationBitmap
& rAnimBitmap
= maAnimation
.Get(sal_uInt16(nIndex
));
87 sal_uInt32
nWaitTime(rAnimBitmap
.nWait
* 10);
90 // Take care of special value for MultiPage TIFFs. ATM these shall just
91 // show their first page. Later we will offer some switching when object
93 if(ANIMATION_TIMEOUT_ON_CLICK
== rAnimBitmap
.nWait
)
95 // ATM the huge value would block the timer, so
96 // use a long time to show first page (whole day)
97 nWaitTime
= 100 * 60 * 60 * 24;
100 // Bad trap: There are animated gifs with no set WaitTime (!).
101 // In that case use a default value.
110 animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic
& rGraphic
)
111 : maAnimation(rGraphic
.GetAnimation())
113 OSL_ENSURE(GRAPHIC_BITMAP
== rGraphic
.GetType() && rGraphic
.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)");
115 // #128539# secure access to Animation, looks like there exist animated GIFs out there
116 // with a step count of zero
117 if(maAnimation
.Count())
119 VirtualDevice
aVirtualDevice(*Application::GetDefaultDevice());
120 VirtualDevice
aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L);
122 // Prepare VirtualDevices and their states
123 aVirtualDevice
.EnableMapMode(sal_False
);
124 aVirtualDeviceMask
.EnableMapMode(sal_False
);
125 aVirtualDevice
.SetOutputSizePixel(maAnimation
.GetDisplaySizePixel());
126 aVirtualDeviceMask
.SetOutputSizePixel(maAnimation
.GetDisplaySizePixel());
127 aVirtualDevice
.Erase();
128 aVirtualDeviceMask
.Erase();
130 for(sal_uInt16
a(0L); a
< maAnimation
.Count(); a
++)
132 animationStep aNextStep
;
133 aNextStep
.mnTime
= generateStepTime(a
);
136 const AnimationBitmap
& rAnimBitmap
= maAnimation
.Get(sal_uInt16(a
));
138 switch(rAnimBitmap
.eDisposal
)
142 aVirtualDevice
.DrawBitmapEx(rAnimBitmap
.aPosPix
, rAnimBitmap
.aBmpEx
);
143 Bitmap aMask
= rAnimBitmap
.aBmpEx
.GetMask();
148 const Rectangle
aRect(aEmpty
, aVirtualDeviceMask
.GetOutputSizePixel());
149 const Wallpaper
aWallpaper(COL_BLACK
);
150 aVirtualDeviceMask
.DrawWallpaper(aRect
, aWallpaper
);
154 BitmapEx aExpandVisibilityMask
= BitmapEx(aMask
, aMask
);
155 aVirtualDeviceMask
.DrawBitmapEx(rAnimBitmap
.aPosPix
, aExpandVisibilityMask
);
162 // #i70772# react on no mask, for primitives, too.
163 const Bitmap
aMask(rAnimBitmap
.aBmpEx
.GetMask());
164 const Bitmap
aContent(rAnimBitmap
.aBmpEx
.GetBitmap());
166 aVirtualDeviceMask
.Erase();
167 aVirtualDevice
.DrawBitmap(rAnimBitmap
.aPosPix
, aContent
);
171 const Rectangle
aRect(rAnimBitmap
.aPosPix
, aContent
.GetSizePixel());
172 aVirtualDeviceMask
.SetFillColor(COL_BLACK
);
173 aVirtualDeviceMask
.SetLineColor();
174 aVirtualDeviceMask
.DrawRect(aRect
);
178 aVirtualDeviceMask
.DrawBitmap(rAnimBitmap
.aPosPix
, aMask
);
185 aVirtualDevice
.DrawBitmapEx(rAnimBitmap
.aPosPix
, rAnimBitmap
.aBmpEx
);
188 case DISPOSE_PREVIOUS
:
190 aVirtualDevice
.DrawBitmapEx(rAnimBitmap
.aPosPix
, rAnimBitmap
.aBmpEx
);
191 aVirtualDeviceMask
.DrawBitmap(rAnimBitmap
.aPosPix
, rAnimBitmap
.aBmpEx
.GetMask());
197 Bitmap aMainBitmap
= aVirtualDevice
.GetBitmap(Point(), aVirtualDevice
.GetOutputSizePixel());
198 Bitmap aMaskBitmap
= aVirtualDeviceMask
.GetBitmap(Point(), aVirtualDeviceMask
.GetOutputSizePixel());
199 aNextStep
.maBitmapEx
= BitmapEx(aMainBitmap
, aMaskBitmap
);
202 maSteps
.push_back(aNextStep
);
206 } // end of anonymous namespace
208 //////////////////////////////////////////////////////////////////////////////
210 namespace drawinglayer
212 namespace primitive2d
214 Primitive2DSequence
GraphicPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
216 Primitive2DSequence aRetval
;
218 if(255L != getGraphicAttr().GetTransparency())
220 // get transformed graphic. Suppress rotation and cropping, only filtering is needed
221 // here (and may be replaced later on). Cropping is handled below as mask primitive (if set)
222 GraphicAttr
aSuppressGraphicAttr(getGraphicAttr());
223 aSuppressGraphicAttr
.SetCrop(0L, 0L, 0L, 0L);
224 aSuppressGraphicAttr
.SetRotation(0);
225 Graphic
aTransformedGraphic(getGraphicObject().GetTransformedGraphic(&aSuppressGraphicAttr
));
226 Primitive2DReference xPrimitive
;
228 switch(aTransformedGraphic
.GetType())
230 case GRAPHIC_BITMAP
:
232 if(aTransformedGraphic
.IsAnimated())
234 // prepare animation data
235 animatedBitmapExPreparator
aData(aTransformedGraphic
);
239 // create sub-primitives for animated bitmap and the needed animation loop
240 animation::AnimationEntryLoop
aAnimationLoop(aData
.loopCount() ? aData
.loopCount() : 0xffff);
241 Primitive2DSequence
aBitmapPrimitives(aData
.count());
243 for(sal_uInt32
a(0L); a
< aData
.count(); a
++)
245 animation::AnimationEntryFixed
aTime((double)aData
.stepTime(a
), (double)a
/ (double)aData
.count());
246 aAnimationLoop
.append(aTime
);
247 const Primitive2DReference
xRef(new BitmapPrimitive2D(aData
.stepBitmapEx(a
), getTransform()));
248 aBitmapPrimitives
[a
] = xRef
;
251 // prepare animation list
252 animation::AnimationEntryList aAnimationList
;
253 aAnimationList
.append(aAnimationLoop
);
255 // create and add animated switch primitive
256 xPrimitive
= Primitive2DReference(new AnimatedSwitchPrimitive2D(aAnimationList
, aBitmapPrimitives
, false));
261 xPrimitive
= Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic
.GetBitmapEx(), getTransform()));
267 case GRAPHIC_GDIMETAFILE
:
269 // create MetafilePrimitive2D
270 const GDIMetaFile
& rMetafile
= aTransformedGraphic
.GetGDIMetaFile();
272 xPrimitive
= Primitive2DReference(
273 new MetafilePrimitive2D(
277 // #i100357# find out if clipping is needed for this primitive. Unfortunately,
278 // there exist Metafiles who's content is bigger than the proposed PrefSize set
279 // at them. This is an error, but we need to work around this
280 const Size
aMetaFilePrefSize(rMetafile
.GetPrefSize());
281 const Size
aMetaFileRealSize(
282 const_cast< GDIMetaFile
& >(rMetafile
).GetBoundRect(
283 *Application::GetDefaultDevice()).GetSize());
285 if(aMetaFileRealSize
.getWidth() > aMetaFilePrefSize
.getWidth()
286 || aMetaFileRealSize
.getHeight() > aMetaFilePrefSize
.getHeight())
288 // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon
289 const primitive2d::Primitive2DSequence
aChildContent(&xPrimitive
, 1);
290 basegfx::B2DPolygon
aMaskPolygon(
291 basegfx::tools::createPolygonFromRect(
292 basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
293 aMaskPolygon
.transform(getTransform());
295 xPrimitive
= Primitive2DReference(
297 basegfx::B2DPolyPolygon(aMaskPolygon
),
313 // check for cropping
314 if(getGraphicAttr().IsCropped())
316 // decompose to get current pos and size
317 basegfx::B2DVector aScale
, aTranslate
;
318 double fRotate
, fShearX
;
319 getTransform().decompose(aScale
, aTranslate
, fRotate
, fShearX
);
321 // create ranges. The current object range is just scale and translate
322 const basegfx::B2DRange
aCurrent(aTranslate
.getX(), aTranslate
.getY(), aTranslate
.getX() + aScale
.getX(), aTranslate
.getY() + aScale
.getY());
324 // calculate scalings between real image size and logic object size. This
325 // is necessary since the crop values are relative to original bitmap size
326 double fFactorX(1.0);
327 double fFactorY(1.0);
330 const MapMode
aMapMode100thmm(MAP_100TH_MM
);
331 Size
aBitmapSize(getGraphicObject().GetPrefSize());
333 // #i95968# better support PrefMapMode; special for MAP_PIXEL was missing
334 if(MAP_PIXEL
== getGraphicObject().GetPrefMapMode().GetMapUnit())
336 aBitmapSize
= Application::GetDefaultDevice()->PixelToLogic(aBitmapSize
, aMapMode100thmm
);
340 aBitmapSize
= Application::GetDefaultDevice()->LogicToLogic(aBitmapSize
, getGraphicObject().GetPrefMapMode(), aMapMode100thmm
);
343 const double fDivX(aBitmapSize
.Width() - getGraphicAttr().GetLeftCrop() - getGraphicAttr().GetRightCrop());
344 const double fDivY(aBitmapSize
.Height() - getGraphicAttr().GetTopCrop() - getGraphicAttr().GetBottomCrop());
346 if(!basegfx::fTools::equalZero(fDivX
))
348 fFactorX
= aScale
.getX() / fDivX
;
351 if(!basegfx::fTools::equalZero(fDivY
))
353 fFactorY
= aScale
.getY() / fDivY
;
357 // Create cropped range, describes the bounds of the original graphic
358 basegfx::B2DRange aCropped
;
359 aCropped
.expand(aCurrent
.getMinimum() - basegfx::B2DPoint(getGraphicAttr().GetLeftCrop() * fFactorX
, getGraphicAttr().GetTopCrop() * fFactorY
));
360 aCropped
.expand(aCurrent
.getMaximum() + basegfx::B2DPoint(getGraphicAttr().GetRightCrop() * fFactorX
, getGraphicAttr().GetBottomCrop() * fFactorY
));
362 if(aCropped
.isEmpty())
364 // nothing to add since cropped bitmap is completely empty
365 // xPrimitive will not be used
369 // build new object transformation for transform primitive which contains xPrimitive
370 basegfx::B2DHomMatrix
aNewObjectTransform(getTransform());
371 aNewObjectTransform
.invert();
372 aNewObjectTransform
.scale(aCropped
.getWidth(), aCropped
.getHeight());
373 aNewObjectTransform
.translate(aCropped
.getMinX() - aCurrent
.getMinX(), aCropped
.getMinY() - aCurrent
.getMinY());
374 aNewObjectTransform
.shearX(fShearX
);
375 aNewObjectTransform
.rotate(fRotate
);
376 aNewObjectTransform
.translate(aTranslate
.getX(), aTranslate
.getY());
378 // prepare TransformPrimitive2D with xPrimitive
379 const Primitive2DReference
xTransformPrimitive(new TransformPrimitive2D(aNewObjectTransform
, Primitive2DSequence(&xPrimitive
, 1L)));
381 if(aCurrent
.isInside(aCropped
))
383 // cropped just got smaller, no need to really use a mask. Add to destination directly
384 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, xTransformPrimitive
);
388 // cropped got bigger, mask it with original object's bounds
389 basegfx::B2DPolyPolygon
aMaskPolyPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
390 aMaskPolyPolygon
.transform(getTransform());
392 // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector
393 const Primitive2DReference
xRefB(new MaskPrimitive2D(aMaskPolyPolygon
, Primitive2DSequence(&xTransformPrimitive
, 1L)));
394 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, xRefB
);
400 // add to decomposition
401 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, xPrimitive
);
409 GraphicPrimitive2D::GraphicPrimitive2D(
410 const basegfx::B2DHomMatrix
& rTransform
,
411 const GraphicObject
& rGraphicObject
,
412 const GraphicAttr
& rGraphicAttr
)
414 maTransform(rTransform
),
415 maGraphicObject(rGraphicObject
),
416 maGraphicAttr(rGraphicAttr
)
420 GraphicPrimitive2D::GraphicPrimitive2D(
421 const basegfx::B2DHomMatrix
& rTransform
,
422 const GraphicObject
& rGraphicObject
)
424 maTransform(rTransform
),
425 maGraphicObject(rGraphicObject
),
430 bool GraphicPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
432 if(BasePrimitive2D::operator==(rPrimitive
))
434 const GraphicPrimitive2D
& rCompare
= (GraphicPrimitive2D
&)rPrimitive
;
436 return (getTransform() == rCompare
.getTransform()
437 && getGraphicObject() == rCompare
.getGraphicObject()
438 && getGraphicAttr() == rCompare
.getGraphicAttr());
444 basegfx::B2DRange
GraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D
& /*rViewInformation*/) const
446 basegfx::B2DRange
aRetval(0.0, 0.0, 1.0, 1.0);
447 aRetval
.transform(getTransform());
452 ImplPrimitrive2DIDBlock(GraphicPrimitive2D
, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D
)
454 } // end of namespace primitive2d
455 } // end of namespace drawinglayer
457 //////////////////////////////////////////////////////////////////////////////