Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <drawinglayer/primitive2d/graphicprimitivehelper2d.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 <drawinglayer/primitive2d/maskprimitive2d.hxx>
27 : #include <basegfx/polygon/b2dpolygon.hxx>
28 : #include <basegfx/polygon/b2dpolygontools.hxx>
29 :
30 : //////////////////////////////////////////////////////////////////////////////
31 : // helper class for animated graphics
32 :
33 : #include <vcl/animate.hxx>
34 : #include <vcl/graph.hxx>
35 : #include <vcl/virdev.hxx>
36 : #include <vcl/svapp.hxx>
37 : #include <vcl/metaact.hxx>
38 :
39 : //////////////////////////////////////////////////////////////////////////////
40 : // includes for testing MetafilePrimitive2D::create2DDecomposition
41 :
42 : //////////////////////////////////////////////////////////////////////////////
43 :
44 : namespace
45 : {
46 0 : struct animationStep
47 : {
48 : BitmapEx maBitmapEx;
49 : sal_uInt32 mnTime;
50 : };
51 :
52 0 : class animatedBitmapExPreparator
53 : {
54 : ::Animation maAnimation;
55 : ::std::vector< animationStep > maSteps;
56 :
57 : sal_uInt32 generateStepTime(sal_uInt32 nIndex) const;
58 :
59 : public:
60 : animatedBitmapExPreparator(const Graphic& rGraphic);
61 :
62 0 : sal_uInt32 count() const { return maSteps.size(); }
63 0 : sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); }
64 0 : sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; }
65 0 : const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; }
66 : };
67 :
68 0 : sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const
69 : {
70 0 : const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex));
71 0 : sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10);
72 :
73 : // #115934#
74 : // Take care of special value for MultiPage TIFFs. ATM these shall just
75 : // show their first page. Later we will offer some switching when object
76 : // is selected.
77 0 : if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait)
78 : {
79 : // ATM the huge value would block the timer, so
80 : // use a long time to show first page (whole day)
81 0 : nWaitTime = 100 * 60 * 60 * 24;
82 : }
83 :
84 : // Bad trap: There are animated gifs with no set WaitTime (!).
85 : // In that case use a default value.
86 0 : if(0L == nWaitTime)
87 : {
88 0 : nWaitTime = 100L;
89 : }
90 :
91 0 : return nWaitTime;
92 : }
93 :
94 0 : animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic)
95 0 : : maAnimation(rGraphic.GetAnimation())
96 : {
97 : OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)");
98 :
99 : // #128539# secure access to Animation, looks like there exist animated GIFs out there
100 : // with a step count of zero
101 0 : if(maAnimation.Count())
102 : {
103 0 : VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
104 0 : VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L);
105 :
106 : // Prepare VirtualDevices and their states
107 0 : aVirtualDevice.EnableMapMode(sal_False);
108 0 : aVirtualDeviceMask.EnableMapMode(sal_False);
109 0 : aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
110 0 : aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
111 0 : aVirtualDevice.Erase();
112 0 : aVirtualDeviceMask.Erase();
113 :
114 0 : for(sal_uInt16 a(0L); a < maAnimation.Count(); a++)
115 : {
116 0 : animationStep aNextStep;
117 0 : aNextStep.mnTime = generateStepTime(a);
118 :
119 : // prepare step
120 0 : const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a));
121 :
122 0 : switch(rAnimBitmap.eDisposal)
123 : {
124 : case DISPOSE_NOT:
125 : {
126 0 : aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
127 0 : Bitmap aMask = rAnimBitmap.aBmpEx.GetMask();
128 :
129 0 : if(aMask.IsEmpty())
130 : {
131 0 : const Point aEmpty;
132 0 : const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel());
133 0 : const Wallpaper aWallpaper(COL_BLACK);
134 0 : aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper);
135 : }
136 : else
137 : {
138 0 : BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask);
139 0 : aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask);
140 : }
141 :
142 0 : break;
143 : }
144 : case DISPOSE_BACK:
145 : {
146 : // #i70772# react on no mask, for primitives, too.
147 0 : const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask());
148 0 : const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap());
149 :
150 0 : aVirtualDeviceMask.Erase();
151 0 : aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent);
152 :
153 0 : if(aMask.IsEmpty())
154 : {
155 0 : const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel());
156 0 : aVirtualDeviceMask.SetFillColor(COL_BLACK);
157 0 : aVirtualDeviceMask.SetLineColor();
158 0 : aVirtualDeviceMask.DrawRect(aRect);
159 : }
160 : else
161 : {
162 0 : aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask);
163 : }
164 :
165 0 : break;
166 : }
167 : case DISPOSE_FULL:
168 : {
169 0 : aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
170 0 : break;
171 : }
172 : case DISPOSE_PREVIOUS :
173 : {
174 0 : aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
175 0 : aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask());
176 0 : break;
177 : }
178 : }
179 :
180 : // create BitmapEx
181 0 : Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel());
182 : #if defined(MACOSX)
183 : AlphaMask aMaskBitmap( aVirtualDeviceMask.GetBitmap( Point(), aVirtualDeviceMask.GetOutputSizePixel()));
184 : #else
185 0 : Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap( Point(), aVirtualDeviceMask.GetOutputSizePixel());
186 : #endif
187 0 : aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap);
188 :
189 : // add to vector
190 0 : maSteps.push_back(aNextStep);
191 0 : }
192 : }
193 0 : }
194 : } // end of anonymous namespace
195 :
196 : //////////////////////////////////////////////////////////////////////////////
197 :
198 : namespace drawinglayer
199 : {
200 : namespace primitive2d
201 : {
202 18 : Primitive2DSequence create2DDecompositionOfGraphic(
203 : const Graphic& rGraphic,
204 : const basegfx::B2DHomMatrix& rTransform)
205 : {
206 18 : Primitive2DSequence aRetval;
207 :
208 18 : switch(rGraphic.GetType())
209 : {
210 : case GRAPHIC_BITMAP :
211 : {
212 14 : if(rGraphic.IsAnimated())
213 : {
214 : // prepare animation data
215 0 : animatedBitmapExPreparator aData(rGraphic);
216 :
217 0 : if(aData.count())
218 : {
219 : // create sub-primitives for animated bitmap and the needed animation loop
220 0 : animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff);
221 0 : Primitive2DSequence aBitmapPrimitives(aData.count());
222 :
223 0 : for(sal_uInt32 a(0); a < aData.count(); a++)
224 : {
225 0 : animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count());
226 0 : aAnimationLoop.append(aTime);
227 0 : aBitmapPrimitives[a] = new BitmapPrimitive2D(
228 : aData.stepBitmapEx(a),
229 0 : rTransform);
230 0 : }
231 :
232 : // prepare animation list
233 0 : animation::AnimationEntryList aAnimationList;
234 0 : aAnimationList.append(aAnimationLoop);
235 :
236 : // create and add animated switch primitive
237 0 : aRetval.realloc(1);
238 0 : aRetval[0] = new AnimatedSwitchPrimitive2D(
239 : aAnimationList,
240 : aBitmapPrimitives,
241 0 : false);
242 0 : }
243 : }
244 14 : else if(rGraphic.getSvgData().get())
245 : {
246 : // embedded Svg fill, create embed transform
247 0 : const basegfx::B2DRange& rSvgRange(rGraphic.getSvgData()->getRange());
248 :
249 0 : if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0))
250 : {
251 : // translate back to origin, scale to unit coordinates
252 : basegfx::B2DHomMatrix aEmbedSvg(
253 : basegfx::tools::createTranslateB2DHomMatrix(
254 0 : -rSvgRange.getMinX(),
255 0 : -rSvgRange.getMinY()));
256 :
257 : aEmbedSvg.scale(
258 0 : 1.0 / rSvgRange.getWidth(),
259 0 : 1.0 / rSvgRange.getHeight());
260 :
261 : // apply created object transformation
262 0 : aEmbedSvg = rTransform * aEmbedSvg;
263 :
264 : // add Svg primitives embedded
265 0 : aRetval.realloc(1);
266 0 : aRetval[0] = new TransformPrimitive2D(
267 : aEmbedSvg,
268 0 : rGraphic.getSvgData()->getPrimitive2DSequence());
269 : }
270 : }
271 : else
272 : {
273 14 : aRetval.realloc(1);
274 42 : aRetval[0] = new BitmapPrimitive2D(
275 : rGraphic.GetBitmapEx(),
276 28 : rTransform);
277 : }
278 :
279 14 : break;
280 : }
281 :
282 : case GRAPHIC_GDIMETAFILE :
283 : {
284 : // create MetafilePrimitive2D
285 4 : const GDIMetaFile& rMetafile = rGraphic.GetGDIMetaFile();
286 :
287 4 : aRetval.realloc(1);
288 8 : aRetval[0] = new MetafilePrimitive2D(
289 : rTransform,
290 8 : rMetafile);
291 :
292 : // #i100357# find out if clipping is needed for this primitive. Unfortunately,
293 : // there exist Metafiles who's content is bigger than the proposed PrefSize set
294 : // at them. This is an error, but we need to work around this
295 4 : const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
296 : const Size aMetaFileRealSize(
297 : const_cast< GDIMetaFile& >(rMetafile).GetBoundRect(
298 4 : *Application::GetDefaultDevice()).GetSize());
299 :
300 8 : if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
301 4 : || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
302 : {
303 : // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon
304 0 : basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon());
305 0 : aMaskPolygon.transform(rTransform);
306 :
307 0 : aRetval[0] = new MaskPrimitive2D(
308 : basegfx::B2DPolyPolygon(aMaskPolygon),
309 0 : aRetval);
310 : }
311 4 : break;
312 : }
313 :
314 : default:
315 : {
316 : // nothing to create
317 0 : break;
318 : }
319 : }
320 :
321 18 : return aRetval;
322 : }
323 : } // end of namespace primitive2d
324 408 : } // end of namespace drawinglayer
325 :
326 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|