Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
30 : : #include <basegfx/tools/canvastools.hxx>
31 : : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
32 : : #include <basegfx/color/bcolor.hxx>
33 : : #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
34 : : #include <vcl/lineinfo.hxx>
35 : : #include <drawinglayer/attribute/lineattribute.hxx>
36 : : #include <drawinglayer/attribute/strokeattribute.hxx>
37 : : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
38 : : #include <vcl/metaact.hxx>
39 : : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
40 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
41 : : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
42 : : #include <basegfx/polygon/b2dpolygontools.hxx>
43 : : #include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
44 : : #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
45 : : #include <vcl/salbtype.hxx>
46 : : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
47 : : #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
48 : : #include <vcl/svapp.hxx>
49 : : #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
50 : : #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
51 : : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
52 : : #include <basegfx/polygon/b2dpolygonclipper.hxx>
53 : : #include <drawinglayer/primitive2d/invertprimitive2d.hxx>
54 : : #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
55 : : #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
56 : : #include <drawinglayer/primitive2d/wallpaperprimitive2d.hxx>
57 : : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
58 : : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
59 : : #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
60 : : #include <i18npool/mslangid.hxx>
61 : : #include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
62 : : #include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
63 : : #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
64 : : #include <drawinglayer/primitive2d/rendergraphicprimitive2d.hxx>
65 : : #include <numeric>
66 : :
67 : : //////////////////////////////////////////////////////////////////////////////
68 : :
69 : : using namespace com::sun::star;
70 : :
71 : : //////////////////////////////////////////////////////////////////////////////
72 : :
73 : : namespace
74 : : {
75 : : /** helper class for graphic context
76 : :
77 : : This class allows to hold a complete status of classic
78 : : VCL OutputDevice stati. This data is needed for correct
79 : : interpretation of the MetaFile action flow.
80 : : */
81 [ + - ][ + - ]: 195 : class PropertyHolder
82 : : {
83 : : private:
84 : : /// current transformation (aka MapMode)
85 : : basegfx::B2DHomMatrix maTransformation;
86 : : MapUnit maMapUnit;
87 : :
88 : : /// current colors
89 : : basegfx::BColor maLineColor;
90 : : basegfx::BColor maFillColor;
91 : : basegfx::BColor maTextColor;
92 : : basegfx::BColor maTextFillColor;
93 : : basegfx::BColor maTextLineColor;
94 : : basegfx::BColor maOverlineColor;
95 : :
96 : : /// clipping
97 : : basegfx::B2DPolyPolygon maClipPolyPoygon;
98 : :
99 : : /// font, etc.
100 : : Font maFont;
101 : : RasterOp maRasterOp;
102 : : sal_uInt32 mnLayoutMode;
103 : : LanguageType maLanguageType;
104 : : sal_uInt16 mnPushFlags;
105 : :
106 : : /// bitfield
107 : : /// contains all active markers
108 : : bool mbLineColor : 1;
109 : : bool mbFillColor : 1;
110 : : bool mbTextColor : 1;
111 : : bool mbTextFillColor : 1;
112 : : bool mbTextLineColor : 1;
113 : : bool mbOverlineColor : 1;
114 : : bool mbClipPolyPolygonActive : 1;
115 : :
116 : : public:
117 : 70 : PropertyHolder()
118 : : : maTransformation(),
119 : : maMapUnit(MAP_100TH_MM),
120 : : maLineColor(),
121 : : maFillColor(),
122 : : maTextColor(COL_BLACK),
123 : : maTextFillColor(),
124 : : maTextLineColor(),
125 : : maOverlineColor(),
126 : : maClipPolyPoygon(),
127 : : maFont(),
128 : : maRasterOp(ROP_OVERPAINT),
129 : : mnLayoutMode(0),
130 : : maLanguageType(0),
131 : : mnPushFlags(0),
132 : : mbLineColor(false),
133 : : mbFillColor(false),
134 : : mbTextColor(true),
135 : : mbTextFillColor(false),
136 : : mbTextLineColor(false),
137 : : mbOverlineColor(false),
138 [ + - ][ + - ]: 70 : mbClipPolyPolygonActive(false)
139 : : {
140 : 70 : }
141 : :
142 : 265 : ~PropertyHolder()
143 [ + - ][ + - ]: 265 : {
144 : 265 : }
145 : :
146 : : /// read/write accesses
147 : 7824 : const basegfx::B2DHomMatrix& getTransformation() const { return maTransformation; }
148 [ - + ]: 130 : void setTransformation(const basegfx::B2DHomMatrix& rNew) { if(rNew != maTransformation) maTransformation = rNew; }
149 : :
150 : 130 : MapUnit getMapUnit() const { return maMapUnit; }
151 [ - + ]: 195 : void setMapUnit(MapUnit eNew) { if(eNew != maMapUnit) maMapUnit = eNew; }
152 : :
153 : 3725 : const basegfx::BColor& getLineColor() const { return maLineColor; }
154 [ + + ]: 7320 : void setLineColor(const basegfx::BColor& rNew) { if(rNew != maLineColor) maLineColor = rNew; }
155 : 4625 : bool getLineColorActive() const { return mbLineColor; }
156 [ + + ]: 12581 : void setLineColorActive(bool bNew) { if(bNew != mbLineColor) mbLineColor = bNew; }
157 : :
158 : 1030 : const basegfx::BColor& getFillColor() const { return maFillColor; }
159 [ + + ]: 1030 : void setFillColor(const basegfx::BColor& rNew) { if(rNew != maFillColor) maFillColor = rNew; }
160 : 1030 : bool getFillColorActive() const { return mbFillColor; }
161 [ + + ]: 8986 : void setFillColorActive(bool bNew) { if(bNew != mbFillColor) mbFillColor = bNew; }
162 : :
163 : 3122 : const basegfx::BColor& getTextColor() const { return maTextColor; }
164 [ - + ]: 3122 : void setTextColor(const basegfx::BColor& rNew) { if(rNew != maTextColor) maTextColor = rNew; }
165 : 3122 : bool getTextColorActive() const { return mbTextColor; }
166 [ - + ]: 3122 : void setTextColorActive(bool bNew) { if(bNew != mbTextColor) mbTextColor = bNew; }
167 : :
168 : 130 : const basegfx::BColor& getTextFillColor() const { return maTextFillColor; }
169 [ - + ]: 130 : void setTextFillColor(const basegfx::BColor& rNew) { if(rNew != maTextFillColor) maTextFillColor = rNew; }
170 : 3122 : bool getTextFillColorActive() const { return mbTextFillColor; }
171 [ - + ]: 6114 : void setTextFillColorActive(bool bNew) { if(bNew != mbTextFillColor) mbTextFillColor = bNew; }
172 : :
173 : 130 : const basegfx::BColor& getTextLineColor() const { return maTextLineColor; }
174 [ - + ]: 130 : void setTextLineColor(const basegfx::BColor& rNew) { if(rNew != maTextLineColor) maTextLineColor = rNew; }
175 : 130 : bool getTextLineColorActive() const { return mbTextLineColor; }
176 [ - + ]: 130 : void setTextLineColorActive(bool bNew) { if(bNew != mbTextLineColor) mbTextLineColor = bNew; }
177 : :
178 : 130 : const basegfx::BColor& getOverlineColor() const { return maOverlineColor; }
179 [ - + ]: 130 : void setOverlineColor(const basegfx::BColor& rNew) { if(rNew != maOverlineColor) maOverlineColor = rNew; }
180 : 130 : bool getOverlineColorActive() const { return mbOverlineColor; }
181 [ - + ]: 130 : void setOverlineColorActive(bool bNew) { if(bNew != mbOverlineColor) mbOverlineColor = bNew; }
182 : :
183 : 649 : const basegfx::B2DPolyPolygon& getClipPolyPolygon() const { return maClipPolyPoygon; }
184 [ + - ]: 65 : void setClipPolyPolygon(const basegfx::B2DPolyPolygon& rNew) { if(rNew != maClipPolyPoygon) maClipPolyPoygon = rNew; }
185 : 1753 : bool getClipPolyPolygonActive() const { return mbClipPolyPolygonActive; }
186 [ + - ]: 260 : void setClipPolyPolygonActive(bool bNew) { if(bNew != mbClipPolyPolygonActive) mbClipPolyPolygonActive = bNew; }
187 : :
188 : 12358 : const Font& getFont() const { return maFont; }
189 [ + + ]: 6114 : void setFont(const Font& rFont) { if(rFont != maFont) maFont = rFont; }
190 : :
191 : 130 : const RasterOp& getRasterOp() const { return maRasterOp; }
192 [ - + ]: 130 : void setRasterOp(const RasterOp& rRasterOp) { if(rRasterOp != maRasterOp) maRasterOp = rRasterOp; }
193 [ + - ][ - + ]: 130 : bool isRasterOpInvert() const { return (ROP_XOR == maRasterOp || ROP_INVERT == maRasterOp); }
194 : 130 : bool isRasterOpForceBlack() const { return ROP_0 == maRasterOp; }
195 [ + - ][ - + ]: 130 : bool isRasterOpActive() const { return isRasterOpInvert() || isRasterOpForceBlack(); }
196 : :
197 : 6114 : sal_uInt32 getLayoutMode() const { return mnLayoutMode; }
198 [ - + ]: 195 : void setLayoutMode(sal_uInt32 nNew) { if(nNew != mnLayoutMode) mnLayoutMode = nNew; }
199 : :
200 : 3122 : LanguageType getLanguageType() const { return maLanguageType; }
201 [ + + ]: 195 : void setLanguageType(LanguageType aNew) { if(aNew != maLanguageType) maLanguageType = aNew; }
202 : :
203 : 585 : sal_uInt16 getPushFlags() const { return mnPushFlags; }
204 [ + - ]: 195 : void setPushFlags(sal_uInt16 nNew) { if(nNew != mnPushFlags) mnPushFlags = nNew; }
205 : :
206 [ + - ][ + + ]: 5261 : bool getLineOrFillActive() const { return (mbLineColor || mbFillColor); }
207 : : };
208 : : } // end of anonymous namespace
209 : :
210 : : //////////////////////////////////////////////////////////////////////////////
211 : :
212 : : namespace
213 : : {
214 : : /** stack for properites
215 : :
216 : : This class builds a stack based on the PropertyHolder
217 : : class. It encapsulates the pointer/new/delete usage to
218 : : make it safe and implements the push/pop as needed by a
219 : : VCL Metafile interpreter. The critical part here are the
220 : : flag values VCL OutputDevice uses here; not all stuff is
221 : : pushed and thus needs to be copied at pop.
222 : : */
223 : : class PropertyHolders
224 : : {
225 : : private:
226 : : std::vector< PropertyHolder* > maPropertyHolders;
227 : :
228 : : public:
229 : 65 : PropertyHolders()
230 : 65 : {
231 [ + - ][ + - ]: 65 : maPropertyHolders.push_back(new PropertyHolder());
[ + - ]
232 : 65 : }
233 : :
234 : : sal_uInt32 size() const
235 : : {
236 : : return maPropertyHolders.size();
237 : : }
238 : :
239 : 0 : void PushDefault()
240 : : {
241 [ # # ][ # # ]: 0 : PropertyHolder* pNew = new PropertyHolder();
242 [ # # ]: 0 : maPropertyHolders.push_back(pNew);
243 : 0 : }
244 : :
245 : 195 : void Push(sal_uInt16 nPushFlags)
246 : : {
247 [ + - ]: 195 : if(nPushFlags)
248 : : {
249 : : OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: PUSH with no property holders (!)");
250 [ + - ]: 195 : if ( !maPropertyHolders.empty() )
251 : : {
252 [ + - ][ + - ]: 195 : PropertyHolder* pNew = new PropertyHolder(*maPropertyHolders.back());
[ + - ]
253 : 195 : pNew->setPushFlags(nPushFlags);
254 [ + - ]: 195 : maPropertyHolders.push_back(pNew);
255 : : }
256 : : }
257 : 195 : }
258 : :
259 : 195 : void Pop()
260 : : {
261 : : OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: POP with no property holders (!)");
262 : 195 : const sal_uInt32 nSize(maPropertyHolders.size());
263 : :
264 [ + - ]: 195 : if(nSize)
265 : : {
266 : 195 : const PropertyHolder* pTip = maPropertyHolders.back();
267 : 195 : const sal_uInt16 nPushFlags(pTip->getPushFlags());
268 : :
269 [ + - ]: 195 : if(nPushFlags)
270 : : {
271 [ + - ]: 195 : if(nSize > 1)
272 : : {
273 : : // copy back content for all non-set flags
274 : 195 : PropertyHolder* pLast = maPropertyHolders[nSize - 2];
275 : :
276 [ + + ]: 195 : if(PUSH_ALL != nPushFlags)
277 : : {
278 [ + - ]: 130 : if(!(nPushFlags & PUSH_LINECOLOR ))
279 : : {
280 : 130 : pLast->setLineColor(pTip->getLineColor());
281 : 130 : pLast->setLineColorActive(pTip->getLineColorActive());
282 : : }
283 [ + - ]: 130 : if(!(nPushFlags & PUSH_FILLCOLOR ))
284 : : {
285 : 130 : pLast->setFillColor(pTip->getFillColor());
286 : 130 : pLast->setFillColorActive(pTip->getFillColorActive());
287 : : }
288 [ + - ]: 130 : if(!(nPushFlags & PUSH_FONT ))
289 : : {
290 : 130 : pLast->setFont(pTip->getFont());
291 : : }
292 [ + - ]: 130 : if(!(nPushFlags & PUSH_TEXTCOLOR ))
293 : : {
294 : 130 : pLast->setTextColor(pTip->getTextColor());
295 : 130 : pLast->setTextColorActive(pTip->getTextColorActive());
296 : : }
297 [ + - ]: 130 : if(!(nPushFlags & PUSH_MAPMODE ))
298 : : {
299 : 130 : pLast->setTransformation(pTip->getTransformation());
300 : 130 : pLast->setMapUnit(pTip->getMapUnit());
301 : : }
302 [ - + ]: 130 : if(!(nPushFlags & PUSH_CLIPREGION ))
303 : : {
304 : 0 : pLast->setClipPolyPolygon(pTip->getClipPolyPolygon());
305 : 0 : pLast->setClipPolyPolygonActive(pTip->getClipPolyPolygonActive());
306 : : }
307 [ + - ]: 130 : if(!(nPushFlags & PUSH_RASTEROP ))
308 : : {
309 : 130 : pLast->setRasterOp(pTip->getRasterOp());
310 : : }
311 [ + - ]: 130 : if(!(nPushFlags & PUSH_TEXTFILLCOLOR ))
312 : : {
313 : 130 : pLast->setTextFillColor(pTip->getTextFillColor());
314 : 130 : pLast->setTextFillColorActive(pTip->getTextFillColorActive());
315 : : }
316 [ + - ]: 130 : if(!(nPushFlags & PUSH_TEXTALIGN ))
317 : : {
318 [ - + ]: 130 : if(pLast->getFont().GetAlign() != pTip->getFont().GetAlign())
319 : : {
320 [ # # ]: 0 : Font aFont(pLast->getFont());
321 [ # # ][ # # ]: 0 : aFont.SetAlign(pTip->getFont().GetAlign());
322 [ # # ][ # # ]: 0 : pLast->setFont(aFont);
323 : : }
324 : : }
325 : 130 : if(!(nPushFlags & PUSH_REFPOINT ))
326 : : {
327 : : // not supported
328 : : }
329 [ + - ]: 130 : if(!(nPushFlags & PUSH_TEXTLINECOLOR ))
330 : : {
331 : 130 : pLast->setTextLineColor(pTip->getTextLineColor());
332 : 130 : pLast->setTextLineColorActive(pTip->getTextLineColorActive());
333 : : }
334 [ + - ]: 130 : if(!(nPushFlags & PUSH_TEXTLAYOUTMODE ))
335 : : {
336 : 130 : pLast->setLayoutMode(pTip->getLayoutMode());
337 : : }
338 [ + - ]: 130 : if(!(nPushFlags & PUSH_TEXTLANGUAGE ))
339 : : {
340 : 130 : pLast->setLanguageType(pTip->getLanguageType());
341 : : }
342 [ + - ]: 130 : if(!(nPushFlags & PUSH_OVERLINECOLOR ))
343 : : {
344 : 130 : pLast->setOverlineColor(pTip->getOverlineColor());
345 : 130 : pLast->setOverlineColorActive(pTip->getOverlineColorActive());
346 : : }
347 : : }
348 : : }
349 : : }
350 : :
351 : : // execute the pop
352 [ + - ]: 195 : delete maPropertyHolders.back();
353 : 195 : maPropertyHolders.pop_back();
354 : : }
355 : 195 : }
356 : :
357 : 76254 : PropertyHolder& Current()
358 : : {
359 [ + + ][ + - ]: 76254 : static PropertyHolder aDummy;
[ + - ][ # # ]
360 : : OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: CURRENT with no property holders (!)");
361 [ - + ]: 76254 : return maPropertyHolders.empty() ? aDummy : *maPropertyHolders.back();
362 : : }
363 : :
364 : 65 : ~PropertyHolders()
365 : 65 : {
366 [ + + ]: 130 : while(!maPropertyHolders.empty())
367 : : {
368 [ + - ][ + - ]: 65 : delete maPropertyHolders.back();
[ + - ]
369 [ + - ]: 65 : maPropertyHolders.pop_back();
370 : : }
371 : 65 : }
372 : : };
373 : : } // end of anonymous namespace
374 : :
375 : : //////////////////////////////////////////////////////////////////////////////
376 : :
377 : : namespace
378 : : {
379 : : /** helper to convert a Region to a B2DPolyPolygon
380 : : when it does not yet contain one. In the future
381 : : this may be expanded to merge the polygons created
382 : : from rectangles or use a special algo to directly turn
383 : : the spans of regions to a single, already merged
384 : : PolyPolygon.
385 : : */
386 : 130 : basegfx::B2DPolyPolygon getB2DPolyPolygonFromRegion(const Region& rRegion)
387 : : {
388 : 130 : basegfx::B2DPolyPolygon aRetval;
389 : :
390 [ + - ][ + - ]: 130 : if(!rRegion.IsEmpty())
391 : : {
392 [ + - ]: 130 : Region aRegion(rRegion);
393 [ + - ][ + - ]: 130 : aRetval = aRegion.GetB2DPolyPolygon();
[ + - ]
394 : :
395 [ + - ][ + - ]: 130 : if(!aRetval.count())
396 : : {
397 [ + - ]: 130 : RegionHandle aRegionHandle(aRegion.BeginEnumRects());
398 [ + - ]: 130 : Rectangle aRegionRectangle;
399 : :
400 [ + - ][ + + ]: 260 : while(aRegion.GetEnumRects(aRegionHandle, aRegionRectangle))
401 : : {
402 [ + - ][ + - ]: 130 : if(!aRegionRectangle.IsEmpty())
403 : : {
404 : : const basegfx::B2DRange aRegionRange(
405 : 130 : aRegionRectangle.Left(), aRegionRectangle.Top(),
406 [ + - ]: 260 : aRegionRectangle.Right(), aRegionRectangle.Bottom());
407 [ + - ][ + - ]: 130 : aRetval.append(basegfx::tools::createPolygonFromRect(aRegionRange));
[ + - ]
408 : : }
409 : : }
410 : :
411 [ + - ]: 130 : aRegion.EndEnumRects(aRegionHandle);
412 [ + - ]: 130 : }
413 : : }
414 : :
415 : 130 : return aRetval;
416 : : }
417 : : } // end of anonymous namespace
418 : :
419 : : //////////////////////////////////////////////////////////////////////////////
420 : :
421 : : namespace
422 : : {
423 : : /** Helper class to buffer and hold a Primive target vector. It
424 : : encapsulates the new/delete functionality and aloows to work
425 : : on pointers of the implementation classes. All data will
426 : : be converted to uno sequences of uno references when accessing the
427 : : data.
428 : : */
429 : : class TargetHolder
430 : : {
431 : : private:
432 : : std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargets;
433 : :
434 : : public:
435 : 130 : TargetHolder()
436 : 130 : : aTargets()
437 : : {
438 : 130 : }
439 : :
440 : 130 : ~TargetHolder()
441 : 130 : {
442 : 130 : const sal_uInt32 nCount(aTargets.size());
443 : :
444 [ - + ]: 130 : for(sal_uInt32 a(0); a < nCount; a++)
445 : : {
446 [ # # ][ # # ]: 0 : delete aTargets[a];
[ # # ]
447 : : }
448 : 130 : }
449 : :
450 : 65 : sal_uInt32 size() const
451 : : {
452 : 65 : return aTargets.size();
453 : : }
454 : :
455 : 7563 : void append(drawinglayer::primitive2d::BasePrimitive2D* pCandidate)
456 : : {
457 [ + - ]: 7563 : if(pCandidate)
458 : : {
459 : 7563 : aTargets.push_back(pCandidate);
460 : : }
461 : 7563 : }
462 : :
463 : 129 : drawinglayer::primitive2d::Primitive2DSequence getPrimitive2DSequence(const PropertyHolder& rPropertyHolder)
464 : : {
465 : 129 : const sal_uInt32 nCount(aTargets.size());
466 : 129 : drawinglayer::primitive2d::Primitive2DSequence xRetval(nCount);
467 : :
468 [ + + ]: 7692 : for(sal_uInt32 a(0); a < nCount; a++)
469 : : {
470 [ + - ][ + - ]: 7563 : xRetval[a] = aTargets[a];
[ + - ][ + - ]
471 : : }
472 : :
473 : : // All Targets were pointers, but do not need to be deleted since they
474 : : // were converted to UNO API references now, so they stay as long as
475 : : // referenced. Do NOT delete the C++ implementation classes here, but clear
476 : : // the buffer to not delete them in the destructor.
477 : 129 : aTargets.clear();
478 : :
479 [ + + ][ + + ]: 129 : if(xRetval.hasElements() && rPropertyHolder.getClipPolyPolygonActive())
[ + + ]
480 : : {
481 : 64 : const basegfx::B2DPolyPolygon& rClipPolyPolygon = rPropertyHolder.getClipPolyPolygon();
482 : :
483 [ + - ][ + - ]: 64 : if(rClipPolyPolygon.count())
484 : : {
485 : : const drawinglayer::primitive2d::Primitive2DReference xMask(
486 : : new drawinglayer::primitive2d::MaskPrimitive2D(
487 : : rClipPolyPolygon,
488 [ + - ][ + - ]: 64 : xRetval));
[ + - ]
489 : :
490 [ + - ][ + - ]: 64 : xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
[ + - ]
491 : : }
492 : : }
493 : :
494 : 129 : return xRetval;
495 : : }
496 : : };
497 : : } // end of anonymous namespace
498 : :
499 : : //////////////////////////////////////////////////////////////////////////////
500 : :
501 : : namespace
502 : : {
503 : : /** Helper class which builds a stack on the TargetHolder class */
504 : : class TargetHolders
505 : : {
506 : : private:
507 : : std::vector< TargetHolder* > maTargetHolders;
508 : :
509 : : public:
510 : 65 : TargetHolders()
511 : 65 : {
512 [ + - ][ + - ]: 65 : maTargetHolders.push_back(new TargetHolder());
[ + - ]
513 : 65 : }
514 : :
515 : 260 : sal_uInt32 size() const
516 : : {
517 : 260 : return maTargetHolders.size();
518 : : }
519 : :
520 : 65 : void Push()
521 : : {
522 [ + - ][ + - ]: 65 : maTargetHolders.push_back(new TargetHolder());
523 : 65 : }
524 : :
525 : 65 : void Pop()
526 : : {
527 : : OSL_ENSURE(maTargetHolders.size(), "TargetHolders: POP with no property holders (!)");
528 [ + - ]: 65 : if(!maTargetHolders.empty())
529 : : {
530 [ + - ]: 65 : delete maTargetHolders.back();
531 : 65 : maTargetHolders.pop_back();
532 : : }
533 : 65 : }
534 : :
535 : 7757 : TargetHolder& Current()
536 : : {
537 : : OSL_ENSURE(maTargetHolders.size(), "TargetHolders: CURRENT with no property holders (!)");
538 : 7757 : return *maTargetHolders.back();
539 : : }
540 : :
541 : 65 : ~TargetHolders()
542 : 65 : {
543 [ + + ]: 130 : while(!maTargetHolders.empty())
544 : : {
545 [ + - ][ + - ]: 65 : delete maTargetHolders.back();
[ + - ]
546 [ + - ]: 65 : maTargetHolders.pop_back();
547 : : }
548 : 65 : }
549 : : };
550 : : } // end of anonymous namespace
551 : :
552 : : //////////////////////////////////////////////////////////////////////////////
553 : :
554 : : namespace drawinglayer
555 : : {
556 : : namespace primitive2d
557 : : {
558 : : /** NonOverlappingFillGradientPrimitive2D class
559 : :
560 : : This is a special version of the FillGradientPrimitive2D which decomposes
561 : : to a non-overlapping geometry version of the gradient. This needs to be
562 : : used to support the old XOR paint-'trick'.
563 : :
564 : : It does not need an own identifier since a renderer who wants to interpret
565 : : it itself may do so. It just overloads the decomposition of the C++
566 : : implementation class to do an alternative decomposition.
567 : : */
568 [ # # ]: 0 : class NonOverlappingFillGradientPrimitive2D : public FillGradientPrimitive2D
569 : : {
570 : : protected:
571 : : /// local decomposition.
572 : : virtual Primitive2DSequence create2DDecomposition(
573 : : const geometry::ViewInformation2D& rViewInformation) const;
574 : :
575 : : public:
576 : : /// constructor
577 : 0 : NonOverlappingFillGradientPrimitive2D(
578 : : const basegfx::B2DRange& rObjectRange,
579 : : const attribute::FillGradientAttribute& rFillGradient)
580 : 0 : : FillGradientPrimitive2D(rObjectRange, rFillGradient)
581 : : {
582 : 0 : }
583 : : };
584 : :
585 : 0 : Primitive2DSequence NonOverlappingFillGradientPrimitive2D::create2DDecomposition(
586 : : const geometry::ViewInformation2D& /*rViewInformation*/) const
587 : : {
588 [ # # ]: 0 : if(!getFillGradient().isDefault())
589 : : {
590 : 0 : return createFill(false);
591 : : }
592 : : else
593 : : {
594 : 0 : return Primitive2DSequence();
595 : : }
596 : : }
597 : : } // end of namespace primitive2d
598 : : } // end of namespace drawinglayer
599 : :
600 : : //////////////////////////////////////////////////////////////////////////////
601 : :
602 : : namespace
603 : : {
604 : : /** helper to convert a MapMode to a transformation */
605 : 0 : basegfx::B2DHomMatrix getTransformFromMapMode(const MapMode& rMapMode)
606 : : {
607 [ # # ]: 0 : basegfx::B2DHomMatrix aMapping;
608 [ # # ]: 0 : const Fraction aNoScale(1, 1);
609 : 0 : const Point& rOrigin(rMapMode.GetOrigin());
610 : :
611 [ # # ][ # # ]: 0 : if(0 != rOrigin.X() || 0 != rOrigin.Y())
[ # # ]
612 : : {
613 [ # # ]: 0 : aMapping.translate(rOrigin.X(), rOrigin.Y());
614 : : }
615 : :
616 [ # # ][ # # ]: 0 : if(rMapMode.GetScaleX() != aNoScale || rMapMode.GetScaleY() != aNoScale)
[ # # ][ # # ]
[ # # ]
617 : : {
618 : : aMapping.scale(
619 : 0 : double(rMapMode.GetScaleX()),
620 [ # # # # ]: 0 : double(rMapMode.GetScaleY()));
[ # # ]
621 : : }
622 : :
623 : 0 : return aMapping;
624 : : }
625 : :
626 : : /** helper to create a PointArrayPrimitive2D based on current context */
627 : 0 : void createPointArrayPrimitive(
628 : : const std::vector< basegfx::B2DPoint >& rPositions,
629 : : TargetHolder& rTarget,
630 : : PropertyHolder& rProperties,
631 : : basegfx::BColor aBColor)
632 : : {
633 [ # # ]: 0 : if(!rPositions.empty())
634 : : {
635 [ # # ]: 0 : if(rProperties.getTransformation().isIdentity())
636 : : {
637 : : rTarget.append(
638 : : new drawinglayer::primitive2d::PointArrayPrimitive2D(
639 : : rPositions,
640 [ # # ]: 0 : aBColor));
641 : : }
642 : : else
643 : : {
644 [ # # ]: 0 : std::vector< basegfx::B2DPoint > aPositions(rPositions);
645 : :
646 [ # # ]: 0 : for(sal_uInt32 a(0); a < aPositions.size(); a++)
647 : : {
648 [ # # ]: 0 : aPositions[a] = rProperties.getTransformation() * aPositions[a];
649 : : }
650 : :
651 : : rTarget.append(
652 : : new drawinglayer::primitive2d::PointArrayPrimitive2D(
653 : : aPositions,
654 [ # # ][ # # ]: 0 : aBColor));
655 : : }
656 : : }
657 : 0 : }
658 : :
659 : : /** helper to create a PolygonHairlinePrimitive2D based on current context */
660 : 3347 : void createHairlinePrimitive(
661 : : const basegfx::B2DPolygon& rLinePolygon,
662 : : TargetHolder& rTarget,
663 : : PropertyHolder& rProperties)
664 : : {
665 [ + - ]: 3347 : if(rLinePolygon.count())
666 : : {
667 [ + - ]: 3347 : basegfx::B2DPolygon aLinePolygon(rLinePolygon);
668 [ + - ]: 3347 : aLinePolygon.transform(rProperties.getTransformation());
669 : : rTarget.append(
670 : : new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
671 : : aLinePolygon,
672 [ + - ][ + - ]: 3347 : rProperties.getLineColor()));
[ + - ]
673 : : }
674 : 3347 : }
675 : :
676 : : /** helper to create a PolyPolygonColorPrimitive2D based on current context */
677 : 900 : void createFillPrimitive(
678 : : const basegfx::B2DPolyPolygon& rFillPolyPolygon,
679 : : TargetHolder& rTarget,
680 : : PropertyHolder& rProperties)
681 : : {
682 [ + - ]: 900 : if(rFillPolyPolygon.count())
683 : : {
684 [ + - ]: 900 : basegfx::B2DPolyPolygon aFillPolyPolygon(rFillPolyPolygon);
685 [ + - ]: 900 : aFillPolyPolygon.transform(rProperties.getTransformation());
686 : : rTarget.append(
687 : : new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
688 : : aFillPolyPolygon,
689 [ + - ][ + - ]: 900 : rProperties.getFillColor()));
[ + - ]
690 : : }
691 : 900 : }
692 : :
693 : : /** helper to create a PolygonStrokePrimitive2D based on current context */
694 : 3595 : void createLinePrimitive(
695 : : const basegfx::B2DPolygon& rLinePolygon,
696 : : const LineInfo& rLineInfo,
697 : : TargetHolder& rTarget,
698 : : PropertyHolder& rProperties)
699 : : {
700 [ + - ]: 3595 : if(rLinePolygon.count())
701 : : {
702 : 3595 : const bool bDashDotUsed(LINE_DASH == rLineInfo.GetStyle());
703 : 3595 : const bool bWidthUsed(rLineInfo.GetWidth() > 1);
704 : :
705 [ + + ][ + - ]: 3595 : if(bDashDotUsed || bWidthUsed)
706 : : {
707 [ + - ]: 248 : basegfx::B2DPolygon aLinePolygon(rLinePolygon);
708 [ + - ]: 248 : aLinePolygon.transform(rProperties.getTransformation());
709 : : const drawinglayer::attribute::LineAttribute aLineAttribute(
710 : 248 : rProperties.getLineColor(),
711 : 248 : bWidthUsed ? rLineInfo.GetWidth() : 0.0,
712 [ + - ][ + - ]: 744 : rLineInfo.GetLineJoin());
713 : :
714 [ - + ]: 248 : if(bDashDotUsed)
715 : : {
716 [ # # ]: 0 : ::std::vector< double > fDotDashArray;
717 : 0 : const double fDashLen(rLineInfo.GetDashLen());
718 : 0 : const double fDotLen(rLineInfo.GetDotLen());
719 : 0 : const double fDistance(rLineInfo.GetDistance());
720 : :
721 [ # # ]: 0 : for(sal_uInt16 a(0); a < rLineInfo.GetDashCount(); a++)
722 : : {
723 [ # # ]: 0 : fDotDashArray.push_back(fDashLen);
724 [ # # ]: 0 : fDotDashArray.push_back(fDistance);
725 : : }
726 : :
727 [ # # ]: 0 : for(sal_uInt16 b(0); b < rLineInfo.GetDotCount(); b++)
728 : : {
729 [ # # ]: 0 : fDotDashArray.push_back(fDotLen);
730 [ # # ]: 0 : fDotDashArray.push_back(fDistance);
731 : : }
732 : :
733 [ # # ]: 0 : const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));
734 : : const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(
735 : : fDotDashArray,
736 [ # # ]: 0 : fAccumulated);
737 : :
738 : : rTarget.append(
739 : : new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
740 : : aLinePolygon,
741 : : aLineAttribute,
742 [ # # ][ # # ]: 0 : aStrokeAttribute));
[ # # ]
743 : : }
744 : : else
745 : : {
746 : : rTarget.append(
747 : : new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
748 : : aLinePolygon,
749 [ + - ][ + - ]: 248 : aLineAttribute));
750 [ + - ][ + - ]: 248 : }
751 : : }
752 : : else
753 : : {
754 : 3595 : createHairlinePrimitive(rLinePolygon, rTarget, rProperties);
755 : : }
756 : : }
757 : 3595 : }
758 : :
759 : : /** helper to create needed line and fill primitives based on current context */
760 : 0 : void createHairlineAndFillPrimitive(
761 : : const basegfx::B2DPolygon& rPolygon,
762 : : TargetHolder& rTarget,
763 : : PropertyHolder& rProperties)
764 : : {
765 [ # # ]: 0 : if(rProperties.getFillColorActive())
766 : : {
767 [ # # ]: 0 : createFillPrimitive(basegfx::B2DPolyPolygon(rPolygon), rTarget, rProperties);
768 : : }
769 : :
770 [ # # ]: 0 : if(rProperties.getLineColorActive())
771 : : {
772 : 0 : createHairlinePrimitive(rPolygon, rTarget, rProperties);
773 : : }
774 : 0 : }
775 : :
776 : : /** helper to create needed line and fill primitives based on current context */
777 : 900 : void createHairlineAndFillPrimitive(
778 : : const basegfx::B2DPolyPolygon& rPolyPolygon,
779 : : TargetHolder& rTarget,
780 : : PropertyHolder& rProperties)
781 : : {
782 [ + - ]: 900 : if(rProperties.getFillColorActive())
783 : : {
784 : 900 : createFillPrimitive(rPolyPolygon, rTarget, rProperties);
785 : : }
786 : :
787 [ - + ]: 900 : if(rProperties.getLineColorActive())
788 : : {
789 [ # # ]: 0 : for(sal_uInt32 a(0); a < rPolyPolygon.count(); a++)
790 : : {
791 [ # # ]: 0 : createHairlinePrimitive(rPolyPolygon.getB2DPolygon(a), rTarget, rProperties);
792 : : }
793 : : }
794 : 900 : }
795 : :
796 : : /** helper to create DiscreteBitmapPrimitive2D based on current context.
797 : : The DiscreteBitmapPrimitive2D is especially created for this usage
798 : : since no other usage defines a bitmap visualisation based on top-left
799 : : position and size in pixels. At the end it will create a view-dependent
800 : : transformed embedding of a BitmapPrimitive2D.
801 : : */
802 : 0 : void createBitmapExPrimitive(
803 : : const BitmapEx& rBitmapEx,
804 : : const Point& rPoint,
805 : : TargetHolder& rTarget,
806 : : PropertyHolder& rProperties)
807 : : {
808 [ # # ]: 0 : if(!rBitmapEx.IsEmpty())
809 : : {
810 : 0 : basegfx::B2DPoint aPoint(rPoint.X(), rPoint.Y());
811 [ # # ]: 0 : aPoint = rProperties.getTransformation() * aPoint;
812 : :
813 : : rTarget.append(
814 : : new drawinglayer::primitive2d::DiscreteBitmapPrimitive2D(
815 : : rBitmapEx,
816 [ # # ][ # # ]: 0 : aPoint));
817 : : }
818 : 0 : }
819 : :
820 : : /** helper to create BitmapPrimitive2D based on current context */
821 : 12 : void createBitmapExPrimitive(
822 : : const BitmapEx& rBitmapEx,
823 : : const Point& rPoint,
824 : : const Size& rSize,
825 : : TargetHolder& rTarget,
826 : : PropertyHolder& rProperties)
827 : : {
828 [ + - ]: 12 : if(!rBitmapEx.IsEmpty())
829 : : {
830 [ + - ]: 12 : basegfx::B2DHomMatrix aObjectTransform;
831 : :
832 [ + - ]: 12 : aObjectTransform.set(0, 0, rSize.Width());
833 [ + - ]: 12 : aObjectTransform.set(1, 1, rSize.Height());
834 [ + - ]: 12 : aObjectTransform.set(0, 2, rPoint.X());
835 [ + - ]: 12 : aObjectTransform.set(1, 2, rPoint.Y());
836 : :
837 [ + - ][ + - ]: 12 : aObjectTransform = rProperties.getTransformation() * aObjectTransform;
[ + - ]
838 : :
839 : : rTarget.append(
840 : : new drawinglayer::primitive2d::BitmapPrimitive2D(
841 : : rBitmapEx,
842 [ + - ][ + - ]: 12 : aObjectTransform));
[ + - ]
843 : : }
844 : 12 : }
845 : :
846 : : /** helper to create a regular BotmapEx from a MaskAction (definitions
847 : : which use a bitmap without transparence but define one of the colors as
848 : : transparent)
849 : : */
850 : 0 : BitmapEx createMaskBmpEx(const Bitmap& rBitmap, const Color& rMaskColor)
851 : : {
852 : 0 : const Color aWhite(COL_WHITE);
853 [ # # ]: 0 : BitmapPalette aBiLevelPalette(2);
854 : :
855 : 0 : aBiLevelPalette[0] = aWhite;
856 : 0 : aBiLevelPalette[1] = rMaskColor;
857 : :
858 [ # # ]: 0 : Bitmap aMask(rBitmap.CreateMask(aWhite));
859 [ # # ][ # # ]: 0 : Bitmap aSolid(rBitmap.GetSizePixel(), 1, &aBiLevelPalette);
860 : :
861 [ # # ]: 0 : aSolid.Erase(rMaskColor);
862 : :
863 [ # # ][ # # ]: 0 : return BitmapEx(aSolid, aMask);
[ # # ]
864 : : }
865 : :
866 : : /** helper to convert from a VCL Gradient definition to the corresponding
867 : : data for primitive representation
868 : : */
869 : 0 : drawinglayer::attribute::FillGradientAttribute createFillGradientAttribute(const Gradient& rGradient)
870 : : {
871 : 0 : const Color aStartColor(rGradient.GetStartColor());
872 : 0 : const sal_uInt16 nStartIntens(rGradient.GetStartIntensity());
873 : 0 : basegfx::BColor aStart(aStartColor.getBColor());
874 : :
875 [ # # ]: 0 : if(nStartIntens != 100)
876 : : {
877 : 0 : const basegfx::BColor aBlack;
878 : 0 : aStart = interpolate(aBlack, aStart, (double)nStartIntens * 0.01);
879 : : }
880 : :
881 : 0 : const Color aEndColor(rGradient.GetEndColor());
882 : 0 : const sal_uInt16 nEndIntens(rGradient.GetEndIntensity());
883 : 0 : basegfx::BColor aEnd(aEndColor.getBColor());
884 : :
885 [ # # ]: 0 : if(nEndIntens != 100)
886 : : {
887 : 0 : const basegfx::BColor aBlack;
888 : 0 : aEnd = interpolate(aBlack, aEnd, (double)nEndIntens * 0.01);
889 : : }
890 : :
891 : 0 : drawinglayer::attribute::GradientStyle aGradientStyle(drawinglayer::attribute::GRADIENTSTYLE_RECT);
892 : :
893 [ # # # # : 0 : switch(rGradient.GetStyle())
# # ]
894 : : {
895 : : case GradientStyle_LINEAR :
896 : : {
897 : 0 : aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_LINEAR;
898 : 0 : break;
899 : : }
900 : : case GradientStyle_AXIAL :
901 : : {
902 : 0 : aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_AXIAL;
903 : 0 : break;
904 : : }
905 : : case GradientStyle_RADIAL :
906 : : {
907 : 0 : aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RADIAL;
908 : 0 : break;
909 : : }
910 : : case GradientStyle_ELLIPTICAL :
911 : : {
912 : 0 : aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_ELLIPTICAL;
913 : 0 : break;
914 : : }
915 : : case GradientStyle_SQUARE :
916 : : {
917 : 0 : aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_SQUARE;
918 : 0 : break;
919 : : }
920 : : default : // GradientStyle_RECT
921 : : {
922 : 0 : aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RECT;
923 : 0 : break;
924 : : }
925 : : }
926 : :
927 : : return drawinglayer::attribute::FillGradientAttribute(
928 : : aGradientStyle,
929 : 0 : (double)rGradient.GetBorder() * 0.01,
930 : 0 : (double)rGradient.GetOfsX() * 0.01,
931 : 0 : (double)rGradient.GetOfsY() * 0.01,
932 : 0 : (double)rGradient.GetAngle() * F_PI1800,
933 : : aStart,
934 : : aEnd,
935 [ # # ]: 0 : rGradient.GetSteps());
936 : : }
937 : :
938 : : /** helper to convert from a VCL Hatch definition to the corresponding
939 : : data for primitive representation
940 : : */
941 : 0 : drawinglayer::attribute::FillHatchAttribute createFillHatchAttribute(const Hatch& rHatch)
942 : : {
943 : 0 : drawinglayer::attribute::HatchStyle aHatchStyle(drawinglayer::attribute::HATCHSTYLE_SINGLE);
944 : :
945 [ # # # ]: 0 : switch(rHatch.GetStyle())
946 : : {
947 : : default : // case HATCH_SINGLE :
948 : : {
949 : 0 : aHatchStyle = drawinglayer::attribute::HATCHSTYLE_SINGLE;
950 : 0 : break;
951 : : }
952 : : case HATCH_DOUBLE :
953 : : {
954 : 0 : aHatchStyle = drawinglayer::attribute::HATCHSTYLE_DOUBLE;
955 : 0 : break;
956 : : }
957 : : case HATCH_TRIPLE :
958 : : {
959 : 0 : aHatchStyle = drawinglayer::attribute::HATCHSTYLE_TRIPLE;
960 : 0 : break;
961 : : }
962 : : }
963 : :
964 : : return drawinglayer::attribute::FillHatchAttribute(
965 : : aHatchStyle,
966 : 0 : (double)rHatch.GetDistance(),
967 : 0 : (double)rHatch.GetAngle() * F_PI1800,
968 : 0 : rHatch.GetColor().getBColor(),
969 [ # # ]: 0 : false);
970 : : }
971 : :
972 : : /** helper to take needed action on ClipRegion change. This method needs to be called
973 : : on any Region change, e.g. at the obvious actions doing this, but also at pop-calls
974 : : whcih change the Region of the current context. It takes care of creating the
975 : : current embeddec context, set the new Region at the context and eventually prepare
976 : : a new target for embracing new geometry to the current region
977 : : */
978 : 390 : void HandleNewClipRegion(
979 : : const basegfx::B2DPolyPolygon& rClipPolyPolygon,
980 : : TargetHolders& rTargetHolders,
981 : : PropertyHolders& rPropertyHolders)
982 : : {
983 : 390 : const bool bNewActive(rClipPolyPolygon.count());
984 : :
985 : : // #i108636# The handlig of new ClipPolyPolygons was not done as good as possible
986 : : // in the first version of this interpreter; e.g. when a ClipPolyPolygon was set
987 : : // initially and then using a lot of push/pop actions, the pop always leads
988 : : // to setting a 'new' ClipPolyPolygon which indeed is the return to the ClipPolyPolygon
989 : : // of the properties next on the stack.
990 : : //
991 : : // This ClipPolyPolygon is identical to the current one, so there is no need to
992 : : // create a MaskPrimitive2D containing the up-to-now created primitives, but
993 : : // this was done before. While this does not lead to wrong primitive
994 : : // representations of the metafile data, it creates unneccesarily expensive
995 : : // representations. Just detecting when no really 'new' ClipPolyPolygon gets set
996 : : // solves the problem.
997 : :
998 [ - + ][ - + ]: 390 : if(!rPropertyHolders.Current().getClipPolyPolygonActive() && !bNewActive)
[ + + ]
999 : : {
1000 : : // no active ClipPolyPolygon exchanged by no new one, done
1001 : 0 : return;
1002 : : }
1003 : :
1004 [ + + ][ + + ]: 390 : if(rPropertyHolders.Current().getClipPolyPolygonActive() && bNewActive)
[ + + ]
1005 : : {
1006 : : // active ClipPolyPolygon and new active ClipPolyPolygon
1007 [ + - ]: 130 : if(rPropertyHolders.Current().getClipPolyPolygon() == rClipPolyPolygon)
1008 : : {
1009 : : // new is the same as old, done
1010 : 130 : return;
1011 : : }
1012 : : }
1013 : :
1014 : : // Here the old and the new are definitively different, maybe
1015 : : // old one and/or new one is not active.
1016 : :
1017 : : // Handle deletion of old ClipPolyPolygon. The process evtl. created primitives which
1018 : : // belong to this active ClipPolyPolygon. These need to be embedded to a
1019 : : // MaskPrimitive2D accordingly.
1020 [ + + ][ + + ]: 260 : if(rPropertyHolders.Current().getClipPolyPolygonActive() && rTargetHolders.size() > 1)
[ + + ]
1021 : : {
1022 [ + - ]: 65 : drawinglayer::primitive2d::Primitive2DSequence aSubContent;
1023 : :
1024 [ + - ][ + - ]: 130 : if(rPropertyHolders.Current().getClipPolyPolygon().count()
[ + - + + ]
[ + + ]
1025 [ + - ]: 65 : && rTargetHolders.Current().size())
1026 : : {
1027 [ + - ]: 64 : aSubContent = rTargetHolders.Current().getPrimitive2DSequence(
1028 [ + - ][ + - ]: 128 : rPropertyHolders.Current());
[ + - ][ + - ]
1029 : : }
1030 : :
1031 [ + - ]: 65 : rTargetHolders.Pop();
1032 : :
1033 [ + + ]: 65 : if(aSubContent.hasElements())
1034 : : {
1035 [ + - ]: 64 : rTargetHolders.Current().append(
1036 : : new drawinglayer::primitive2d::GroupPrimitive2D(
1037 [ + - ][ + - ]: 128 : aSubContent));
1038 [ + - ]: 65 : }
1039 : : }
1040 : :
1041 : : // apply new settings to current properties by setting
1042 : : // the new region now
1043 : 260 : rPropertyHolders.Current().setClipPolyPolygonActive(bNewActive);
1044 : :
1045 [ + + ]: 260 : if(bNewActive)
1046 : : {
1047 : 65 : rPropertyHolders.Current().setClipPolyPolygon(rClipPolyPolygon);
1048 : :
1049 : : // prepare new content holder for new active region
1050 : 390 : rTargetHolders.Push();
1051 : : }
1052 : : }
1053 : :
1054 : : /** helper to handle the change of RasterOp. It takes care of encapsulating all current
1055 : : geometry to the current RasterOp (if changed) and needs to be called on any RasterOp
1056 : : change. It will also start a new geometry target to embrace to the new RasterOp if
1057 : : a changuing RasterOp is used. Currently, ROP_XOR and ROP_INVERT are supported using
1058 : : InvertPrimitive2D, and ROP_0 by using a ModifiedColorPrimitive2D to force to black paint
1059 : : */
1060 : 0 : void HandleNewRasterOp(
1061 : : RasterOp aRasterOp,
1062 : : TargetHolders& rTargetHolders,
1063 : : PropertyHolders& rPropertyHolders)
1064 : : {
1065 : : // check if currently active
1066 [ # # ][ # # ]: 0 : if(rPropertyHolders.Current().isRasterOpActive() && rTargetHolders.size() > 1)
[ # # ]
1067 : : {
1068 [ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence aSubContent;
1069 : :
1070 [ # # ][ # # ]: 0 : if(rTargetHolders.Current().size())
1071 : : {
1072 [ # # ][ # # ]: 0 : aSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
1073 : : }
1074 : :
1075 [ # # ]: 0 : rTargetHolders.Pop();
1076 : :
1077 [ # # ]: 0 : if(aSubContent.hasElements())
1078 : : {
1079 [ # # ][ # # ]: 0 : if(rPropertyHolders.Current().isRasterOpForceBlack())
1080 : : {
1081 : : // force content to black
1082 [ # # ]: 0 : rTargetHolders.Current().append(
1083 : : new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
1084 : : aSubContent,
1085 [ # # ][ # # ]: 0 : basegfx::BColorModifier(basegfx::BColor(0.0, 0.0, 0.0))));
[ # # ]
1086 : : }
1087 : : else // if(rPropertyHolders.Current().isRasterOpInvert())
1088 : : {
1089 : : // invert content
1090 [ # # ]: 0 : rTargetHolders.Current().append(
1091 : : new drawinglayer::primitive2d::InvertPrimitive2D(
1092 [ # # ][ # # ]: 0 : aSubContent));
1093 : : }
1094 [ # # ]: 0 : }
1095 : : }
1096 : :
1097 : : // apply new settings
1098 : 0 : rPropertyHolders.Current().setRasterOp(aRasterOp);
1099 : :
1100 : : // check if now active
1101 [ # # ]: 0 : if(rPropertyHolders.Current().isRasterOpActive())
1102 : : {
1103 : : // prepare new content holder for new invert
1104 : 0 : rTargetHolders.Push();
1105 : : }
1106 : 0 : }
1107 : :
1108 : : /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
1109 : : It is a quite mighty action. This helper is for simple color filled background.
1110 : : */
1111 : 0 : drawinglayer::primitive2d::BasePrimitive2D* CreateColorWallpaper(
1112 : : const basegfx::B2DRange& rRange,
1113 : : const basegfx::BColor& rColor,
1114 : : PropertyHolder& rPropertyHolder)
1115 : : {
1116 [ # # ]: 0 : basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(rRange));
1117 [ # # ]: 0 : aOutline.transform(rPropertyHolder.getTransformation());
1118 : :
1119 : : return new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
1120 : : basegfx::B2DPolyPolygon(aOutline),
1121 [ # # ][ # # ]: 0 : rColor);
[ # # ][ # # ]
1122 : : }
1123 : :
1124 : : /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
1125 : : It is a quite mighty action. This helper is for gradient filled background.
1126 : : */
1127 : 0 : drawinglayer::primitive2d::BasePrimitive2D* CreateGradientWallpaper(
1128 : : const basegfx::B2DRange& rRange,
1129 : : const Gradient& rGradient,
1130 : : PropertyHolder& rPropertyHolder)
1131 : : {
1132 [ # # ]: 0 : const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
1133 : :
1134 [ # # ][ # # ]: 0 : if(aAttribute.getStartColor() == aAttribute.getEndColor())
[ # # ]
1135 : : {
1136 : : // not really a gradient. Create filled rectangle
1137 [ # # ][ # # ]: 0 : return CreateColorWallpaper(rRange, aAttribute.getStartColor(), rPropertyHolder);
1138 : : }
1139 : : else
1140 : : {
1141 : : // really a gradient
1142 : : drawinglayer::primitive2d::BasePrimitive2D* pRetval =
1143 : : new drawinglayer::primitive2d::FillGradientPrimitive2D(
1144 : : rRange,
1145 [ # # ]: 0 : aAttribute);
1146 : :
1147 [ # # ][ # # ]: 0 : if(!rPropertyHolder.getTransformation().isIdentity())
1148 : : {
1149 [ # # ][ # # ]: 0 : const drawinglayer::primitive2d::Primitive2DReference xPrim(pRetval);
1150 [ # # ]: 0 : const drawinglayer::primitive2d::Primitive2DSequence xSeq(&xPrim, 1);
1151 : :
1152 : : pRetval = new drawinglayer::primitive2d::TransformPrimitive2D(
1153 : : rPropertyHolder.getTransformation(),
1154 [ # # ][ # # ]: 0 : xSeq);
1155 : : }
1156 : :
1157 : 0 : return pRetval;
1158 [ # # ]: 0 : }
1159 : : }
1160 : :
1161 : : /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
1162 : : It is a quite mighty action. This helper decides if color and/or gradient
1163 : : background is needed for the wnated bitmap fill and then creates the needed
1164 : : WallpaperBitmapPrimitive2D. This primitive was created for this purpose and
1165 : : takes over all needed logic of orientations and tiling.
1166 : : */
1167 : 0 : void CreateAndAppendBitmapWallpaper(
1168 : : basegfx::B2DRange aWallpaperRange,
1169 : : const Wallpaper& rWallpaper,
1170 : : TargetHolder& rTarget,
1171 : : PropertyHolder& rProperty)
1172 : : {
1173 [ # # ]: 0 : const BitmapEx aBitmapEx(rWallpaper.GetBitmap());
1174 [ # # ]: 0 : const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
1175 : :
1176 : : // if bitmap visualisation is transparent, maybe background
1177 : : // needs to be filled. Create background
1178 [ # # ][ # # ]: 0 : if(aBitmapEx.IsTransparent()
[ # # ][ # # ]
[ # # ]
1179 : : || (WALLPAPER_TILE != eWallpaperStyle && WALLPAPER_SCALE != eWallpaperStyle))
1180 : : {
1181 [ # # ][ # # ]: 0 : if(rWallpaper.IsGradient())
1182 : : {
1183 : : rTarget.append(
1184 : : CreateGradientWallpaper(
1185 : : aWallpaperRange,
1186 : : rWallpaper.GetGradient(),
1187 [ # # ][ # # ]: 0 : rProperty));
[ # # ][ # # ]
1188 : : }
1189 [ # # ][ # # ]: 0 : else if(!rWallpaper.GetColor().GetTransparency())
1190 : : {
1191 : : rTarget.append(
1192 : : CreateColorWallpaper(
1193 : : aWallpaperRange,
1194 [ # # ]: 0 : rWallpaper.GetColor().getBColor(),
1195 [ # # ][ # # ]: 0 : rProperty));
1196 : : }
1197 : : }
1198 : :
1199 : : // use wallpaper rect if set
1200 [ # # ][ # # ]: 0 : if(rWallpaper.IsRect() && !rWallpaper.GetRect().IsEmpty())
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # # ]
1201 : : {
1202 : : aWallpaperRange = basegfx::B2DRange(
1203 [ # # ][ # # ]: 0 : rWallpaper.GetRect().Left(), rWallpaper.GetRect().Top(),
1204 [ # # ][ # # ]: 0 : rWallpaper.GetRect().Right(), rWallpaper.GetRect().Bottom());
[ # # ]
1205 : : }
1206 : :
1207 : : drawinglayer::primitive2d::BasePrimitive2D* pBitmapWallpaperFill =
1208 : : new drawinglayer::primitive2d::WallpaperBitmapPrimitive2D(
1209 : : aWallpaperRange,
1210 : : aBitmapEx,
1211 [ # # ]: 0 : eWallpaperStyle);
1212 : :
1213 [ # # ][ # # ]: 0 : if(rProperty.getTransformation().isIdentity())
1214 : : {
1215 : : // add directly
1216 [ # # ]: 0 : rTarget.append(pBitmapWallpaperFill);
1217 : : }
1218 : : else
1219 : : {
1220 : : // when a transformation is set, embed to it
1221 [ # # ][ # # ]: 0 : const drawinglayer::primitive2d::Primitive2DReference xPrim(pBitmapWallpaperFill);
1222 : :
1223 : : rTarget.append(
1224 : : new drawinglayer::primitive2d::TransformPrimitive2D(
1225 : : rProperty.getTransformation(),
1226 [ # # ][ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence(&xPrim, 1)));
[ # # ][ # # ]
1227 [ # # ]: 0 : }
1228 : 0 : }
1229 : :
1230 : : /** helper to decide UnderlineAbove for text primitives */
1231 : 0 : bool isUnderlineAbove(const Font& rFont)
1232 : : {
1233 [ # # ]: 0 : if(!rFont.IsVertical())
1234 : : {
1235 : 0 : return false;
1236 : : }
1237 : :
1238 [ # # ][ # # ]: 0 : if((LANGUAGE_JAPANESE == rFont.GetLanguage()) || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()))
[ # # ]
1239 : : {
1240 : : // the underline is right for Japanese only
1241 : 0 : return true;
1242 : : }
1243 : :
1244 : 0 : return false;
1245 : : }
1246 : :
1247 : 2992 : void createFontAttributeTransformAndAlignment(
1248 : : drawinglayer::attribute::FontAttribute& rFontAttribute,
1249 : : basegfx::B2DHomMatrix& rTextTransform,
1250 : : basegfx::B2DVector& rAlignmentOffset,
1251 : : PropertyHolder& rProperty)
1252 : : {
1253 : 2992 : const Font& rFont = rProperty.getFont();
1254 : 2992 : basegfx::B2DVector aFontScaling;
1255 : :
1256 : : rFontAttribute = drawinglayer::attribute::FontAttribute(
1257 : : drawinglayer::primitive2d::getFontAttributeFromVclFont(
1258 : : aFontScaling,
1259 : : rFont,
1260 : 2992 : 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_RTL),
1261 [ + - ][ + - ]: 5984 : 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_STRONG)));
[ + - ]
1262 : :
1263 : : // add FontScaling
1264 [ + - ]: 2992 : rTextTransform.scale(aFontScaling.getX(), aFontScaling.getY());
1265 : :
1266 : : // take text align into account
1267 [ + - ][ - + ]: 2992 : if(ALIGN_BASELINE != rFont.GetAlign())
1268 : : {
1269 [ # # ]: 0 : drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
1270 [ # # ]: 0 : aTextLayouterDevice.setFont(rFont);
1271 : :
1272 [ # # ][ # # ]: 0 : if(ALIGN_TOP == rFont.GetAlign())
1273 : : {
1274 [ # # ]: 0 : rAlignmentOffset.setY(aTextLayouterDevice.getFontAscent());
1275 : : }
1276 : : else // ALIGN_BOTTOM
1277 : : {
1278 [ # # ]: 0 : rAlignmentOffset.setY(-aTextLayouterDevice.getFontDescent());
1279 : : }
1280 : :
1281 [ # # ][ # # ]: 0 : rTextTransform.translate(rAlignmentOffset.getX(), rAlignmentOffset.getY());
1282 : : }
1283 : :
1284 : : // add FontRotation (if used)
1285 [ + - ][ - + ]: 2992 : if(rFont.GetOrientation())
1286 : : {
1287 [ # # ][ # # ]: 0 : rTextTransform.rotate(-rFont.GetOrientation() * F_PI1800);
1288 : 2992 : }
1289 : 2992 : }
1290 : :
1291 : : /** helper which takes complete care for creating the needed text primitives. It
1292 : : takes care of decorated stuff and all the geometry adaptions needed
1293 : : */
1294 : 2992 : void proccessMetaTextAction(
1295 : : const Point& rTextStartPosition,
1296 : : const XubString& rText,
1297 : : sal_uInt16 nTextStart,
1298 : : sal_uInt16 nTextLength,
1299 : : const ::std::vector< double >& rDXArray,
1300 : : TargetHolder& rTarget,
1301 : : PropertyHolder& rProperty)
1302 : : {
1303 : 2992 : drawinglayer::primitive2d::BasePrimitive2D* pResult = 0;
1304 : 2992 : const Font& rFont = rProperty.getFont();
1305 : 2992 : basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
1306 : :
1307 [ + - ]: 2992 : if(nTextLength)
1308 : : {
1309 [ + - ]: 2992 : drawinglayer::attribute::FontAttribute aFontAttribute;
1310 [ + - ]: 2992 : basegfx::B2DHomMatrix aTextTransform;
1311 : :
1312 : : // fill parameters derived from current font
1313 : : createFontAttributeTransformAndAlignment(
1314 : : aFontAttribute,
1315 : : aTextTransform,
1316 : : aAlignmentOffset,
1317 [ + - ]: 2992 : rProperty);
1318 : :
1319 : : // add TextStartPosition
1320 [ + - ]: 2992 : aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
1321 : :
1322 : : // prepare FontColor and Locale
1323 : 2992 : const basegfx::BColor aFontColor(rProperty.getTextColor());
1324 [ + - ]: 2992 : const com::sun::star::lang::Locale aLocale(MsLangId::convertLanguageToLocale(rProperty.getLanguageType()));
1325 [ + - ]: 2992 : const bool bWordLineMode(rFont.IsWordLineMode());
1326 : :
1327 : : const bool bDecoratedIsNeeded(
1328 [ + - ]: 2992 : UNDERLINE_NONE != rFont.GetOverline()
1329 [ + - ]: 2992 : || UNDERLINE_NONE != rFont.GetUnderline()
1330 [ + - ]: 2992 : || STRIKEOUT_NONE != rFont.GetStrikeout()
1331 [ + - ]: 2992 : || EMPHASISMARK_NONE != (rFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
1332 [ + - ]: 2992 : || RELIEF_NONE != rFont.GetRelief()
1333 [ + - ]: 2992 : || rFont.IsShadow()
1334 [ + - ][ + - ]: 17952 : || bWordLineMode);
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ]
1335 : :
1336 [ - + ]: 2992 : if(bDecoratedIsNeeded)
1337 : : {
1338 : : // prepare overline, underline and srikeout data
1339 [ # # ][ # # ]: 0 : const drawinglayer::primitive2d::TextLine eFontOverline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetOverline()));
1340 [ # # ][ # # ]: 0 : const drawinglayer::primitive2d::TextLine eFontUnderline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetUnderline()));
1341 [ # # ][ # # ]: 0 : const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rFont.GetStrikeout()));
1342 : :
1343 : : // check UndelineAbove
1344 [ # # ][ # # ]: 0 : const bool bUnderlineAbove(drawinglayer::primitive2d::TEXT_LINE_NONE != eFontUnderline && isUnderlineAbove(rFont));
[ # # ]
1345 : :
1346 : : // prepare emphasis mark data
1347 : 0 : drawinglayer::primitive2d::TextEmphasisMark eTextEmphasisMark(drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE);
1348 : :
1349 [ # # ][ # # : 0 : switch(rFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
# # # ]
1350 : : {
1351 : 0 : case EMPHASISMARK_DOT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DOT; break;
1352 : 0 : case EMPHASISMARK_CIRCLE : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_CIRCLE; break;
1353 : 0 : case EMPHASISMARK_DISC : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DISC; break;
1354 : 0 : case EMPHASISMARK_ACCENT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_ACCENT; break;
1355 : : }
1356 : :
1357 [ # # ]: 0 : const bool bEmphasisMarkAbove(rFont.GetEmphasisMark() & EMPHASISMARK_POS_ABOVE);
1358 [ # # ]: 0 : const bool bEmphasisMarkBelow(rFont.GetEmphasisMark() & EMPHASISMARK_POS_BELOW);
1359 : :
1360 : : // prepare font relief data
1361 : 0 : drawinglayer::primitive2d::TextRelief eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE);
1362 : :
1363 [ # # ]: 0 : switch(rFont.GetRelief())
[ # # # ]
1364 : : {
1365 : 0 : case RELIEF_EMBOSSED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
1366 : 0 : case RELIEF_ENGRAVED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
1367 : 0 : default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
1368 : : }
1369 : :
1370 : : // prepare shadow/outline data
1371 [ # # ]: 0 : const bool bShadow(rFont.IsShadow());
1372 : :
1373 : : // TextDecoratedPortionPrimitive2D is needed, create one
1374 : : pResult = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
1375 : :
1376 : : // attributes for TextSimplePortionPrimitive2D
1377 : : aTextTransform,
1378 : : rText,
1379 : : nTextStart,
1380 : : nTextLength,
1381 : : rDXArray,
1382 : : aFontAttribute,
1383 : : aLocale,
1384 : : aFontColor,
1385 : :
1386 : : // attributes for TextDecoratedPortionPrimitive2D
1387 : 0 : rProperty.getOverlineColorActive() ? rProperty.getOverlineColor() : aFontColor,
1388 : 0 : rProperty.getTextLineColorActive() ? rProperty.getTextLineColor() : aFontColor,
1389 : : eFontOverline,
1390 : : eFontUnderline,
1391 : : bUnderlineAbove,
1392 : : eTextStrikeout,
1393 : : bWordLineMode,
1394 : : eTextEmphasisMark,
1395 : : bEmphasisMarkAbove,
1396 : : bEmphasisMarkBelow,
1397 : : eTextRelief,
1398 [ # # ][ # # ]: 0 : bShadow);
[ # # ]
1399 : : }
1400 : : else
1401 : : {
1402 : : // TextSimplePortionPrimitive2D is enough
1403 : : pResult = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
1404 : : aTextTransform,
1405 : : rText,
1406 : : nTextStart,
1407 : : nTextLength,
1408 : : rDXArray,
1409 : : aFontAttribute,
1410 : : aLocale,
1411 [ + - ]: 2992 : aFontColor);
1412 [ + - ][ + - ]: 2992 : }
1413 : : }
1414 : :
1415 [ + - ][ - + ]: 2992 : if(pResult && rProperty.getTextFillColorActive())
[ - + ]
1416 : : {
1417 : : // text background is requested, add and encapsulate both to new primitive
1418 [ # # ]: 0 : drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
1419 [ # # ]: 0 : aTextLayouterDevice.setFont(rFont);
1420 : :
1421 : : // get text width
1422 : 0 : double fTextWidth(0.0);
1423 : :
1424 [ # # ]: 0 : if(rDXArray.empty())
1425 : : {
1426 [ # # ]: 0 : fTextWidth = aTextLayouterDevice.getTextWidth(rText, nTextStart, nTextLength);
1427 : : }
1428 : : else
1429 : : {
1430 [ # # ]: 0 : fTextWidth = rDXArray.back();
1431 : : }
1432 : :
1433 [ # # ]: 0 : if(basegfx::fTools::more(fTextWidth, 0.0))
1434 : : {
1435 : : // build text range
1436 : : const basegfx::B2DRange aTextRange(
1437 [ # # ]: 0 : 0.0, -aTextLayouterDevice.getFontAscent(),
1438 [ # # ][ # # ]: 0 : fTextWidth, aTextLayouterDevice.getFontDescent());
1439 : :
1440 : : // create Transform
1441 [ # # ]: 0 : basegfx::B2DHomMatrix aTextTransform;
1442 : :
1443 [ # # ]: 0 : aTextTransform.translate(aAlignmentOffset.getX(), aAlignmentOffset.getY());
1444 : :
1445 [ # # ][ # # ]: 0 : if(rFont.GetOrientation())
1446 : : {
1447 [ # # ][ # # ]: 0 : aTextTransform.rotate(-rFont.GetOrientation() * F_PI1800);
1448 : : }
1449 : :
1450 [ # # ]: 0 : aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
1451 : :
1452 : : // prepare Primitive2DSequence, put text in foreground
1453 [ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence aSequence(2);
1454 [ # # ][ # # ]: 0 : aSequence[1] = drawinglayer::primitive2d::Primitive2DReference(pResult);
[ # # ][ # # ]
1455 : :
1456 : : // prepare filled polygon
1457 [ # # ]: 0 : basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aTextRange));
1458 [ # # ]: 0 : aOutline.transform(aTextTransform);
1459 : :
1460 [ # # ]: 0 : aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(
1461 : : new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
1462 : : basegfx::B2DPolyPolygon(aOutline),
1463 [ # # ][ # # ]: 0 : rProperty.getTextFillColor()));
[ # # ][ # # ]
[ # # ][ # # ]
1464 : :
1465 : : // set as group at pResult
1466 [ # # ][ # # ]: 0 : pResult = new drawinglayer::primitive2d::GroupPrimitive2D(aSequence);
[ # # ][ # # ]
1467 [ # # ]: 0 : }
1468 : : }
1469 : :
1470 [ + - ]: 2992 : if(pResult)
1471 : : {
1472 : : // add created text primitive to target
1473 [ + - ][ + - ]: 2992 : if(rProperty.getTransformation().isIdentity())
1474 : : {
1475 [ + - ]: 2992 : rTarget.append(pResult);
1476 : : }
1477 : : else
1478 : : {
1479 : : // when a transformation is set, embed to it
1480 [ # # ][ # # ]: 0 : const drawinglayer::primitive2d::Primitive2DReference aReference(pResult);
1481 : :
1482 : : rTarget.append(
1483 : : new drawinglayer::primitive2d::TransformPrimitive2D(
1484 : : rProperty.getTransformation(),
1485 [ # # ][ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1)));
[ # # ][ # # ]
1486 : : }
1487 : 2992 : }
1488 : 2992 : }
1489 : :
1490 : : /** helper which takes complete care for creating the needed textLine primitives */
1491 : 0 : void proccessMetaTextLineAction(
1492 : : const MetaTextLineAction& rAction,
1493 : : TargetHolder& rTarget,
1494 : : PropertyHolder& rProperty)
1495 : : {
1496 : 0 : const double fLineWidth(fabs((double)rAction.GetWidth()));
1497 : :
1498 [ # # ]: 0 : if(fLineWidth > 0.0)
1499 : : {
1500 : 0 : const drawinglayer::primitive2d::TextLine aOverlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetOverline()));
1501 : 0 : const drawinglayer::primitive2d::TextLine aUnderlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetUnderline()));
1502 : 0 : const drawinglayer::primitive2d::TextStrikeout aTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rAction.GetStrikeout()));
1503 : :
1504 : 0 : const bool bOverlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aOverlineMode);
1505 : 0 : const bool bUnderlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aUnderlineMode);
1506 : 0 : const bool bStrikeoutUsed(drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE != aTextStrikeout);
1507 : :
1508 [ # # ][ # # ]: 0 : if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed)
[ # # ]
1509 : : {
1510 [ # # ]: 0 : std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargetVector;
1511 : 0 : basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
1512 [ # # ]: 0 : drawinglayer::attribute::FontAttribute aFontAttribute;
1513 [ # # ]: 0 : basegfx::B2DHomMatrix aTextTransform;
1514 : :
1515 : : // fill parameters derived from current font
1516 : : createFontAttributeTransformAndAlignment(
1517 : : aFontAttribute,
1518 : : aTextTransform,
1519 : : aAlignmentOffset,
1520 [ # # ]: 0 : rProperty);
1521 : :
1522 : : // add TextStartPosition
1523 [ # # ]: 0 : aTextTransform.translate(rAction.GetStartPoint().X(), rAction.GetStartPoint().Y());
1524 : :
1525 : : // prepare TextLayouter (used in most cases)
1526 [ # # ]: 0 : drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
1527 [ # # ]: 0 : aTextLayouter.setFont(rProperty.getFont());
1528 : :
1529 [ # # ]: 0 : if(bOverlineUsed)
1530 : : {
1531 : : // create primitive geometry for overline
1532 : : aTargetVector.push_back(
1533 : : new drawinglayer::primitive2d::TextLinePrimitive2D(
1534 : : aTextTransform,
1535 : : fLineWidth,
1536 : : aTextLayouter.getOverlineOffset(),
1537 : : aTextLayouter.getOverlineHeight(),
1538 : : aOverlineMode,
1539 [ # # ][ # # ]: 0 : rProperty.getOverlineColor()));
[ # # ][ # # ]
1540 : : }
1541 : :
1542 [ # # ]: 0 : if(bUnderlineUsed)
1543 : : {
1544 : : // create primitive geometry for underline
1545 : : aTargetVector.push_back(
1546 : : new drawinglayer::primitive2d::TextLinePrimitive2D(
1547 : : aTextTransform,
1548 : : fLineWidth,
1549 : : aTextLayouter.getUnderlineOffset(),
1550 : : aTextLayouter.getUnderlineHeight(),
1551 : : aUnderlineMode,
1552 [ # # ][ # # ]: 0 : rProperty.getTextLineColor()));
[ # # ][ # # ]
1553 : : }
1554 : :
1555 [ # # ]: 0 : if(bStrikeoutUsed)
1556 : : {
1557 : : // create primitive geometry for strikeout
1558 [ # # ][ # # ]: 0 : if(drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout
1559 : : || drawinglayer::primitive2d::TEXT_STRIKEOUT_X == aTextStrikeout)
1560 : : {
1561 : : // strikeout with character
1562 : : const sal_Unicode aStrikeoutChar(
1563 [ # # ]: 0 : drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout ? '/' : 'X');
1564 : : const com::sun::star::lang::Locale aLocale(MsLangId::convertLanguageToLocale(
1565 [ # # ]: 0 : rProperty.getLanguageType()));
1566 : :
1567 : : aTargetVector.push_back(
1568 : : new drawinglayer::primitive2d::TextCharacterStrikeoutPrimitive2D(
1569 : : aTextTransform,
1570 : : fLineWidth,
1571 : : rProperty.getTextColor(),
1572 : : aStrikeoutChar,
1573 : : aFontAttribute,
1574 [ # # ][ # # ]: 0 : aLocale));
1575 : : }
1576 : : else
1577 : : {
1578 : : // strikeout with geometry
1579 : : aTargetVector.push_back(
1580 : : new drawinglayer::primitive2d::TextGeometryStrikeoutPrimitive2D(
1581 : : aTextTransform,
1582 : : fLineWidth,
1583 : : rProperty.getTextColor(),
1584 : : aTextLayouter.getUnderlineHeight(),
1585 : : aTextLayouter.getStrikeoutOffset(),
1586 [ # # ][ # # ]: 0 : aTextStrikeout));
[ # # ][ # # ]
1587 : : }
1588 : : }
1589 : :
1590 [ # # ]: 0 : if(!aTargetVector.empty())
1591 : : {
1592 : : // add created text primitive to target
1593 [ # # ][ # # ]: 0 : if(rProperty.getTransformation().isIdentity())
1594 : : {
1595 [ # # ]: 0 : for(sal_uInt32 a(0); a < aTargetVector.size(); a++)
1596 : : {
1597 [ # # ][ # # ]: 0 : rTarget.append(aTargetVector[a]);
1598 : : }
1599 : : }
1600 : : else
1601 : : {
1602 : : // when a transformation is set, embed to it
1603 [ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence xTargets(aTargetVector.size());
1604 : :
1605 [ # # ]: 0 : for(sal_uInt32 a(0); a < aTargetVector.size(); a++)
1606 : : {
1607 [ # # ][ # # ]: 0 : xTargets[a] = drawinglayer::primitive2d::Primitive2DReference(aTargetVector[a]);
[ # # ][ # # ]
[ # # ]
1608 : : }
1609 : :
1610 : : rTarget.append(
1611 : : new drawinglayer::primitive2d::TransformPrimitive2D(
1612 : : rProperty.getTransformation(),
1613 [ # # ][ # # ]: 0 : xTargets));
[ # # ]
1614 : : }
1615 [ # # ][ # # ]: 0 : }
[ # # ]
1616 : : }
1617 : : }
1618 : :
1619 : 0 : }
1620 : :
1621 : : /** This is the main interpreter method. It is designed to handle the given Metafile
1622 : : completely inside the given context and target. It may use and modify the context and
1623 : : target. This design allows to call itself recursively wich adapted contexts and
1624 : : targets as e.g. needed for the META_FLOATTRANSPARENT_ACTION where the content is expressed
1625 : : as a metafile as sub-content.
1626 : :
1627 : : This interpreter is as free of VCL functionality as possible. It uses VCL data classes
1628 : : (else reading the data would not be possible), but e.g. does NOT use a local OutputDevice
1629 : : as most other MetaFile interpreters/exporters do to hold and work with the current context.
1630 : : This is necessary to be able to get away from the strong internal VCL-binding.
1631 : :
1632 : : It tries to combine e.g. pixel and/or point actions and to stitch together single line primitives
1633 : : where possible (which is not trivial with the possible line geometry definitions).
1634 : :
1635 : : It tries to handle clipping no longer as Regions and spans of Rectangles, but as PolyPolygon
1636 : : ClipRegions with (where possible) high precision by using the best possible data quality
1637 : : from the Region. The Region is unavoidable as data container, but nowadays allows the transport
1638 : : of Polygon-based clip regions. Where this is not used, a Polygon is constructed from the
1639 : : Region ranges. All primitive clipping uses the MaskPrimitive2D with Polygon-based clipping.
1640 : :
1641 : : I have marked the single MetaActions with:
1642 : :
1643 : : SIMPLE, DONE:
1644 : : Simple, e.g nothing to do or value setting in the context
1645 : :
1646 : : CHECKED, WORKS WELL:
1647 : : Thoroughly tested with extra written test code which created a replacement
1648 : : Metafile just to test this action in various combinations
1649 : :
1650 : : NEEDS IMPLEMENTATION:
1651 : : Not implemented and asserted, but also no usage found, neither in own Metafile
1652 : : creations, nor in EMF/WMF imports (checked with a whole bunch of critical EMF/WMF
1653 : : bugdocs)
1654 : :
1655 : : For more commens, see the single action implementations.
1656 : : */
1657 : 65 : void interpretMetafile(
1658 : : const GDIMetaFile& rMetaFile,
1659 : : TargetHolders& rTargetHolders,
1660 : : PropertyHolders& rPropertyHolders,
1661 : : const drawinglayer::geometry::ViewInformation2D& rViewInformation)
1662 : : {
1663 : 65 : const size_t nCount(rMetaFile.GetActionSize());
1664 : :
1665 [ + + ]: 94042 : for(size_t nAction(0); nAction < nCount; nAction++)
1666 : : {
1667 : 93977 : MetaAction* pAction = rMetaFile.GetAction(nAction);
1668 : :
1669 [ - - - - : 93977 : switch(pAction->GetType())
+ - - - -
- + - + -
+ - - - -
- - + - -
- - - - -
- + + - +
+ + + + -
+ + + - -
- - - - -
- + + - -
+ - ]
1670 : : {
1671 : : case META_NULL_ACTION :
1672 : : {
1673 : : /** SIMPLE, DONE */
1674 : 0 : break;
1675 : : }
1676 : : case META_PIXEL_ACTION :
1677 : : {
1678 : : /** CHECKED, WORKS WELL */
1679 [ # # ]: 0 : std::vector< basegfx::B2DPoint > aPositions;
1680 : 0 : Color aLastColor(COL_BLACK);
1681 : :
1682 [ # # ][ # # ]: 0 : while(META_PIXEL_ACTION == pAction->GetType() && nAction < nCount)
[ # # ]
1683 : : {
1684 : 0 : const MetaPixelAction* pA = (const MetaPixelAction*)pAction;
1685 : :
1686 [ # # ]: 0 : if(pA->GetColor() != aLastColor)
1687 : : {
1688 [ # # ]: 0 : if(!aPositions.empty())
1689 : : {
1690 [ # # ][ # # ]: 0 : createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
[ # # ]
1691 : 0 : aPositions.clear();
1692 : : }
1693 : :
1694 : 0 : aLastColor = pA->GetColor();
1695 : : }
1696 : :
1697 : 0 : const Point& rPoint = pA->GetPoint();
1698 [ # # ]: 0 : aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y()));
1699 [ # # ][ # # ]: 0 : nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
1700 : : }
1701 : :
1702 : 0 : nAction--;
1703 : :
1704 [ # # ]: 0 : if(!aPositions.empty())
1705 : : {
1706 [ # # ][ # # ]: 0 : createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
[ # # ]
1707 : : }
1708 : :
1709 : 0 : break;
1710 : : }
1711 : : case META_POINT_ACTION :
1712 : : {
1713 : : /** CHECKED, WORKS WELL */
1714 [ # # ]: 0 : if(rPropertyHolders.Current().getLineColorActive())
1715 : : {
1716 [ # # ]: 0 : std::vector< basegfx::B2DPoint > aPositions;
1717 : :
1718 [ # # ][ # # ]: 0 : while(META_POINT_ACTION == pAction->GetType() && nAction < nCount)
[ # # ]
1719 : : {
1720 : 0 : const MetaPointAction* pA = (const MetaPointAction*)pAction;
1721 : 0 : const Point& rPoint = pA->GetPoint();
1722 [ # # ]: 0 : aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y()));
1723 [ # # ][ # # ]: 0 : nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
1724 : : }
1725 : :
1726 : 0 : nAction--;
1727 : :
1728 [ # # ]: 0 : if(!aPositions.empty())
1729 : : {
1730 [ # # ][ # # ]: 0 : createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), rPropertyHolders.Current().getLineColor());
[ # # ][ # # ]
1731 : 0 : }
1732 : : }
1733 : :
1734 : 0 : break;
1735 : : }
1736 : : case META_LINE_ACTION :
1737 : : {
1738 : : /** CHECKED, WORKS WELL */
1739 [ # # ]: 0 : if(rPropertyHolders.Current().getLineColorActive())
1740 : : {
1741 [ # # ]: 0 : basegfx::B2DPolygon aLinePolygon;
1742 [ # # ]: 0 : LineInfo aLineInfo;
1743 : :
1744 [ # # ][ # # ]: 0 : while(META_LINE_ACTION == pAction->GetType() && nAction < nCount)
[ # # ]
1745 : : {
1746 : 0 : const MetaLineAction* pA = (const MetaLineAction*)pAction;
1747 : 0 : const Point& rStartPoint = pA->GetStartPoint();
1748 : 0 : const Point& rEndPoint = pA->GetEndPoint();
1749 : 0 : const basegfx::B2DPoint aStart(rStartPoint.X(), rStartPoint.Y());
1750 : 0 : const basegfx::B2DPoint aEnd(rEndPoint.X(), rEndPoint.Y());
1751 : :
1752 [ # # ][ # # ]: 0 : if(aLinePolygon.count())
1753 : : {
1754 [ # # ]: 0 : if(pA->GetLineInfo() == aLineInfo
[ # # # # ]
[ # # ]
1755 [ # # ][ # # ]: 0 : && aStart == aLinePolygon.getB2DPoint(aLinePolygon.count() - 1))
[ # # ][ # # ]
1756 : : {
1757 [ # # ]: 0 : aLinePolygon.append(aEnd);
1758 : : }
1759 : : else
1760 : : {
1761 [ # # ]: 0 : aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE
1762 [ # # ][ # # ]: 0 : createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ]
1763 [ # # ]: 0 : aLinePolygon.clear();
1764 [ # # ]: 0 : aLineInfo = pA->GetLineInfo();
1765 [ # # ]: 0 : aLinePolygon.append(aStart);
1766 [ # # ]: 0 : aLinePolygon.append(aEnd);
1767 : : }
1768 : : }
1769 : : else
1770 : : {
1771 [ # # ]: 0 : aLineInfo = pA->GetLineInfo();
1772 [ # # ]: 0 : aLinePolygon.append(aStart);
1773 [ # # ]: 0 : aLinePolygon.append(aEnd);
1774 : : }
1775 : :
1776 [ # # ][ # # ]: 0 : nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
1777 : 0 : }
1778 : :
1779 : 0 : nAction--;
1780 : :
1781 [ # # ][ # # ]: 0 : if(aLinePolygon.count())
1782 : : {
1783 [ # # ]: 0 : aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE
1784 [ # # ][ # # ]: 0 : createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ]
1785 [ # # ][ # # ]: 0 : }
1786 : : }
1787 : :
1788 : 0 : break;
1789 : : }
1790 : : case META_RECT_ACTION :
1791 : : {
1792 : : /** CHECKED, WORKS WELL */
1793 [ - + ]: 4361 : if(rPropertyHolders.Current().getLineOrFillActive())
1794 : : {
1795 : 0 : const MetaRectAction* pA = (const MetaRectAction*)pAction;
1796 : 0 : const Rectangle& rRectangle = pA->GetRect();
1797 : :
1798 [ # # ]: 0 : if(!rRectangle.IsEmpty())
1799 : : {
1800 [ # # ]: 0 : const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
1801 : :
1802 [ # # ][ # # ]: 0 : if(!aRange.isEmpty())
1803 : : {
1804 [ # # ]: 0 : const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
1805 [ # # ][ # # ]: 0 : createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
1806 : : }
1807 : : }
1808 : : }
1809 : :
1810 : 4361 : break;
1811 : : }
1812 : : case META_ROUNDRECT_ACTION :
1813 : : {
1814 : : /** CHECKED, WORKS WELL */
1815 : : /** The original OutputDevice::DrawRect paints nothing when nHor or nVer is zero; but just
1816 : : because the tools::Polygon operator creating the rounding does produce nonsense. I assume
1817 : : this an error and create an unrounded rectangle in that case (implicit in
1818 : : createPolygonFromRect)
1819 : : */
1820 [ # # ]: 0 : if(rPropertyHolders.Current().getLineOrFillActive())
1821 : : {
1822 : 0 : const MetaRoundRectAction* pA = (const MetaRoundRectAction*)pAction;
1823 : 0 : const Rectangle& rRectangle = pA->GetRect();
1824 : :
1825 [ # # ]: 0 : if(!rRectangle.IsEmpty())
1826 : : {
1827 [ # # ]: 0 : const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
1828 : :
1829 [ # # ][ # # ]: 0 : if(!aRange.isEmpty())
1830 : : {
1831 : 0 : const sal_uInt32 nHor(pA->GetHorzRound());
1832 : 0 : const sal_uInt32 nVer(pA->GetVertRound());
1833 [ # # ]: 0 : basegfx::B2DPolygon aOutline;
1834 : :
1835 [ # # ][ # # ]: 0 : if(nHor || nVer)
1836 : : {
1837 [ # # ][ # # ]: 0 : double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
[ # # ]
1838 [ # # ][ # # ]: 0 : double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
[ # # ]
1839 [ # # ][ # # ]: 0 : fRadiusX = std::max(0.0, std::min(1.0, fRadiusX));
1840 [ # # ][ # # ]: 0 : fRadiusY = std::max(0.0, std::min(1.0, fRadiusY));
1841 : :
1842 [ # # ][ # # ]: 0 : aOutline = basegfx::tools::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
[ # # ]
1843 : : }
1844 : : else
1845 : : {
1846 [ # # ][ # # ]: 0 : aOutline = basegfx::tools::createPolygonFromRect(aRange);
[ # # ]
1847 : : }
1848 : :
1849 [ # # ][ # # ]: 0 : createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
1850 : : }
1851 : : }
1852 : : }
1853 : :
1854 : 0 : break;
1855 : : }
1856 : : case META_ELLIPSE_ACTION :
1857 : : {
1858 : : /** CHECKED, WORKS WELL */
1859 [ # # ]: 0 : if(rPropertyHolders.Current().getLineOrFillActive())
1860 : : {
1861 : 0 : const MetaEllipseAction* pA = (const MetaEllipseAction*)pAction;
1862 : 0 : const Rectangle& rRectangle = pA->GetRect();
1863 : :
1864 [ # # ]: 0 : if(!rRectangle.IsEmpty())
1865 : : {
1866 [ # # ]: 0 : const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
1867 : :
1868 [ # # ][ # # ]: 0 : if(!aRange.isEmpty())
1869 : : {
1870 : : const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromEllipse(
1871 [ # # ][ # # ]: 0 : aRange.getCenter(), aRange.getWidth() * 0.5, aRange.getHeight() * 0.5));
[ # # ][ # # ]
1872 : :
1873 [ # # ][ # # ]: 0 : createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
1874 : : }
1875 : : }
1876 : : }
1877 : :
1878 : 0 : break;
1879 : : }
1880 : : case META_ARC_ACTION :
1881 : : {
1882 : : /** CHECKED, WORKS WELL */
1883 [ # # ]: 0 : if(rPropertyHolders.Current().getLineColorActive())
1884 : : {
1885 : 0 : const MetaArcAction* pA = (const MetaArcAction*)pAction;
1886 [ # # ]: 0 : const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC);
1887 [ # # ]: 0 : const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
1888 : :
1889 [ # # ][ # # ]: 0 : createHairlinePrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
1890 : : }
1891 : :
1892 : 0 : break;
1893 : : }
1894 : : case META_PIE_ACTION :
1895 : : {
1896 : : /** CHECKED, WORKS WELL */
1897 [ # # ]: 0 : if(rPropertyHolders.Current().getLineOrFillActive())
1898 : : {
1899 : 0 : const MetaPieAction* pA = (const MetaPieAction*)pAction;
1900 [ # # ]: 0 : const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE);
1901 [ # # ]: 0 : const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
1902 : :
1903 [ # # ][ # # ]: 0 : createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
1904 : : }
1905 : :
1906 : 0 : break;
1907 : : }
1908 : : case META_CHORD_ACTION :
1909 : : {
1910 : : /** CHECKED, WORKS WELL */
1911 [ # # ]: 0 : if(rPropertyHolders.Current().getLineOrFillActive())
1912 : : {
1913 : 0 : const MetaChordAction* pA = (const MetaChordAction*)pAction;
1914 [ # # ]: 0 : const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD);
1915 [ # # ]: 0 : const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
1916 : :
1917 [ # # ][ # # ]: 0 : createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
1918 : : }
1919 : :
1920 : 0 : break;
1921 : : }
1922 : : case META_POLYLINE_ACTION :
1923 : : {
1924 : : /** CHECKED, WORKS WELL */
1925 [ + - ]: 3595 : if(rPropertyHolders.Current().getLineColorActive())
1926 : : {
1927 : 3595 : const MetaPolyLineAction* pA = (const MetaPolyLineAction*)pAction;
1928 [ + - ]: 3595 : createLinePrimitive(pA->GetPolygon().getB2DPolygon(), pA->GetLineInfo(), rTargetHolders.Current(), rPropertyHolders.Current());
1929 : : }
1930 : :
1931 : 3595 : break;
1932 : : }
1933 : : case META_POLYGON_ACTION :
1934 : : {
1935 : : /** CHECKED, WORKS WELL */
1936 [ # # ]: 0 : if(rPropertyHolders.Current().getLineOrFillActive())
1937 : : {
1938 : 0 : const MetaPolygonAction* pA = (const MetaPolygonAction*)pAction;
1939 [ # # ]: 0 : basegfx::B2DPolygon aOutline(pA->GetPolygon().getB2DPolygon());
1940 : :
1941 : : // the metafile play interprets the polygons from MetaPolygonAction
1942 : : // always as closed and always paints an edge from last to first point,
1943 : : // so force to closed here to emulate that
1944 [ # # ][ # # ]: 0 : if(aOutline.count() > 1 && !aOutline.isClosed())
[ # # ][ # # ]
[ # # ]
1945 : : {
1946 [ # # ]: 0 : aOutline.setClosed(true);
1947 : : }
1948 : :
1949 [ # # ][ # # ]: 0 : createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
1950 : : }
1951 : :
1952 : 0 : break;
1953 : : }
1954 : : case META_POLYPOLYGON_ACTION :
1955 : : {
1956 : : /** CHECKED, WORKS WELL */
1957 [ + - ]: 900 : if(rPropertyHolders.Current().getLineOrFillActive())
1958 : : {
1959 : 900 : const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*)pAction;
1960 [ + - ]: 900 : basegfx::B2DPolyPolygon aPolyPolygonOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
1961 : :
1962 : : // the metafile play interprets the single polygons from MetaPolyPolygonAction
1963 : : // always as closed and always paints an edge from last to first point,
1964 : : // so force to closed here to emulate that
1965 [ + - ][ + + ]: 1800 : for(sal_uInt32 b(0); b < aPolyPolygonOutline.count(); b++)
1966 : : {
1967 [ + - ]: 900 : basegfx::B2DPolygon aPolygonOutline(aPolyPolygonOutline.getB2DPolygon(b));
1968 : :
1969 [ + - ][ + - ]: 900 : if(aPolygonOutline.count() > 1 && !aPolygonOutline.isClosed())
[ + - ][ - + ]
[ - + ]
1970 : : {
1971 [ # # ]: 0 : aPolygonOutline.setClosed(true);
1972 [ # # ]: 0 : aPolyPolygonOutline.setB2DPolygon(b, aPolygonOutline);
1973 : : }
1974 [ + - ]: 900 : }
1975 : :
1976 [ + - ][ + - ]: 900 : createHairlineAndFillPrimitive(aPolyPolygonOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ + - ][ + - ]
1977 : : }
1978 : :
1979 : 900 : break;
1980 : : }
1981 : : case META_TEXT_ACTION :
1982 : : {
1983 : : /** CHECKED, WORKS WELL */
1984 : 0 : const MetaTextAction* pA = (const MetaTextAction*)pAction;
1985 : 0 : sal_uInt32 nTextLength(pA->GetLen());
1986 : 0 : const sal_uInt32 nTextIndex(pA->GetIndex());
1987 : 0 : const sal_uInt32 nStringLength(pA->GetText().getLength());
1988 : :
1989 [ # # ]: 0 : if(nTextLength + nTextIndex > nStringLength)
1990 : : {
1991 : 0 : nTextLength = nStringLength - nTextIndex;
1992 : : }
1993 : :
1994 [ # # ][ # # ]: 0 : if(nTextLength && rPropertyHolders.Current().getTextColorActive())
[ # # ]
1995 : : {
1996 [ # # ]: 0 : const std::vector< double > aDXArray;
1997 : : proccessMetaTextAction(
1998 : 0 : pA->GetPoint(),
1999 : 0 : pA->GetText(),
2000 : : nTextIndex,
2001 : : nTextLength,
2002 : : aDXArray,
2003 [ # # ]: 0 : rTargetHolders.Current(),
2004 [ # # # # : 0 : rPropertyHolders.Current());
# # ][ # # ]
2005 : : }
2006 : :
2007 : 0 : break;
2008 : : }
2009 : : case META_TEXTARRAY_ACTION :
2010 : : {
2011 : : /** CHECKED, WORKS WELL */
2012 : 2992 : const MetaTextArrayAction* pA = (const MetaTextArrayAction*)pAction;
2013 : 2992 : sal_uInt32 nTextLength(pA->GetLen());
2014 : 2992 : const sal_uInt32 nTextIndex(pA->GetIndex());
2015 : 2992 : const sal_uInt32 nStringLength(pA->GetText().getLength());
2016 : :
2017 [ - + ]: 2992 : if(nTextLength + nTextIndex > nStringLength)
2018 : : {
2019 [ # # ]: 0 : nTextLength = nTextIndex > nStringLength ? 0 : nStringLength - nTextIndex;
2020 : : }
2021 : :
2022 [ + - ][ + - ]: 2992 : if(nTextLength && rPropertyHolders.Current().getTextColorActive())
[ + - ]
2023 : : {
2024 : : // preapare DXArray (if used)
2025 [ + - ]: 2992 : std::vector< double > aDXArray;
2026 : 2992 : sal_Int32* pDXArray = pA->GetDXArray();
2027 : :
2028 [ + - ]: 2992 : if(pDXArray)
2029 : : {
2030 [ + - ]: 2992 : aDXArray.reserve(nTextLength);
2031 : :
2032 [ + + ]: 27969 : for(sal_uInt32 a(0); a < nTextLength; a++)
2033 : : {
2034 [ + - ]: 24977 : aDXArray.push_back((double)(*(pDXArray + a)));
2035 : : }
2036 : : }
2037 : :
2038 : : proccessMetaTextAction(
2039 : 2992 : pA->GetPoint(),
2040 : 2992 : pA->GetText(),
2041 : : nTextIndex,
2042 : : nTextLength,
2043 : : aDXArray,
2044 [ + - ]: 2992 : rTargetHolders.Current(),
2045 [ + - + - : 8976 : rPropertyHolders.Current());
+ - ][ + - ]
2046 : : }
2047 : :
2048 : 2992 : break;
2049 : : }
2050 : : case META_STRETCHTEXT_ACTION :
2051 : : {
2052 : : // #i108440# StarMath uses MetaStretchTextAction, thus support is needed.
2053 : : // It looks as if it pretty never really uses a width different from
2054 : : // the default text-layout width, but it's not possible to be sure.
2055 : : // Implemented getting the DXArray and checking for scale at all. If
2056 : : // scale is more than 3.5% different, scale the DXArray before usage.
2057 : : // New status:
2058 : :
2059 : : /** CHECKED, WORKS WELL */
2060 : 0 : const MetaStretchTextAction* pA = (const MetaStretchTextAction*)pAction;
2061 : 0 : sal_uInt32 nTextLength(pA->GetLen());
2062 : 0 : const sal_uInt32 nTextIndex(pA->GetIndex());
2063 : 0 : const sal_uInt32 nStringLength(pA->GetText().getLength());
2064 : :
2065 [ # # ]: 0 : if(nTextLength + nTextIndex > nStringLength)
2066 : : {
2067 : 0 : nTextLength = nStringLength - nTextIndex;
2068 : : }
2069 : :
2070 [ # # ][ # # ]: 0 : if(nTextLength && rPropertyHolders.Current().getTextColorActive())
[ # # ]
2071 : : {
2072 [ # # ]: 0 : drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
2073 [ # # ][ # # ]: 0 : aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
2074 : :
2075 : : ::std::vector< double > aTextArray(
2076 : : aTextLayouterDevice.getTextArray(
2077 : 0 : pA->GetText(),
2078 : : nTextIndex,
2079 [ # # ][ # # ]: 0 : nTextLength));
[ # # ]
2080 : :
2081 [ # # ]: 0 : if(!aTextArray.empty())
2082 : : {
2083 [ # # ]: 0 : const double fTextLength(aTextArray.back());
2084 : :
2085 [ # # ][ # # ]: 0 : if(0.0 != fTextLength && pA->GetWidth())
[ # # ]
2086 : : {
2087 : 0 : const double fRelative(pA->GetWidth() / fTextLength);
2088 : :
2089 [ # # ]: 0 : if(fabs(fRelative - 1.0) >= 0.035)
2090 : : {
2091 : : // when derivation is more than 3,5% from default text size,
2092 : : // scale the DXArray
2093 [ # # ]: 0 : for(sal_uInt32 a(0); a < aTextArray.size(); a++)
2094 : : {
2095 [ # # ]: 0 : aTextArray[a] *= fRelative;
2096 : : }
2097 : : }
2098 : : }
2099 : : }
2100 : :
2101 : : proccessMetaTextAction(
2102 : 0 : pA->GetPoint(),
2103 : 0 : pA->GetText(),
2104 : : nTextIndex,
2105 : : nTextLength,
2106 : : aTextArray,
2107 [ # # ]: 0 : rTargetHolders.Current(),
2108 [ # # # # : 0 : rPropertyHolders.Current());
# # ][ # # ]
[ # # ]
2109 : : }
2110 : :
2111 : 0 : break;
2112 : : }
2113 : : case META_TEXTRECT_ACTION :
2114 : : {
2115 : : /** CHECKED, WORKS WELL */
2116 : : // OSL_FAIL("META_TEXTRECT_ACTION requested (!)");
2117 : 0 : const MetaTextRectAction* pA = (const MetaTextRectAction*)pAction;
2118 : 0 : const Rectangle& rRectangle = pA->GetRect();
2119 : 0 : const sal_uInt32 nStringLength(pA->GetText().getLength());
2120 : :
2121 [ # # ][ # # ]: 0 : if(!rRectangle.IsEmpty() && 0 != nStringLength)
[ # # ]
2122 : : {
2123 : : // The problem with this action is that it describes unlayouted text
2124 : : // and the layout capabilities are in EditEngine/Outliner in SVX. The
2125 : : // same problem is true for VCL which internally has implementations
2126 : : // to layout text in this case. There exists even a call
2127 : : // OutputDevice::AddTextRectActions(...) to create the needed actions
2128 : : // as 'sub-content' of a Metafile. Unfortunately i do not have an
2129 : : // OutputDevice here since this interpreter tries to work without
2130 : : // VCL AFAP.
2131 : : // Since AddTextRectActions is the only way as long as we do not have
2132 : : // a simple text layouter available, i will try to add it to the
2133 : : // TextLayouterDevice isloation.
2134 [ # # ]: 0 : drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
2135 [ # # ][ # # ]: 0 : aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
2136 [ # # ]: 0 : GDIMetaFile aGDIMetaFile;
2137 : :
2138 : : aTextLayouterDevice.addTextRectActions(
2139 [ # # ][ # # ]: 0 : rRectangle, pA->GetText(), pA->GetStyle(), aGDIMetaFile);
[ # # ]
2140 : :
2141 [ # # ][ # # ]: 0 : if(aGDIMetaFile.GetActionSize())
2142 : : {
2143 : : // cerate sub-content
2144 [ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence xSubContent;
2145 : : {
2146 [ # # ]: 0 : rTargetHolders.Push();
2147 : : // #i# for sub-Mteafile contents, do start with new, default render state
2148 [ # # ]: 0 : rPropertyHolders.PushDefault();
2149 [ # # ]: 0 : interpretMetafile(aGDIMetaFile, rTargetHolders, rPropertyHolders, rViewInformation);
2150 [ # # ][ # # ]: 0 : xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
2151 [ # # ]: 0 : rPropertyHolders.Pop();
2152 [ # # ]: 0 : rTargetHolders.Pop();
2153 : : }
2154 : :
2155 [ # # ]: 0 : if(xSubContent.hasElements())
2156 : : {
2157 : : // add with transformation
2158 [ # # ]: 0 : rTargetHolders.Current().append(
2159 : : new drawinglayer::primitive2d::TransformPrimitive2D(
2160 [ # # ]: 0 : rPropertyHolders.Current().getTransformation(),
2161 [ # # ][ # # ]: 0 : xSubContent));
2162 [ # # ]: 0 : }
2163 [ # # ][ # # ]: 0 : }
2164 : : }
2165 : :
2166 : 0 : break;
2167 : : }
2168 : : case META_BMP_ACTION :
2169 : : {
2170 : : /** CHECKED, WORKS WELL */
2171 : 0 : const MetaBmpAction* pA = (const MetaBmpAction*)pAction;
2172 [ # # ]: 0 : const BitmapEx aBitmapEx(pA->GetBitmap());
2173 : :
2174 [ # # ][ # # ]: 0 : createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ]
2175 : :
2176 [ # # ]: 0 : break;
2177 : : }
2178 : : case META_BMPSCALE_ACTION :
2179 : : {
2180 : : /** CHECKED, WORKS WELL */
2181 : 0 : const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*)pAction;
2182 [ # # ]: 0 : const Bitmap aBitmapEx(pA->GetBitmap());
2183 : :
2184 [ # # ][ # # ]: 0 : createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
2185 : :
2186 [ # # ]: 0 : break;
2187 : : }
2188 : : case META_BMPSCALEPART_ACTION :
2189 : : {
2190 : : /** CHECKED, WORKS WELL */
2191 : 0 : const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*)pAction;
2192 : 0 : const Bitmap& rBitmap = pA->GetBitmap();
2193 : :
2194 [ # # ]: 0 : if(!rBitmap.IsEmpty())
2195 : : {
2196 [ # # ]: 0 : Bitmap aCroppedBitmap(rBitmap);
2197 [ # # ]: 0 : const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
2198 : :
2199 [ # # ][ # # ]: 0 : if(!aCropRectangle.IsEmpty())
2200 : : {
2201 [ # # ]: 0 : aCroppedBitmap.Crop(aCropRectangle);
2202 : : }
2203 : :
2204 [ # # ]: 0 : const BitmapEx aCroppedBitmapEx(aCroppedBitmap);
2205 [ # # ][ # # ]: 0 : createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
2206 : : }
2207 : :
2208 : 0 : break;
2209 : : }
2210 : : case META_BMPEX_ACTION :
2211 : : {
2212 : : /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */
2213 : 0 : const MetaBmpExAction* pA = (const MetaBmpExAction*)pAction;
2214 : 0 : const BitmapEx& rBitmapEx = pA->GetBitmapEx();
2215 : :
2216 : 0 : createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
2217 : :
2218 : 0 : break;
2219 : : }
2220 : : case META_BMPEXSCALE_ACTION :
2221 : : {
2222 : : /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */
2223 : 12 : const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*)pAction;
2224 : 12 : const BitmapEx& rBitmapEx = pA->GetBitmapEx();
2225 : :
2226 : 12 : createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
2227 : :
2228 : 12 : break;
2229 : : }
2230 : : case META_BMPEXSCALEPART_ACTION :
2231 : : {
2232 : : /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */
2233 : 0 : const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*)pAction;
2234 : 0 : const BitmapEx& rBitmapEx = pA->GetBitmapEx();
2235 : :
2236 [ # # ]: 0 : if(!rBitmapEx.IsEmpty())
2237 : : {
2238 [ # # ]: 0 : BitmapEx aCroppedBitmapEx(rBitmapEx);
2239 [ # # ]: 0 : const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
2240 : :
2241 [ # # ][ # # ]: 0 : if(!aCropRectangle.IsEmpty())
2242 : : {
2243 [ # # ]: 0 : aCroppedBitmapEx.Crop(aCropRectangle);
2244 : : }
2245 : :
2246 [ # # ][ # # ]: 0 : createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
2247 : : }
2248 : :
2249 : 0 : break;
2250 : : }
2251 : : case META_MASK_ACTION :
2252 : : {
2253 : : /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */
2254 : 0 : const MetaMaskAction* pA = (const MetaMaskAction*)pAction;
2255 [ # # ]: 0 : const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
2256 : :
2257 [ # # ][ # # ]: 0 : createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ]
2258 : :
2259 [ # # ]: 0 : break;
2260 : : }
2261 : : case META_MASKSCALE_ACTION :
2262 : : {
2263 : : /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */
2264 : 0 : const MetaMaskScaleAction* pA = (const MetaMaskScaleAction*)pAction;
2265 [ # # ]: 0 : const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
2266 : :
2267 [ # # ][ # # ]: 0 : createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ]
2268 : :
2269 [ # # ]: 0 : break;
2270 : : }
2271 : : case META_MASKSCALEPART_ACTION :
2272 : : {
2273 : : /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */
2274 : 0 : const MetaMaskScalePartAction* pA = (const MetaMaskScalePartAction*)pAction;
2275 : 0 : const Bitmap& rBitmap = pA->GetBitmap();
2276 : :
2277 [ # # ]: 0 : if(!rBitmap.IsEmpty())
2278 : : {
2279 [ # # ]: 0 : Bitmap aCroppedBitmap(rBitmap);
2280 [ # # ]: 0 : const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
2281 : :
2282 [ # # ][ # # ]: 0 : if(!aCropRectangle.IsEmpty())
2283 : : {
2284 [ # # ]: 0 : aCroppedBitmap.Crop(aCropRectangle);
2285 : : }
2286 : :
2287 [ # # ]: 0 : const BitmapEx aCroppedBitmapEx(createMaskBmpEx(aCroppedBitmap, pA->GetColor()));
2288 [ # # ][ # # ]: 0 : createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
2289 : : }
2290 : :
2291 : 0 : break;
2292 : : }
2293 : : case META_GRADIENT_ACTION :
2294 : : {
2295 : : /** CHECKED, WORKS WELL */
2296 : 0 : const MetaGradientAction* pA = (const MetaGradientAction*)pAction;
2297 : 0 : const Rectangle& rRectangle = pA->GetRect();
2298 : :
2299 [ # # ]: 0 : if(!rRectangle.IsEmpty())
2300 : : {
2301 [ # # ]: 0 : basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
2302 : :
2303 [ # # ][ # # ]: 0 : if(!aRange.isEmpty())
2304 : : {
2305 : 0 : const Gradient& rGradient = pA->GetGradient();
2306 [ # # ]: 0 : const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
2307 [ # # ][ # # ]: 0 : basegfx::B2DPolyPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
[ # # ]
2308 : :
2309 [ # # ][ # # ]: 0 : if(aAttribute.getStartColor() == aAttribute.getEndColor())
[ # # ]
2310 : : {
2311 : : // not really a gradient. Create filled rectangle
2312 : : createFillPrimitive(
2313 : : aOutline,
2314 [ # # ]: 0 : rTargetHolders.Current(),
2315 [ # # ][ # # ]: 0 : rPropertyHolders.Current());
2316 : : }
2317 : : else
2318 : : {
2319 : : // really a gradient
2320 [ # # ][ # # ]: 0 : aRange.transform(rPropertyHolders.Current().getTransformation());
2321 [ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence xGradient(1);
2322 : :
2323 [ # # ][ # # ]: 0 : if(rPropertyHolders.Current().isRasterOpInvert())
2324 : : {
2325 : : // use a special version of FillGradientPrimitive2D which creates
2326 : : // non-overlapping geometry on decomposition to makethe old XOR
2327 : : // paint 'trick' work.
2328 [ # # ]: 0 : xGradient[0] = drawinglayer::primitive2d::Primitive2DReference(
2329 : : new drawinglayer::primitive2d::NonOverlappingFillGradientPrimitive2D(
2330 : : aRange,
2331 [ # # ][ # # ]: 0 : aAttribute));
[ # # ][ # # ]
2332 : : }
2333 : : else
2334 : : {
2335 [ # # ]: 0 : xGradient[0] = drawinglayer::primitive2d::Primitive2DReference(
2336 : : new drawinglayer::primitive2d::FillGradientPrimitive2D(
2337 : : aRange,
2338 [ # # ][ # # ]: 0 : aAttribute));
[ # # ][ # # ]
2339 : : }
2340 : :
2341 : : // #i112300# clip against polygon representing the rectangle from
2342 : : // the action. This is implicitely done using a temp Clipping in VCL
2343 : : // when a MetaGradientAction is executed
2344 [ # # ][ # # ]: 0 : aOutline.transform(rPropertyHolders.Current().getTransformation());
2345 [ # # ]: 0 : rTargetHolders.Current().append(
2346 : : new drawinglayer::primitive2d::MaskPrimitive2D(
2347 : : aOutline,
2348 [ # # ][ # # ]: 0 : xGradient));
[ # # ]
2349 [ # # ][ # # ]: 0 : }
2350 : : }
2351 : : }
2352 : :
2353 : 0 : break;
2354 : : }
2355 : : case META_HATCH_ACTION :
2356 : : {
2357 : : /** CHECKED, WORKS WELL */
2358 : 0 : const MetaHatchAction* pA = (const MetaHatchAction*)pAction;
2359 [ # # ]: 0 : basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
2360 : :
2361 [ # # ][ # # ]: 0 : if(aOutline.count())
2362 : : {
2363 : 0 : const Hatch& rHatch = pA->GetHatch();
2364 [ # # ]: 0 : const drawinglayer::attribute::FillHatchAttribute aAttribute(createFillHatchAttribute(rHatch));
2365 : :
2366 [ # # ][ # # ]: 0 : aOutline.transform(rPropertyHolders.Current().getTransformation());
2367 : :
2368 [ # # ]: 0 : const basegfx::B2DRange aObjectRange(aOutline.getB2DRange());
2369 : : const drawinglayer::primitive2d::Primitive2DReference aFillHatch(
2370 : : new drawinglayer::primitive2d::FillHatchPrimitive2D(
2371 : : aObjectRange,
2372 : : basegfx::BColor(),
2373 [ # # ][ # # ]: 0 : aAttribute));
[ # # ]
2374 : :
2375 [ # # ]: 0 : rTargetHolders.Current().append(
2376 : : new drawinglayer::primitive2d::MaskPrimitive2D(
2377 : : aOutline,
2378 [ # # ][ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence(&aFillHatch, 1)));
[ # # ][ # # ]
[ # # ]
2379 : : }
2380 : :
2381 [ # # ]: 0 : break;
2382 : : }
2383 : : case META_WALLPAPER_ACTION :
2384 : : {
2385 : : /** CHECKED, WORKS WELL */
2386 : 0 : const MetaWallpaperAction* pA = (const MetaWallpaperAction*)pAction;
2387 : 0 : Rectangle aWallpaperRectangle(pA->GetRect());
2388 : :
2389 [ # # ][ # # ]: 0 : if(!aWallpaperRectangle.IsEmpty())
2390 : : {
2391 : 0 : const Wallpaper& rWallpaper = pA->GetWallpaper();
2392 [ # # ]: 0 : const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
2393 : : basegfx::B2DRange aWallpaperRange(
2394 : 0 : aWallpaperRectangle.Left(), aWallpaperRectangle.Top(),
2395 [ # # ]: 0 : aWallpaperRectangle.Right(), aWallpaperRectangle.Bottom());
2396 : :
2397 [ # # ]: 0 : if(WALLPAPER_NULL != eWallpaperStyle)
2398 : : {
2399 [ # # ][ # # ]: 0 : if(rWallpaper.IsBitmap())
2400 : : {
2401 : : // create bitmap background. Caution: This
2402 : : // also will create gradient/color background(s)
2403 : : // when the bitmap is transparent or not tiled
2404 : : CreateAndAppendBitmapWallpaper(
2405 : : aWallpaperRange,
2406 : : rWallpaper,
2407 [ # # ]: 0 : rTargetHolders.Current(),
2408 [ # # ][ # # ]: 0 : rPropertyHolders.Current());
2409 : : }
2410 [ # # ][ # # ]: 0 : else if(rWallpaper.IsGradient())
2411 : : {
2412 : : // create gradient background
2413 [ # # ]: 0 : rTargetHolders.Current().append(
2414 : : CreateGradientWallpaper(
2415 : : aWallpaperRange,
2416 : : rWallpaper.GetGradient(),
2417 [ # # ][ # # ]: 0 : rPropertyHolders.Current()));
[ # # ][ # # ]
[ # # ]
2418 : : }
2419 [ # # ][ # # ]: 0 : else if(!rWallpaper.GetColor().GetTransparency())
2420 : : {
2421 : : // create color background
2422 [ # # ]: 0 : rTargetHolders.Current().append(
2423 : : CreateColorWallpaper(
2424 : : aWallpaperRange,
2425 [ # # ]: 0 : rWallpaper.GetColor().getBColor(),
2426 [ # # ][ # # ]: 0 : rPropertyHolders.Current()));
[ # # ]
2427 : : }
2428 : : }
2429 : : }
2430 : :
2431 : : break;
2432 : : }
2433 : : case META_CLIPREGION_ACTION :
2434 : : {
2435 : : /** CHECKED, WORKS WELL */
2436 : 0 : const MetaClipRegionAction* pA = (const MetaClipRegionAction*)pAction;
2437 : :
2438 [ # # ]: 0 : if(pA->IsClipping())
2439 : : {
2440 : : // new clipping. Get PolyPolygon and transform with current transformation
2441 [ # # ]: 0 : basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(pA->GetRegion()));
2442 : :
2443 [ # # ][ # # ]: 0 : aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
2444 [ # # ][ # # ]: 0 : HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
2445 : : }
2446 : : else
2447 : : {
2448 : : // end clipping
2449 [ # # ]: 0 : const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
2450 : :
2451 [ # # ][ # # ]: 0 : HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
2452 : : }
2453 : :
2454 : 0 : break;
2455 : : }
2456 : : case META_ISECTRECTCLIPREGION_ACTION :
2457 : : {
2458 : : /** CHECKED, WORKS WELL */
2459 : 65 : const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*)pAction;
2460 : 65 : const Rectangle& rRectangle = pA->GetRect();
2461 : :
2462 [ - + ]: 65 : if(rRectangle.IsEmpty())
2463 : : {
2464 : : // intersect with empty rectangle will always give empty
2465 : : // ClipPolyPolygon; start new clipping with empty PolyPolygon
2466 [ # # ]: 0 : const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
2467 : :
2468 [ # # ][ # # ]: 0 : HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
2469 : : }
2470 : : else
2471 : : {
2472 : : // create transformed ClipRange
2473 : : basegfx::B2DRange aClipRange(
2474 : 65 : rRectangle.Left(), rRectangle.Top(),
2475 [ + - ]: 130 : rRectangle.Right(), rRectangle.Bottom());
2476 : :
2477 [ + - ][ + - ]: 65 : aClipRange.transform(rPropertyHolders.Current().getTransformation());
2478 : :
2479 [ + - ][ - + ]: 65 : if(rPropertyHolders.Current().getClipPolyPolygonActive())
2480 : : {
2481 [ # # ][ # # ]: 0 : if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
[ # # ]
2482 : : {
2483 : : // nothing to do, empty active clipPolyPolygon will stay
2484 : : // empty when intersecting
2485 : : }
2486 : : else
2487 : : {
2488 : : // AND existing region and new ClipRange
2489 : : const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
2490 [ # # ][ # # ]: 0 : rPropertyHolders.Current().getClipPolyPolygon());
2491 [ # # ]: 0 : basegfx::B2DPolyPolygon aClippedPolyPolygon;
2492 : :
2493 [ # # ][ # # ]: 0 : if(aOriginalPolyPolygon.count())
2494 : : {
2495 : : aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnRange(
2496 : : aOriginalPolyPolygon,
2497 : : aClipRange,
2498 : : true,
2499 [ # # ][ # # ]: 0 : false);
[ # # ]
2500 : : }
2501 : :
2502 [ # # ][ # # ]: 0 : if(aClippedPolyPolygon != aOriginalPolyPolygon)
2503 : : {
2504 : : // start new clipping with intersected region
2505 : : HandleNewClipRegion(
2506 : : aClippedPolyPolygon,
2507 : : rTargetHolders,
2508 [ # # ]: 0 : rPropertyHolders);
2509 [ # # ][ # # ]: 0 : }
2510 : : }
2511 : : }
2512 : : else
2513 : : {
2514 : : // start new clipping with ClipRange
2515 : : const basegfx::B2DPolyPolygon aNewClipPolyPolygon(
2516 [ + - ][ + - ]: 65 : basegfx::tools::createPolygonFromRect(aClipRange));
[ + - ]
2517 : :
2518 [ + - ][ + - ]: 65 : HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
2519 : : }
2520 : : }
2521 : :
2522 : 65 : break;
2523 : : }
2524 : : case META_ISECTREGIONCLIPREGION_ACTION :
2525 : : {
2526 : : /** CHECKED, WORKS WELL */
2527 : 130 : const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*)pAction;
2528 : 130 : const Region& rNewRegion = pA->GetRegion();
2529 : :
2530 [ - + ]: 130 : if(rNewRegion.IsEmpty())
2531 : : {
2532 : : // intersect with empty region will always give empty
2533 : : // region; start new clipping with empty PolyPolygon
2534 [ # # ]: 0 : const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
2535 : :
2536 [ # # ][ # # ]: 0 : HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
2537 : : }
2538 : : else
2539 : : {
2540 : : // get new ClipPolyPolygon, transform it with current transformation
2541 [ + - ]: 130 : basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(rNewRegion));
2542 [ + - ][ + - ]: 130 : aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
2543 : :
2544 [ + - ][ + - ]: 130 : if(rPropertyHolders.Current().getClipPolyPolygonActive())
2545 : : {
2546 [ + - ][ + - ]: 130 : if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
[ + - ]
2547 : : {
2548 : : // nothing to do, empty active clipPolyPolygon will stay empty
2549 : : // when intersecting with any region
2550 : : }
2551 : : else
2552 : : {
2553 : : // AND existing and new region
2554 : : const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
2555 [ + - ][ + - ]: 130 : rPropertyHolders.Current().getClipPolyPolygon());
2556 [ + - ]: 130 : basegfx::B2DPolyPolygon aClippedPolyPolygon;
2557 : :
2558 [ + - ][ + - ]: 130 : if(aOriginalPolyPolygon.count())
2559 : : {
2560 : : aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
2561 [ + - ][ + - ]: 130 : aOriginalPolyPolygon, aNewClipPolyPolygon, true, false);
[ + - ]
2562 : : }
2563 : :
2564 [ + - ][ - + ]: 130 : if(aClippedPolyPolygon != aOriginalPolyPolygon)
2565 : : {
2566 : : // start new clipping with intersected ClipPolyPolygon
2567 [ # # ]: 0 : HandleNewClipRegion(aClippedPolyPolygon, rTargetHolders, rPropertyHolders);
2568 [ + - ][ + - ]: 130 : }
2569 : : }
2570 : : }
2571 : : else
2572 : : {
2573 : : // start new clipping with new ClipPolyPolygon
2574 [ # # ]: 0 : HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
2575 [ + - ]: 130 : }
2576 : : }
2577 : :
2578 : 130 : break;
2579 : : }
2580 : : case META_MOVECLIPREGION_ACTION :
2581 : : {
2582 : : /** CHECKED, WORKS WELL */
2583 : 0 : const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*)pAction;
2584 : :
2585 [ # # ]: 0 : if(rPropertyHolders.Current().getClipPolyPolygonActive())
2586 : : {
2587 [ # # ]: 0 : if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
2588 : : {
2589 : : // nothing to do
2590 : : }
2591 : : else
2592 : : {
2593 : 0 : const sal_Int32 nHor(pA->GetHorzMove());
2594 : 0 : const sal_Int32 nVer(pA->GetVertMove());
2595 : :
2596 [ # # ][ # # ]: 0 : if(0 != nHor || 0 != nVer)
2597 : : {
2598 : : // prepare translation, add current transformation
2599 : 0 : basegfx::B2DVector aVector(pA->GetHorzMove(), pA->GetVertMove());
2600 [ # # ][ # # ]: 0 : aVector *= rPropertyHolders.Current().getTransformation();
2601 : : basegfx::B2DHomMatrix aTransform(
2602 [ # # ]: 0 : basegfx::tools::createTranslateB2DHomMatrix(aVector));
2603 : :
2604 : : // transform existing region
2605 : : basegfx::B2DPolyPolygon aClipPolyPolygon(
2606 [ # # ][ # # ]: 0 : rPropertyHolders.Current().getClipPolyPolygon());
2607 : :
2608 [ # # ]: 0 : aClipPolyPolygon.transform(aTransform);
2609 [ # # ][ # # ]: 0 : HandleNewClipRegion(aClipPolyPolygon, rTargetHolders, rPropertyHolders);
[ # # ]
2610 : : }
2611 : : }
2612 : : }
2613 : :
2614 : 0 : break;
2615 : : }
2616 : : case META_LINECOLOR_ACTION :
2617 : : {
2618 : : /** CHECKED, WORKS WELL */
2619 : 12451 : const MetaLineColorAction* pA = (const MetaLineColorAction*)pAction;
2620 : 12451 : const bool bActive(pA->IsSetting());
2621 : :
2622 : 12451 : rPropertyHolders.Current().setLineColorActive(bActive);
2623 [ + + ]: 12451 : if(bActive)
2624 [ + - ][ + - ]: 7190 : rPropertyHolders.Current().setLineColor(pA->GetColor().getBColor());
2625 : :
2626 : 12451 : break;
2627 : : }
2628 : : case META_FILLCOLOR_ACTION :
2629 : : {
2630 : : /** CHECKED, WORKS WELL */
2631 : 8856 : const MetaFillColorAction* pA = (const MetaFillColorAction*)pAction;
2632 : 8856 : const bool bActive(pA->IsSetting());
2633 : :
2634 : 8856 : rPropertyHolders.Current().setFillColorActive(bActive);
2635 [ + + ]: 8856 : if(bActive)
2636 [ + - ][ + - ]: 900 : rPropertyHolders.Current().setFillColor(pA->GetColor().getBColor());
2637 : :
2638 : 8856 : break;
2639 : : }
2640 : : case META_TEXTCOLOR_ACTION :
2641 : : {
2642 : : /** SIMPLE, DONE */
2643 : 2992 : const MetaTextColorAction* pA = (const MetaTextColorAction*)pAction;
2644 : 2992 : const bool bActivate(COL_TRANSPARENT != pA->GetColor().GetColor());
2645 : :
2646 : 2992 : rPropertyHolders.Current().setTextColorActive(bActivate);
2647 [ + - ][ + - ]: 2992 : rPropertyHolders.Current().setTextColor(pA->GetColor().getBColor());
2648 : :
2649 : 2992 : break;
2650 : : }
2651 : : case META_TEXTFILLCOLOR_ACTION :
2652 : : {
2653 : : /** SIMPLE, DONE */
2654 : 2992 : const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*)pAction;
2655 : 2992 : const bool bWithColorArgument(pA->IsSetting());
2656 : :
2657 [ - + ]: 2992 : if(bWithColorArgument)
2658 : : {
2659 : : // emulate OutputDevice::SetTextFillColor(...) WITH argument
2660 : 0 : const Color& rFontFillColor = pA->GetColor();
2661 [ # # ][ # # ]: 0 : rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
2662 : 0 : rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor());
2663 : : }
2664 : : else
2665 : : {
2666 : : // emulate SetFillColor() <- NO argument (!)
2667 : 2992 : rPropertyHolders.Current().setTextFillColorActive(false);
2668 : : }
2669 : :
2670 : 2992 : break;
2671 : : }
2672 : : case META_TEXTALIGN_ACTION :
2673 : : {
2674 : : /** SIMPLE, DONE */
2675 : 2992 : const MetaTextAlignAction* pA = (const MetaTextAlignAction*)pAction;
2676 : 2992 : const TextAlign aNewTextAlign = pA->GetTextAlign();
2677 : :
2678 : : // TextAlign is applied to the current font (as in
2679 : : // OutputDevice::SetTextAlign which would be used when
2680 : : // playing the Metafile)
2681 [ + - ]: 2992 : if(rPropertyHolders.Current().getFont().GetAlign() != aNewTextAlign)
2682 : : {
2683 [ + - ][ + - ]: 2992 : Font aNewFont(rPropertyHolders.Current().getFont());
2684 [ + - ]: 2992 : aNewFont.SetAlign(aNewTextAlign);
2685 [ + - ][ + - ]: 2992 : rPropertyHolders.Current().setFont(aNewFont);
[ + - ]
2686 : : }
2687 : :
2688 : 2992 : break;
2689 : : }
2690 : : case META_MAPMODE_ACTION :
2691 : : {
2692 : : /** CHECKED, WORKS WELL */
2693 : : // the most necessary MapMode to be interpreted is MAP_RELATIVE,
2694 : : // but also the others may occur. Even not yet supported ones
2695 : : // may need to be added here later
2696 : 0 : const MetaMapModeAction* pA = (const MetaMapModeAction*)pAction;
2697 : 0 : const MapMode& rMapMode = pA->GetMapMode();
2698 [ # # ]: 0 : basegfx::B2DHomMatrix aMapping;
2699 : :
2700 [ # # ]: 0 : if(MAP_RELATIVE == rMapMode.GetMapUnit())
2701 : : {
2702 [ # # ][ # # ]: 0 : aMapping = getTransformFromMapMode(rMapMode);
[ # # ]
2703 : : }
2704 : : else
2705 : : {
2706 [ # # # ]: 0 : switch(rMapMode.GetMapUnit())
2707 : : {
2708 : : case MAP_100TH_MM :
2709 : : {
2710 [ # # ][ # # ]: 0 : if(MAP_TWIP == rPropertyHolders.Current().getMapUnit())
2711 : : {
2712 : : // MAP_TWIP -> MAP_100TH_MM
2713 : 0 : const double fTwipTo100thMm(127.0 / 72.0);
2714 [ # # ]: 0 : aMapping.scale(fTwipTo100thMm, fTwipTo100thMm);
2715 : : }
2716 : 0 : break;
2717 : : }
2718 : : case MAP_TWIP :
2719 : : {
2720 [ # # ][ # # ]: 0 : if(MAP_100TH_MM == rPropertyHolders.Current().getMapUnit())
2721 : : {
2722 : : // MAP_100TH_MM -> MAP_TWIP
2723 : 0 : const double f100thMmToTwip(72.0 / 127.0);
2724 [ # # ]: 0 : aMapping.scale(f100thMmToTwip, f100thMmToTwip);
2725 : : }
2726 : 0 : break;
2727 : : }
2728 : : default :
2729 : : {
2730 : : OSL_FAIL("interpretMetafile: META_MAPMODE_ACTION with unsupported MapUnit (!)");
2731 : 0 : break;
2732 : : }
2733 : : }
2734 : :
2735 [ # # ][ # # ]: 0 : aMapping = getTransformFromMapMode(rMapMode) * aMapping;
[ # # ][ # # ]
[ # # ]
2736 [ # # ]: 0 : rPropertyHolders.Current().setMapUnit(rMapMode.GetMapUnit());
2737 : : }
2738 : :
2739 [ # # ][ # # ]: 0 : if(!aMapping.isIdentity())
2740 : : {
2741 [ # # ][ # # ]: 0 : aMapping = aMapping * rPropertyHolders.Current().getTransformation();
[ # # ][ # # ]
2742 [ # # ][ # # ]: 0 : rPropertyHolders.Current().setTransformation(aMapping);
2743 : : }
2744 : :
2745 [ # # ]: 0 : break;
2746 : : }
2747 : : case META_FONT_ACTION :
2748 : : {
2749 : : /** SIMPLE, DONE */
2750 : 2992 : const MetaFontAction* pA = (const MetaFontAction*)pAction;
2751 [ + - ][ + - ]: 2992 : rPropertyHolders.Current().setFont(pA->GetFont());
2752 [ + - ]: 2992 : Size aFontSize(pA->GetFont().GetSize());
2753 : :
2754 [ - + ]: 2992 : if(0 == aFontSize.Height())
2755 : : {
2756 : : // this should not happen but i got Metafiles where this was the
2757 : : // case. A height needs to be guessed (similar to OutputDevice::ImplNewFont())
2758 [ # # ]: 0 : Font aCorrectedFont(pA->GetFont());
2759 : :
2760 : : // guess 16 pixel (as in VCL)
2761 : 0 : aFontSize = Size(0, 16);
2762 : :
2763 : : // convert to target MapUnit if not pixels
2764 [ # # ]: 0 : aFontSize = Application::GetDefaultDevice()->LogicToLogic(
2765 [ # # ][ # # ]: 0 : aFontSize, MAP_PIXEL, rPropertyHolders.Current().getMapUnit());
[ # # ][ # # ]
[ # # ][ # # ]
2766 : :
2767 [ # # ]: 0 : aCorrectedFont.SetSize(aFontSize);
2768 [ # # ][ # # ]: 0 : rPropertyHolders.Current().setFont(aCorrectedFont);
[ # # ]
2769 : : }
2770 : :
2771 : : // older Metafiles have no META_TEXTCOLOR_ACTION which defines
2772 : : // the FontColor now, so use the Font's color when not transparent
2773 [ + - ]: 2992 : const Color& rFontColor = pA->GetFont().GetColor();
2774 : 2992 : const bool bActivate(COL_TRANSPARENT != rFontColor.GetColor());
2775 : :
2776 [ - + ]: 2992 : if(bActivate)
2777 : : {
2778 [ # # ][ # # ]: 0 : rPropertyHolders.Current().setTextColor(rFontColor.getBColor());
2779 : : }
2780 : :
2781 : : // caution: do NOT decativate here on transparet, see
2782 : : // OutputDevice::SetFont(..) for more info
2783 : : // rPropertyHolders.Current().setTextColorActive(bActivate);
2784 : :
2785 : : // for fill color emulate a MetaTextFillColorAction with !transparent as bool,
2786 : : // see OutputDevice::SetFont(..) the if(mpMetaFile) case
2787 [ - + ]: 2992 : if(bActivate)
2788 : : {
2789 [ # # ]: 0 : const Color& rFontFillColor = pA->GetFont().GetFillColor();
2790 [ # # ][ # # ]: 0 : rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
2791 [ # # ]: 0 : rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor());
2792 : : }
2793 : : else
2794 : : {
2795 [ + - ]: 2992 : rPropertyHolders.Current().setTextFillColorActive(false);
2796 : : }
2797 : :
2798 : : break;
2799 : : }
2800 : : case META_PUSH_ACTION :
2801 : : {
2802 : : /** CHECKED, WORKS WELL */
2803 : 195 : const MetaPushAction* pA = (const MetaPushAction*)pAction;
2804 : 195 : rPropertyHolders.Push(pA->GetFlags());
2805 : :
2806 : 195 : break;
2807 : : }
2808 : : case META_POP_ACTION :
2809 : : {
2810 : : /** CHECKED, WORKS WELL */
2811 : 195 : const bool bRegionMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_CLIPREGION);
2812 : 195 : const bool bRasterOpMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_RASTEROP);
2813 : :
2814 [ + - ][ + - ]: 195 : if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
[ + - ]
2815 : : {
2816 : : // end evtl. clipping
2817 [ + - ]: 195 : const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
2818 : :
2819 [ + - ][ + - ]: 195 : HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
2820 : : }
2821 : :
2822 [ + + ][ - + ]: 195 : if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
[ - + ]
2823 : : {
2824 : : // end evtl. RasterOp
2825 : 0 : HandleNewRasterOp(ROP_OVERPAINT, rTargetHolders, rPropertyHolders);
2826 : : }
2827 : :
2828 : 195 : rPropertyHolders.Pop();
2829 : :
2830 [ - + ][ - + ]: 195 : if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
[ + + ]
2831 : : {
2832 : : // start evtl. RasterOp
2833 : 0 : HandleNewRasterOp(rPropertyHolders.Current().getRasterOp(), rTargetHolders, rPropertyHolders);
2834 : : }
2835 : :
2836 [ + - ][ + + ]: 195 : if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
[ + + ]
2837 : : {
2838 : : // start evtl. clipping
2839 : : HandleNewClipRegion(
2840 : 130 : rPropertyHolders.Current().getClipPolyPolygon(), rTargetHolders, rPropertyHolders);
2841 : : }
2842 : :
2843 : 195 : break;
2844 : : }
2845 : : case META_RASTEROP_ACTION :
2846 : : {
2847 : : /** CHECKED, WORKS WELL */
2848 : 0 : const MetaRasterOpAction* pA = (const MetaRasterOpAction*)pAction;
2849 : 0 : const RasterOp aRasterOp = pA->GetRasterOp();
2850 : :
2851 : 0 : HandleNewRasterOp(aRasterOp, rTargetHolders, rPropertyHolders);
2852 : :
2853 : 0 : break;
2854 : : }
2855 : : case META_TRANSPARENT_ACTION :
2856 : : {
2857 : : /** CHECKED, WORKS WELL */
2858 : 0 : const MetaTransparentAction* pA = (const MetaTransparentAction*)pAction;
2859 [ # # ]: 0 : const basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
2860 : :
2861 [ # # ][ # # ]: 0 : if(aOutline.count())
2862 : : {
2863 : 0 : const sal_uInt16 nTransparence(pA->GetTransparence());
2864 : :
2865 [ # # ]: 0 : if(0 == nTransparence)
2866 : : {
2867 : : // not transparent
2868 [ # # ][ # # ]: 0 : createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ]
2869 : : }
2870 [ # # ]: 0 : else if(nTransparence >= 100)
2871 : : {
2872 : : // fully or more than transparent
2873 : : }
2874 : : else
2875 : : {
2876 : : // transparent. Create new target
2877 [ # # ]: 0 : rTargetHolders.Push();
2878 : :
2879 : : // create primitives there and get them
2880 [ # # ][ # # ]: 0 : createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
[ # # ]
2881 : : const drawinglayer::primitive2d::Primitive2DSequence aSubContent(
2882 [ # # ][ # # ]: 0 : rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()));
[ # # ]
2883 : :
2884 : : // back to old target
2885 [ # # ]: 0 : rTargetHolders.Pop();
2886 : :
2887 [ # # ]: 0 : if(aSubContent.hasElements())
2888 : : {
2889 [ # # ]: 0 : rTargetHolders.Current().append(
2890 : : new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
2891 : : aSubContent,
2892 [ # # ][ # # ]: 0 : nTransparence * 0.01));
2893 [ # # ]: 0 : }
2894 : : }
2895 : : }
2896 : :
2897 [ # # ]: 0 : break;
2898 : : }
2899 : : case META_EPS_ACTION :
2900 : : {
2901 : : /** CHECKED, WORKS WELL */
2902 : : // To support this action, i have added a EpsPrimitive2D which will
2903 : : // by default decompose to the Metafile replacement data. To support
2904 : : // this EPS on screen, the renderer visualizing this has to support
2905 : : // that primitive and visualize the Eps file (e.g. printing)
2906 : 0 : const MetaEPSAction* pA = (const MetaEPSAction*)pAction;
2907 [ # # ]: 0 : const Rectangle aRectangle(pA->GetPoint(), pA->GetSize());
2908 : :
2909 [ # # ][ # # ]: 0 : if(!aRectangle.IsEmpty())
2910 : : {
2911 : : // create object transform
2912 [ # # ]: 0 : basegfx::B2DHomMatrix aObjectTransform;
2913 : :
2914 [ # # ][ # # ]: 0 : aObjectTransform.set(0, 0, aRectangle.GetWidth());
2915 [ # # ][ # # ]: 0 : aObjectTransform.set(1, 1, aRectangle.GetHeight());
2916 [ # # ]: 0 : aObjectTransform.set(0, 2, aRectangle.Left());
2917 [ # # ]: 0 : aObjectTransform.set(1, 2, aRectangle.Top());
2918 : :
2919 : : // add current transformation
2920 [ # # ][ # # ]: 0 : aObjectTransform = rPropertyHolders.Current().getTransformation() * aObjectTransform;
[ # # ][ # # ]
2921 : :
2922 : : // embed using EpsPrimitive
2923 [ # # ]: 0 : rTargetHolders.Current().append(
2924 : : new drawinglayer::primitive2d::EpsPrimitive2D(
2925 : : aObjectTransform,
2926 : : pA->GetLink(),
2927 [ # # ][ # # ]: 0 : pA->GetSubstitute()));
[ # # ]
2928 : : }
2929 : :
2930 : : break;
2931 : : }
2932 : : case META_REFPOINT_ACTION :
2933 : : {
2934 : : /** SIMPLE, DONE */
2935 : : // only used for hatch and line pattern offsets, pretty much no longer
2936 : : // supported today
2937 : : // const MetaRefPointAction* pA = (const MetaRefPointAction*)pAction;
2938 : 0 : break;
2939 : : }
2940 : : case META_TEXTLINECOLOR_ACTION :
2941 : : {
2942 : : /** SIMPLE, DONE */
2943 : 0 : const MetaTextLineColorAction* pA = (const MetaTextLineColorAction*)pAction;
2944 : 0 : const bool bActive(pA->IsSetting());
2945 : :
2946 : 0 : rPropertyHolders.Current().setTextLineColorActive(bActive);
2947 [ # # ]: 0 : if(bActive)
2948 [ # # ][ # # ]: 0 : rPropertyHolders.Current().setTextLineColor(pA->GetColor().getBColor());
2949 : :
2950 : 0 : break;
2951 : : }
2952 : : case META_TEXTLINE_ACTION :
2953 : : {
2954 : : /** CHECKED, WORKS WELL */
2955 : : // actually creates overline, underline and strikeouts, so
2956 : : // these should be isolated from TextDecoratedPortionPrimitive2D
2957 : : // to own primitives. Done, available now.
2958 : : //
2959 : : // This Metaaction seems not to be used (was not used in any
2960 : : // checked files). It's used in combination with the current
2961 : : // Font.
2962 : 0 : const MetaTextLineAction* pA = (const MetaTextLineAction*)pAction;
2963 : :
2964 : : proccessMetaTextLineAction(
2965 : : *pA,
2966 : 0 : rTargetHolders.Current(),
2967 : 0 : rPropertyHolders.Current());
2968 : :
2969 : 0 : break;
2970 : : }
2971 : : case META_FLOATTRANSPARENT_ACTION :
2972 : : {
2973 : : /** CHECKED, WORKS WELL */
2974 : 0 : const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*)pAction;
2975 [ # # ]: 0 : const Rectangle aTargetRectangle(pA->GetPoint(), pA->GetSize());
2976 : :
2977 [ # # ][ # # ]: 0 : if(!aTargetRectangle.IsEmpty())
2978 : : {
2979 : 0 : const GDIMetaFile& rContent = pA->GetGDIMetaFile();
2980 : :
2981 [ # # ][ # # ]: 0 : if(rContent.GetActionSize())
2982 : : {
2983 : : // create the sub-content with no embedding specific to the
2984 : : // sub-metafile, this seems not to be used.
2985 [ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence xSubContent;
2986 : : {
2987 [ # # ]: 0 : rTargetHolders.Push();
2988 : : // #i# for sub-Mteafile contents, do start with new, default render state
2989 [ # # ]: 0 : rPropertyHolders.PushDefault();
2990 [ # # ]: 0 : interpretMetafile(rContent, rTargetHolders, rPropertyHolders, rViewInformation);
2991 [ # # ][ # # ]: 0 : xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
[ # # ][ # # ]
[ # # ]
2992 [ # # ]: 0 : rPropertyHolders.Pop();
2993 [ # # ]: 0 : rTargetHolders.Pop();
2994 : : }
2995 : :
2996 [ # # ]: 0 : if(xSubContent.hasElements())
2997 : : {
2998 : : // check if gradient is a real gradient
2999 : 0 : const Gradient& rGradient = pA->GetGradient();
3000 [ # # ]: 0 : const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
3001 : :
3002 [ # # ][ # # ]: 0 : if(aAttribute.getStartColor() == aAttribute.getEndColor())
[ # # ]
3003 : : {
3004 : : // not really a gradient; create UnifiedTransparencePrimitive2D
3005 [ # # ]: 0 : rTargetHolders.Current().append(
3006 : : new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
3007 : : xSubContent,
3008 [ # # ][ # # ]: 0 : aAttribute.getStartColor().luminance()));
[ # # ]
3009 : : }
3010 : : else
3011 : : {
3012 : : // really a gradient. Create gradient sub-content (with correct scaling)
3013 : : basegfx::B2DRange aRange(
3014 : 0 : aTargetRectangle.Left(), aTargetRectangle.Top(),
3015 [ # # ]: 0 : aTargetRectangle.Right(), aTargetRectangle.Bottom());
3016 [ # # ][ # # ]: 0 : aRange.transform(rPropertyHolders.Current().getTransformation());
3017 : :
3018 : : // prepare gradient for transparent content
3019 : : const drawinglayer::primitive2d::Primitive2DReference xTransparence(
3020 : : new drawinglayer::primitive2d::FillGradientPrimitive2D(
3021 : : aRange,
3022 [ # # ][ # # ]: 0 : aAttribute));
[ # # ]
3023 : :
3024 : : // create transparence primitive
3025 [ # # ]: 0 : rTargetHolders.Current().append(
3026 : : new drawinglayer::primitive2d::TransparencePrimitive2D(
3027 : : xSubContent,
3028 [ # # ][ # # ]: 0 : drawinglayer::primitive2d::Primitive2DSequence(&xTransparence, 1)));
[ # # ][ # # ]
3029 [ # # ]: 0 : }
3030 [ # # ]: 0 : }
3031 : : }
3032 : : }
3033 : :
3034 : : break;
3035 : : }
3036 : : case META_GRADIENTEX_ACTION :
3037 : : {
3038 : : /** SIMPLE, DONE */
3039 : : // This is only a data holder which is interpreted inside comment actions,
3040 : : // see META_COMMENT_ACTION for more info
3041 : : // const MetaGradientExAction* pA = (const MetaGradientExAction*)pAction;
3042 : 0 : break;
3043 : : }
3044 : : case META_LAYOUTMODE_ACTION :
3045 : : {
3046 : : /** SIMPLE, DONE */
3047 : 65 : const MetaLayoutModeAction* pA = (const MetaLayoutModeAction*)pAction;
3048 : 65 : rPropertyHolders.Current().setLayoutMode(pA->GetLayoutMode());
3049 : 65 : break;
3050 : : }
3051 : : case META_TEXTLANGUAGE_ACTION :
3052 : : {
3053 : : /** SIMPLE, DONE */
3054 : 65 : const MetaTextLanguageAction* pA = (const MetaTextLanguageAction*)pAction;
3055 : 65 : rPropertyHolders.Current().setLanguageType(pA->GetTextLanguage());
3056 : 65 : break;
3057 : : }
3058 : : case META_OVERLINECOLOR_ACTION :
3059 : : {
3060 : : /** SIMPLE, DONE */
3061 : 0 : const MetaOverlineColorAction* pA = (const MetaOverlineColorAction*)pAction;
3062 : 0 : const bool bActive(pA->IsSetting());
3063 : :
3064 : 0 : rPropertyHolders.Current().setOverlineColorActive(bActive);
3065 [ # # ]: 0 : if(bActive)
3066 [ # # ][ # # ]: 0 : rPropertyHolders.Current().setOverlineColor(pA->GetColor().getBColor());
3067 : :
3068 : 0 : break;
3069 : : }
3070 : : case META_RENDERGRAPHIC_ACTION :
3071 : : {
3072 : 0 : const MetaRenderGraphicAction* pA = (const MetaRenderGraphicAction*)pAction;
3073 [ # # ]: 0 : const Rectangle aRectangle(pA->GetPoint(), pA->GetSize());
3074 : :
3075 [ # # ][ # # ]: 0 : if(!aRectangle.IsEmpty())
3076 : : {
3077 : : // create object transform
3078 [ # # ]: 0 : basegfx::B2DHomMatrix aObjectTransform;
3079 : :
3080 [ # # ][ # # ]: 0 : aObjectTransform.set(0, 0, aRectangle.GetWidth());
3081 [ # # ][ # # ]: 0 : aObjectTransform.set(1, 1, aRectangle.GetHeight());
3082 [ # # ]: 0 : aObjectTransform.set(0, 2, aRectangle.Left());
3083 [ # # ]: 0 : aObjectTransform.set(1, 2, aRectangle.Top());
3084 : :
3085 : : // add current transformation
3086 [ # # ][ # # ]: 0 : aObjectTransform = rPropertyHolders.Current().getTransformation() * aObjectTransform;
[ # # ][ # # ]
3087 : :
3088 : : // embed using EpsPrimitive
3089 [ # # ]: 0 : rTargetHolders.Current().append(
3090 : : new drawinglayer::primitive2d::RenderGraphicPrimitive2D(
3091 : : pA->GetRenderGraphic(),
3092 [ # # ][ # # ]: 0 : aObjectTransform ) );
[ # # ]
3093 : : }
3094 : :
3095 : : break;
3096 : : }
3097 : : case META_COMMENT_ACTION :
3098 : : {
3099 : : /** CHECKED, WORKS WELL */
3100 : : // I already implemented
3101 : : // XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END
3102 : : // XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END,
3103 : : // but opted to remove these again; it works well without them
3104 : : // and makes the code less dependent from those Metafile Add-Ons
3105 : 48127 : const MetaCommentAction* pA = (const MetaCommentAction*)pAction;
3106 : :
3107 [ - + ]: 48127 : if (pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_BEGIN")))
3108 : : {
3109 : : // XGRAD_SEQ_BEGIN, XGRAD_SEQ_END should be supported since the
3110 : : // pure recorded paint of the gradients uses the XOR paint functionality
3111 : : // ('trick'). This is (and will be) broblematic with AntAliasing, so it's
3112 : : // better to use this info
3113 : 0 : const MetaGradientExAction* pMetaGradientExAction = 0;
3114 : 0 : bool bDone(false);
3115 : 0 : sal_uInt32 b(nAction + 1);
3116 : :
3117 [ # # ][ # # ]: 0 : for(; !bDone && b < nCount; b++)
[ # # ]
3118 : : {
3119 : 0 : pAction = rMetaFile.GetAction(b);
3120 : :
3121 [ # # ]: 0 : if(META_GRADIENTEX_ACTION == pAction->GetType())
3122 : : {
3123 : 0 : pMetaGradientExAction = (const MetaGradientExAction*)pAction;
3124 : : }
3125 [ # # ]: 0 : else if(META_COMMENT_ACTION == pAction->GetType())
3126 : : {
3127 [ # # ]: 0 : if (((const MetaCommentAction*)pAction)->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_END")))
3128 : : {
3129 : 0 : bDone = true;
3130 : : }
3131 : : }
3132 : : }
3133 : :
3134 [ # # ][ # # ]: 0 : if(bDone && pMetaGradientExAction)
3135 : : {
3136 : : // consume actions and skip forward
3137 : 0 : nAction = b - 1;
3138 : :
3139 : : // get geometry data
3140 [ # # ]: 0 : basegfx::B2DPolyPolygon aPolyPolygon(pMetaGradientExAction->GetPolyPolygon().getB2DPolyPolygon());
3141 : :
3142 [ # # ][ # # ]: 0 : if(aPolyPolygon.count())
3143 : : {
3144 : : // transform geometry
3145 [ # # ][ # # ]: 0 : aPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
3146 : :
3147 : : // get and check if gradient is a real gradient
3148 : 0 : const Gradient& rGradient = pMetaGradientExAction->GetGradient();
3149 [ # # ]: 0 : const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
3150 : :
3151 [ # # ][ # # ]: 0 : if(aAttribute.getStartColor() == aAttribute.getEndColor())
[ # # ]
3152 : : {
3153 : : // not really a gradient
3154 [ # # ]: 0 : rTargetHolders.Current().append(
3155 : : new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
3156 : : aPolyPolygon,
3157 [ # # ][ # # ]: 0 : aAttribute.getStartColor()));
[ # # ]
3158 : : }
3159 : : else
3160 : : {
3161 : : // really a gradient
3162 [ # # ]: 0 : rTargetHolders.Current().append(
3163 : : new drawinglayer::primitive2d::PolyPolygonGradientPrimitive2D(
3164 : : aPolyPolygon,
3165 [ # # ][ # # ]: 0 : aAttribute));
3166 [ # # ]: 0 : }
3167 [ # # ]: 0 : }
3168 : : }
3169 : : }
3170 : :
3171 : 48127 : break;
3172 : : }
3173 : : default:
3174 : : {
3175 : : OSL_FAIL("Unknown MetaFile Action (!)");
3176 : 0 : break;
3177 : : }
3178 : : }
3179 : : }
3180 : 65 : }
3181 : : } // end of anonymous namespace
3182 : :
3183 : : //////////////////////////////////////////////////////////////////////////////
3184 : :
3185 : : namespace drawinglayer
3186 : : {
3187 : : namespace primitive2d
3188 : : {
3189 : 65 : Primitive2DSequence MetafilePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
3190 : : {
3191 : : // prepare target and porperties; each will have one default entry
3192 [ + - ]: 65 : TargetHolders aTargetHolders;
3193 [ + - ]: 65 : PropertyHolders aPropertyHolders;
3194 : :
3195 : : // set target MapUnit at Properties
3196 [ + - ]: 65 : aPropertyHolders.Current().setMapUnit(getMetaFile().GetPrefMapMode().GetMapUnit());
3197 : :
3198 : : // interpret the Metafile
3199 [ + - ]: 65 : interpretMetafile(getMetaFile(), aTargetHolders, aPropertyHolders, rViewInformation);
3200 : :
3201 : : // get the content. There should be ony one target, as in the start condition,
3202 : : // but iterating will be the right thing to do when some push/pop is not closed
3203 [ + - ]: 65 : Primitive2DSequence xRetval;
3204 : :
3205 [ - + ]: 65 : while(aTargetHolders.size() > 1)
3206 : : {
3207 : : appendPrimitive2DSequenceToPrimitive2DSequence(xRetval,
3208 [ # # ][ # # ]: 0 : aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
[ # # ][ # # ]
[ # # ]
3209 [ # # ]: 0 : aTargetHolders.Pop();
3210 : : }
3211 : :
3212 : : appendPrimitive2DSequenceToPrimitive2DSequence(xRetval,
3213 [ + - ][ + - ]: 65 : aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
[ + - ][ + - ]
[ + - ]
3214 : :
3215 [ + + ]: 65 : if(xRetval.hasElements())
3216 : : {
3217 : : // get target size
3218 [ + - ]: 64 : const Rectangle aMtfTarget(getMetaFile().GetPrefMapMode().GetOrigin(), getMetaFile().GetPrefSize());
3219 : :
3220 : : // create transformation
3221 [ + - ]: 64 : basegfx::B2DHomMatrix aAdaptedTransform;
3222 : :
3223 [ + - ]: 64 : aAdaptedTransform.translate(-aMtfTarget.Left(), -aMtfTarget.Top());
3224 : : aAdaptedTransform.scale(
3225 : 128 : aMtfTarget.getWidth() ? 1.0 / aMtfTarget.getWidth() : 1.0,
3226 [ + - ][ + - ]: 192 : aMtfTarget.getHeight() ? 1.0 / aMtfTarget.getHeight() : 1.0);
[ + - ]
3227 [ + - ][ + - ]: 64 : aAdaptedTransform = getTransform() * aAdaptedTransform;
[ + - ]
3228 : :
3229 : : // embed to target transformation
3230 : : const Primitive2DReference aEmbeddedTransform(
3231 : : new TransformPrimitive2D(
3232 : : aAdaptedTransform,
3233 [ + - ][ + - ]: 64 : xRetval));
[ + - ]
3234 : :
3235 [ + - ][ + - ]: 64 : xRetval = Primitive2DSequence(&aEmbeddedTransform, 1);
[ + - ][ + - ]
3236 : : }
3237 : :
3238 [ + - ][ + - ]: 65 : return xRetval;
3239 : : }
3240 : :
3241 : 65 : MetafilePrimitive2D::MetafilePrimitive2D(
3242 : : const basegfx::B2DHomMatrix& rMetaFileTransform,
3243 : : const GDIMetaFile& rMetaFile)
3244 : : : BufferedDecompositionPrimitive2D(),
3245 : : maMetaFileTransform(rMetaFileTransform),
3246 [ + - ][ + - ]: 65 : maMetaFile(rMetaFile)
3247 : : {
3248 : 65 : }
3249 : :
3250 : 0 : bool MetafilePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
3251 : : {
3252 [ # # ]: 0 : if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
3253 : : {
3254 : 0 : const MetafilePrimitive2D& rCompare = (MetafilePrimitive2D&)rPrimitive;
3255 : :
3256 : 0 : return (getTransform() == rCompare.getTransform()
3257 [ # # ][ # # ]: 0 : && getMetaFile() == rCompare.getMetaFile());
3258 : : }
3259 : :
3260 : 0 : return false;
3261 : : }
3262 : :
3263 : 0 : basegfx::B2DRange MetafilePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
3264 : : {
3265 : : // use own implementation to quickly answer the getB2DRange question. The
3266 : : // MetafilePrimitive2D assumes that all geometry is inside of the shape. If
3267 : : // this is not the case (i have already seen some wrong Metafiles) it should
3268 : : // be embedded to a MaskPrimitive2D
3269 : 0 : basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
3270 : 0 : aRetval.transform(getTransform());
3271 : :
3272 : 0 : return aRetval;
3273 : : }
3274 : :
3275 : : // provide unique ID
3276 : 67 : ImplPrimitrive2DIDBlock(MetafilePrimitive2D, PRIMITIVE2D_ID_METAFILEPRIMITIVE2D)
3277 : :
3278 : : } // end of namespace primitive2d
3279 : : } // end of namespace drawinglayer
3280 : :
3281 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|