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