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