fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / drawinglayer / source / primitive2d / graphicprimitive2d.cxx
blob00a248525b6cc8fb57d072cf98b46d3edf6edbf0
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 <drawinglayer/primitive2d/graphicprimitive2d.hxx>
21 #include <drawinglayer/animation/animationtiming.hxx>
22 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
23 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
24 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
25 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
26 #include <basegfx/polygon/b2dpolygon.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <drawinglayer/primitive2d/cropprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
30 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
32 //////////////////////////////////////////////////////////////////////////////
33 // helper class for animated graphics
35 #include <vcl/animate.hxx>
36 #include <vcl/graph.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/metaact.hxx>
41 //////////////////////////////////////////////////////////////////////////////
42 // includes for testing MetafilePrimitive2D::create2DDecomposition
44 //////////////////////////////////////////////////////////////////////////////
46 namespace
48 struct animationStep
50 BitmapEx maBitmapEx;
51 sal_uInt32 mnTime;
54 class animatedBitmapExPreparator
56 ::Animation maAnimation;
57 ::std::vector< animationStep > maSteps;
59 sal_uInt32 generateStepTime(sal_uInt32 nIndex) const;
61 public:
62 explicit animatedBitmapExPreparator(const Graphic& rGraphic);
64 sal_uInt32 count() const { return maSteps.size(); }
65 sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); }
66 sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; }
67 const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; }
70 sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const
72 const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex));
73 sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10);
75 // #115934#
76 // Take care of special value for MultiPage TIFFs. ATM these shall just
77 // show their first page. Later we will offer some switching when object
78 // is selected.
79 if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait)
81 // ATM the huge value would block the timer, so
82 // use a long time to show first page (whole day)
83 nWaitTime = 100 * 60 * 60 * 24;
86 // Bad trap: There are animated gifs with no set WaitTime (!).
87 // In that case use a default value.
88 if(0L == nWaitTime)
90 nWaitTime = 100L;
93 return nWaitTime;
96 animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic)
97 : maAnimation(rGraphic.GetAnimation())
99 OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)");
101 // #128539# secure access to Animation, looks like there exist animated GIFs out there
102 // with a step count of zero
103 if(maAnimation.Count())
105 VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
106 VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L);
108 // Prepare VirtualDevices and their states
109 aVirtualDevice.EnableMapMode(sal_False);
110 aVirtualDeviceMask.EnableMapMode(sal_False);
111 aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
112 aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
113 aVirtualDevice.Erase();
114 aVirtualDeviceMask.Erase();
116 for(sal_uInt16 a(0L); a < maAnimation.Count(); a++)
118 animationStep aNextStep;
119 aNextStep.mnTime = generateStepTime(a);
121 // prepare step
122 const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a));
124 switch(rAnimBitmap.eDisposal)
126 case DISPOSE_NOT:
128 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
129 Bitmap aMask = rAnimBitmap.aBmpEx.GetMask();
131 if(aMask.IsEmpty())
133 const Point aEmpty;
134 const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel());
135 const Wallpaper aWallpaper(COL_BLACK);
136 aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper);
138 else
140 BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask);
141 aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask);
144 break;
146 case DISPOSE_BACK:
148 // #i70772# react on no mask, for primitives, too.
149 const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask());
150 const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap());
152 aVirtualDeviceMask.Erase();
153 aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent);
155 if(aMask.IsEmpty())
157 const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel());
158 aVirtualDeviceMask.SetFillColor(COL_BLACK);
159 aVirtualDeviceMask.SetLineColor();
160 aVirtualDeviceMask.DrawRect(aRect);
162 else
164 aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask);
167 break;
169 case DISPOSE_FULL:
171 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
172 break;
174 case DISPOSE_PREVIOUS :
176 aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
177 aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask());
178 break;
182 // create BitmapEx
183 Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel());
184 Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap(Point(), aVirtualDeviceMask.GetOutputSizePixel());
185 aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap);
187 // add to vector
188 maSteps.push_back(aNextStep);
192 } // end of anonymous namespace
194 //////////////////////////////////////////////////////////////////////////////
196 namespace drawinglayer
198 namespace primitive2d
200 Primitive2DSequence GraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D&
201 ) const
203 Primitive2DSequence aRetval;
205 if(255L != getGraphicAttr().GetTransparency())
207 Primitive2DReference xPrimitive;
209 // do not apply mirroring from GraphicAttr to the Metafile by calling
210 // GetTransformedGraphic, this will try to mirror the Metafile using Scale()
211 // at the Metafile. This again calls Scale at the single MetaFile actions,
212 // but this implementation never worked. I reworked that implementations,
213 // but for security reasons i will try not to use it.
214 basegfx::B2DHomMatrix aTransform(getTransform());
216 if(getGraphicAttr().IsMirrored())
218 // content needs mirroring
219 const bool bHMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_HORZ);
220 const bool bVMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_VERT);
222 // mirror by applying negative scale to the unit primitive and
223 // applying the object transformation on it.
224 aTransform = basegfx::tools::createScaleB2DHomMatrix(
225 bHMirr ? -1.0 : 1.0,
226 bVMirr ? -1.0 : 1.0);
227 aTransform.translate(
228 bHMirr ? 1.0 : 0.0,
229 bVMirr ? 1.0 : 0.0);
230 aTransform = getTransform() * aTransform;
233 // Get transformed graphic. Suppress rotation and cropping, only filtering is needed
234 // here (and may be replaced later on). Cropping is handled below as mask primitive (if set).
235 // Also need to suppress mirroring, it is part of the transformation now (see above).
236 GraphicAttr aSuppressGraphicAttr(getGraphicAttr());
237 aSuppressGraphicAttr.SetCrop(0, 0, 0, 0);
238 aSuppressGraphicAttr.SetRotation(0);
239 aSuppressGraphicAttr.SetMirrorFlags(0);
241 const GraphicObject& rGraphicObject = getGraphicObject();
242 const Graphic aTransformedGraphic(rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr));
244 switch(aTransformedGraphic.GetType())
246 case GRAPHIC_BITMAP :
248 if(aTransformedGraphic.IsAnimated())
250 // prepare animation data
251 animatedBitmapExPreparator aData(aTransformedGraphic);
253 if(aData.count())
255 // create sub-primitives for animated bitmap and the needed animation loop
256 animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff);
257 Primitive2DSequence aBitmapPrimitives(aData.count());
259 for(sal_uInt32 a(0L); a < aData.count(); a++)
261 animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count());
262 aAnimationLoop.append(aTime);
263 const Primitive2DReference xRef(new BitmapPrimitive2D(aData.stepBitmapEx(a), aTransform));
264 aBitmapPrimitives[a] = xRef;
267 // prepare animation list
268 animation::AnimationEntryList aAnimationList;
269 aAnimationList.append(aAnimationLoop);
271 // create and add animated switch primitive
272 xPrimitive = Primitive2DReference(new AnimatedSwitchPrimitive2D(aAnimationList, aBitmapPrimitives, false));
275 else if(aTransformedGraphic.getSvgData().get())
277 // embedded Svg fill, create embed transform
278 const basegfx::B2DRange& rSvgRange(aTransformedGraphic.getSvgData()->getRange());
280 if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0))
282 // translate back to origin, scale to unit coordinates
283 basegfx::B2DHomMatrix aEmbedSvg(
284 basegfx::tools::createTranslateB2DHomMatrix(
285 -rSvgRange.getMinX(),
286 -rSvgRange.getMinY()));
288 aEmbedSvg.scale(
289 1.0 / rSvgRange.getWidth(),
290 1.0 / rSvgRange.getHeight());
292 // apply created object transformation
293 aEmbedSvg = aTransform * aEmbedSvg;
295 // add Svg primitives embedded
296 xPrimitive = new TransformPrimitive2D(
297 aEmbedSvg,
298 aTransformedGraphic.getSvgData()->getPrimitive2DSequence());
301 else
303 xPrimitive = Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic.GetBitmapEx(), aTransform));
306 break;
309 case GRAPHIC_GDIMETAFILE :
311 // create MetafilePrimitive2D
312 const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile();
314 xPrimitive = Primitive2DReference(
315 new MetafilePrimitive2D( aTransform, rMetafile ) );
317 // #i100357# find out if clipping is needed for this primitive. Unfortunately,
318 // there exist Metafiles who's content is bigger than the proposed PrefSize set
319 // at them. This is an error, but we need to work around this
320 const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
321 const Size aMetaFileRealSize(
322 const_cast< GDIMetaFile& >(rMetafile).GetBoundRect(
323 *Application::GetDefaultDevice()).GetSize());
325 if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
326 || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
328 // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon
329 const primitive2d::Primitive2DSequence aChildContent(&xPrimitive, 1);
330 basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon());
331 aMaskPolygon.transform(aTransform);
333 xPrimitive = Primitive2DReference(
334 new MaskPrimitive2D(
335 basegfx::B2DPolyPolygon(aMaskPolygon),
336 aChildContent));
338 break;
341 default:
343 // nothing to create
344 break;
348 if(xPrimitive.is())
350 // check for cropping
351 if(getGraphicAttr().IsCropped())
353 // calculate scalings between real image size and logic object size. This
354 // is necessary since the crop values are relative to original bitmap size
355 double fFactorX(1.0);
356 double fFactorY(1.0);
359 const MapMode aMapMode100thmm(MAP_100TH_MM);
360 Size aBitmapSize(rGraphicObject.GetPrefSize());
362 // #i95968# better support PrefMapMode; special for MAP_PIXEL was missing
363 if(MAP_PIXEL == rGraphicObject.GetPrefMapMode().GetMapUnit())
365 aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm);
367 else
369 aBitmapSize = Application::GetDefaultDevice()->LogicToLogic(aBitmapSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm);
372 const double fDivX(aBitmapSize.Width() - getGraphicAttr().GetLeftCrop() - getGraphicAttr().GetRightCrop());
373 const double fDivY(aBitmapSize.Height() - getGraphicAttr().GetTopCrop() - getGraphicAttr().GetBottomCrop());
374 const basegfx::B2DVector aScale(aTransform * basegfx::B2DVector(1.0, 1.0));
376 if(!basegfx::fTools::equalZero(fDivX))
378 fFactorX = fabs(aScale.getX()) / fDivX;
381 if(!basegfx::fTools::equalZero(fDivY))
383 fFactorY = fabs(aScale.getY()) / fDivY;
387 // embed content in cropPrimitive
388 xPrimitive = new CropPrimitive2D(
389 Primitive2DSequence(&xPrimitive, 1),
390 aTransform,
391 getGraphicAttr().GetLeftCrop() * fFactorX,
392 getGraphicAttr().GetTopCrop() * fFactorY,
393 getGraphicAttr().GetRightCrop() * fFactorX,
394 getGraphicAttr().GetBottomCrop() * fFactorY);
397 // add to decomposition
398 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive);
402 return aRetval;
405 GraphicPrimitive2D::GraphicPrimitive2D(
406 const basegfx::B2DHomMatrix& rTransform,
407 const GraphicObject& rGraphicObject,
408 const GraphicAttr& rGraphicAttr)
409 : BufferedDecompositionPrimitive2D(),
410 maTransform(rTransform),
411 maGraphicObject(rGraphicObject),
412 maGraphicAttr(rGraphicAttr)
416 bool GraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
418 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
420 const GraphicPrimitive2D& rCompare = (GraphicPrimitive2D&)rPrimitive;
422 return (getTransform() == rCompare.getTransform()
423 && getGraphicObject() == rCompare.getGraphicObject()
424 && getGraphicAttr() == rCompare.getGraphicAttr());
427 return false;
430 basegfx::B2DRange GraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
432 basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
433 aRetval.transform(getTransform());
434 return aRetval;
437 // provide unique ID
438 ImplPrimitive2DIDBlock(GraphicPrimitive2D, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D)
440 } // end of namespace primitive2d
441 } // end of namespace drawinglayer
443 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */