merge the formfield patch from ooo-build
[ooovba.git] / drawinglayer / source / primitive2d / graphicprimitive2d.cxx
blobe5de786032913eac5d83f98811af3b97e9a0a137
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: graphicprimitive2d.cxx,v $
7 * $Revision: 1.3 $
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,
32 * MA 02111-1307 USA
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 //////////////////////////////////////////////////////////////////////////////
60 namespace
62 struct animationStep
64 BitmapEx maBitmapEx;
65 sal_uInt32 mnTime;
68 class animatedBitmapExPreparator
70 ::Animation maAnimation;
71 ::std::vector< animationStep > maSteps;
73 sal_uInt32 generateStepTime(sal_uInt32 nIndex) const;
75 public:
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);
89 // #115934#
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
92 // is selected.
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.
102 if(0L == nWaitTime)
104 nWaitTime = 100L;
107 return nWaitTime;
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);
135 // prepare step
136 const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a));
138 switch(rAnimBitmap.eDisposal)
140 case DISPOSE_NOT:
142 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
143 Bitmap aMask = rAnimBitmap.aBmpEx.GetMask();
145 if(aMask.IsEmpty())
147 const Point aEmpty;
148 const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel());
149 const Wallpaper aWallpaper(COL_BLACK);
150 aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper);
152 else
154 BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask);
155 aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask);
158 break;
160 case DISPOSE_BACK:
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);
169 if(aMask.IsEmpty())
171 const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel());
172 aVirtualDeviceMask.SetFillColor(COL_BLACK);
173 aVirtualDeviceMask.SetLineColor();
174 aVirtualDeviceMask.DrawRect(aRect);
176 else
178 aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask);
181 break;
183 case DISPOSE_FULL:
185 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
186 break;
188 case DISPOSE_PREVIOUS :
190 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
191 aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask());
192 break;
196 // create BitmapEx
197 Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel());
198 Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap(Point(), aVirtualDeviceMask.GetOutputSizePixel());
199 aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap);
201 // add to vector
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);
237 if(aData.count())
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));
259 else
261 xPrimitive = Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic.GetBitmapEx(), getTransform()));
264 break;
267 case GRAPHIC_GDIMETAFILE :
269 // create MetafilePrimitive2D
270 const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile();
272 xPrimitive = Primitive2DReference(
273 new MetafilePrimitive2D(
274 getTransform(),
275 rMetafile));
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(
296 new MaskPrimitive2D(
297 basegfx::B2DPolyPolygon(aMaskPolygon),
298 aChildContent));
301 break;
304 default:
306 // nothing to create
307 break;
311 if(xPrimitive.is())
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);
338 else
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
367 else
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);
386 else
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);
398 else
400 // add to decomposition
401 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive);
406 return aRetval;
409 GraphicPrimitive2D::GraphicPrimitive2D(
410 const basegfx::B2DHomMatrix& rTransform,
411 const GraphicObject& rGraphicObject,
412 const GraphicAttr& rGraphicAttr)
413 : BasePrimitive2D(),
414 maTransform(rTransform),
415 maGraphicObject(rGraphicObject),
416 maGraphicAttr(rGraphicAttr)
420 GraphicPrimitive2D::GraphicPrimitive2D(
421 const basegfx::B2DHomMatrix& rTransform,
422 const GraphicObject& rGraphicObject)
423 : BasePrimitive2D(),
424 maTransform(rTransform),
425 maGraphicObject(rGraphicObject),
426 maGraphicAttr()
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());
441 return false;
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());
448 return aRetval;
451 // provide unique ID
452 ImplPrimitrive2DIDBlock(GraphicPrimitive2D, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D)
454 } // end of namespace primitive2d
455 } // end of namespace drawinglayer
457 //////////////////////////////////////////////////////////////////////////////
458 // eof