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