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