Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / cppcanvas / source / mtfrenderer / emfplus.cxx
blobc6c719b3d68b47efe7246f1994e413ca530c67e4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/stream.hxx>
21 #include <vcl/metaact.hxx>
22 #include <vcl/graphicfilter.hxx>
23 #include <basegfx/tools/canvastools.hxx>
24 #include <basegfx/tools/gradienttools.hxx>
25 #include <basegfx/tools/tools.hxx>
26 #include <basegfx/numeric/ftools.hxx>
27 #include <basegfx/point/b2dpoint.hxx>
28 #include <basegfx/vector/b2dsize.hxx>
29 #include <basegfx/range/b2drange.hxx>
30 #include <basegfx/range/b2drectangle.hxx>
31 #include <basegfx/polygon/b2dlinegeometry.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
34 #include <basegfx/polygon/b2dpolypolygon.hxx>
35 #include <basegfx/polygon/b2dpolypolygontools.hxx>
36 #include <vcl/canvastools.hxx>
37 #include <rtl/ustring.hxx>
38 #include <sal/alloca.h>
40 #include <com/sun/star/rendering/PathCapType.hpp>
41 #include <com/sun/star/rendering/PathJoinType.hpp>
42 #include <com/sun/star/rendering/TexturingMode.hpp>
43 #include <com/sun/star/rendering/XCanvas.hpp>
45 #include <bitmapaction.hxx>
46 #include <implrenderer.hxx>
47 #include <outdevstate.hxx>
48 #include <polypolyaction.hxx>
49 #include <textaction.hxx>
50 #include <stdio.h>
52 #define EmfPlusRecordTypeHeader 16385
53 #define EmfPlusRecordTypeEndOfFile 16386
54 #define EmfPlusRecordTypeGetDC 16388
55 #define EmfPlusRecordTypeObject 16392
56 #define EmfPlusRecordTypeFillRects 16394
57 #define EmfPlusRecordTypeFillPolygon 16396
58 #define EmfPlusRecordTypeDrawLines 16397
59 #define EmfPlusRecordTypeFillEllipse 16398
60 #define EmfPlusRecordTypeDrawEllipse 16399
61 #define EmfPlusRecordTypeFillPie 16400
62 #define EmfPlusRecordTypeFillPath 16404
63 #define EmfPlusRecordTypeDrawPath 16405
64 #define EmfPlusRecordTypeDrawImage 16410
65 #define EmfPlusRecordTypeDrawImagePoints 16411
66 #define EmfPlusRecordTypeDrawString 16412
67 #define EmfPlusRecordTypeSetRenderingOrigin 16413
68 #define EmfPlusRecordTypeSetAntiAliasMode 16414
69 #define EmfPlusRecordTypeSetTextRenderingHint 16415
70 #define EmfPlusRecordTypeSetInterpolationMode 16417
71 #define EmfPlusRecordTypeSetPixelOffsetMode 16418
72 #define EmfPlusRecordTypeSetCompositingQuality 16420
73 #define EmfPlusRecordTypeSave 16421
74 #define EmfPlusRecordTypeRestore 16422
75 #define EmfPlusRecordTypeBeginContainerNoParams 16424
76 #define EmfPlusRecordTypeEndContainer 16425
77 #define EmfPlusRecordTypeSetWorldTransform 16426
78 #define EmfPlusRecordTypeResetWorldTransform 16427
79 #define EmfPlusRecordTypeMultiplyWorldTransform 16428
80 #define EmfPlusRecordTypeSetPageTransform 16432
81 #define EmfPlusRecordTypeSetClipRect 16434
82 #define EmfPlusRecordTypeSetClipPath 16435
83 #define EmfPlusRecordTypeSetClipRegion 16436
84 #define EmfPlusRecordTypeDrawDriverString 16438
86 #define EmfPlusObjectTypeBrush 0x100
87 #define EmfPlusObjectTypePen 0x200
88 #define EmfPlusObjectTypePath 0x300
89 #define EmfPlusObjectTypeRegion 0x400
90 #define EmfPlusObjectTypeImage 0x500
91 #define EmfPlusObjectTypeFont 0x600
93 #define EmfPlusRegionInitialStateInfinite 0x10000003
95 const sal_Int32 EmfPlusLineStyleSolid = 0x00000000;
96 const sal_Int32 EmfPlusLineStyleDash = 0x00000001;
97 const sal_Int32 EmfPlusLineStyleDot = 0x00000002;
98 const sal_Int32 EmfPlusLineStyleDashDot = 0x00000003;
99 const sal_Int32 EmfPlusLineStyleDashDotDot = 0x00000004;
100 const sal_Int32 EmfPlusLineStyleCustom = 0x00000005;
102 const sal_uInt32 EmfPlusCustomLineCapDataTypeDefault = 0x00000000;
103 const sal_uInt32 EmfPlusCustomLineCapDataTypeAdjustableArrow = 0x00000001;
105 const sal_uInt32 EmfPlusCustomLineCapDataFillPath = 0x00000001;
106 const sal_uInt32 EmfPlusCustomLineCapDataLinePath = 0x00000002;
108 const sal_uInt32 EmfPlusLineCapTypeSquare = 0x00000001;
109 const sal_uInt32 EmfPlusLineCapTypeRound = 0x00000002;
111 const sal_uInt32 EmfPlusLineJoinTypeMiter = 0x00000000;
112 const sal_uInt32 EmfPlusLineJoinTypeBevel = 0x00000001;
113 const sal_uInt32 EmfPlusLineJoinTypeRound = 0x00000002;
114 const sal_uInt32 EmfPlusLineJoinTypeMiterClipped = 0x00000003;
116 using namespace ::com::sun::star;
117 using namespace ::basegfx;
119 namespace cppcanvas
121 namespace internal
124 #if OSL_DEBUG_LEVEL > 1
125 void dumpWords (SvStream& s, int i)
127 sal_uInt32 pos = s.Tell ();
128 sal_Int16 data;
129 SAL_INFO ("cppcanvas.emf", "EMF+ dumping words");
130 for (; i > 0; i --) {
131 s >> data;
132 SAL_INFO ("cppcanvas.emf", "EMF+\tdata: " << std::hex << data << std::dec);
134 SAL_INFO ("cppcanvas.emf", "EMF+ end dumping words");
135 s.Seek (pos);
137 #endif
139 struct EMFPPath : public EMFPObject
141 ::basegfx::B2DPolyPolygon aPolygon;
142 sal_Int32 nPoints;
143 float* pPoints;
144 sal_uInt8* pPointTypes;
146 public:
147 EMFPPath (sal_Int32 _nPoints, bool bLines = false)
149 if( _nPoints<0 || sal_uInt32(_nPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
150 _nPoints = SAL_MAX_INT32/(2*sizeof(float));
151 nPoints = _nPoints;
152 pPoints = new float [nPoints*2];
153 if (!bLines)
154 pPointTypes = new sal_uInt8 [_nPoints];
155 else
156 pPointTypes = NULL;
159 ~EMFPPath ()
161 delete [] pPoints;
162 delete [] pPointTypes;
165 // TODO: remove rR argument when debug code is not longer needed
166 void Read (SvStream& s, sal_uInt32 pathFlags, ImplRenderer& rR)
168 for (int i = 0; i < nPoints; i ++) {
169 if (pathFlags & 0x4000) {
170 // points are stored in short 16bit integer format
171 sal_uInt16 x, y;
173 s >> x >> y;
174 SAL_INFO ("cppcanvas.emf", "EMF+\tpoint [x,y]: " << x << "," << y);
175 pPoints [i*2] = x;
176 pPoints [i*2 + 1] = y;
177 } else {
178 // points are stored in Single (float) format
179 s >> pPoints [i*2] >> pPoints [i*2 + 1];
180 SAL_INFO ("cppcanvas.emf", "EMF+\tpoint [x,y]: " << pPoints [i*2] << "," << pPoints [i*2 + 1]);
184 if (pPointTypes)
185 for (int i = 0; i < nPoints; i ++) {
186 s >> pPointTypes [i];
187 SAL_INFO ("cppcanvas.emf", "EMF+\tpoint type: " << (int)pPointTypes [i]);
190 aPolygon.clear ();
192 #if OSL_DEBUG_LEVEL > 1
193 const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (GetPolygon (rR)));
195 SAL_INFO ("cppcanvas.emf",
196 "EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << aBounds.getWidth () << "x" << aBounds.getHeight () << " (mapped)");
197 #else
198 (void) rR; // avoid warnings
199 #endif
202 ::basegfx::B2DPolyPolygon& GetPolygon (ImplRenderer& rR, bool bMapIt = true)
204 ::basegfx::B2DPolygon polygon;
206 aPolygon.clear ();
208 int last_normal = 0, p = 0;
209 ::basegfx::B2DPoint prev, mapped;
210 bool hasPrev = false;
211 for (int i = 0; i < nPoints; i ++) {
212 if (p && pPointTypes && (pPointTypes [i] == 0)) {
213 aPolygon.append (polygon);
214 last_normal = i;
215 p = 0;
216 polygon.clear ();
219 if (bMapIt)
220 mapped = rR.Map (pPoints [i*2], pPoints [i*2 + 1]);
221 else
222 mapped = ::basegfx::B2DPoint (pPoints [i*2], pPoints [i*2 + 1]);
223 if (pPointTypes) {
224 if ((pPointTypes [i] & 0x07) == 3) {
225 if (((i - last_normal )% 3) == 1) {
226 polygon.setNextControlPoint (p - 1, mapped);
227 SAL_INFO ("cppcanvas.emf", "polygon append next: " << p - 1 << " mapped: " << mapped.getX () << "," << mapped.getY ());
228 continue;
229 } else if (((i - last_normal) % 3) == 2) {
230 prev = mapped;
231 hasPrev = true;
232 continue;
234 } else
235 last_normal = i;
237 polygon.append (mapped);
238 SAL_INFO ("cppcanvas.emf", "polygon append point: " << pPoints [i*2] << "," << pPoints [i*2 + 1] << " mapped: " << mapped.getX () << ":" << mapped.getY ());
239 if (hasPrev) {
240 polygon.setPrevControlPoint (p, prev);
241 SAL_INFO ("cppcanvas.emf", "polygon append prev: " << p << " mapped: " << prev.getX () << "," << prev.getY ());
242 hasPrev = false;
244 p ++;
245 if (pPointTypes && (pPointTypes [i] & 0x80)) { // closed polygon
246 polygon.setClosed (true);
247 aPolygon.append (polygon);
248 SAL_INFO ("cppcanvas.emf", "close polygon");
249 last_normal = i + 1;
250 p = 0;
251 polygon.clear ();
255 if (polygon.count ()) {
256 aPolygon.append (polygon);
258 #if OSL_DEBUG_LEVEL > 1
259 for (unsigned int i=0; i<aPolygon.count(); i++) {
260 polygon = aPolygon.getB2DPolygon(i);
261 SAL_INFO ("cppcanvas.emf", "polygon: " << i);
262 for (unsigned int j=0; j<polygon.count(); j++) {
263 ::basegfx::B2DPoint point = polygon.getB2DPoint(j);
264 SAL_INFO ("cppcanvas.emf", "point: " << point.getX() << "," << point.getY());
265 if (polygon.isPrevControlPointUsed(j)) {
266 point = polygon.getPrevControlPoint(j);
267 SAL_INFO ("cppcanvas.emf", "prev: " << point.getX() << "," << point.getY());
269 if (polygon.isNextControlPointUsed(j)) {
270 point = polygon.getNextControlPoint(j);
271 SAL_INFO ("cppcanvas.emf", "next: " << point.getX() << "," << point.getY());
275 #endif
278 return aPolygon;
282 struct EMFPRegion : public EMFPObject
284 sal_Int32 parts;
285 sal_Int32 *combineMode;
286 sal_Int32 initialState;
287 EMFPPath *initialPath;
288 float ix, iy, iw, ih;
290 EMFPRegion ()
292 combineMode = NULL;
293 initialPath = NULL;
296 ~EMFPRegion ()
298 if (combineMode) {
299 delete [] combineMode;
300 combineMode = NULL;
302 if (initialPath) {
303 delete initialPath;
304 initialPath = NULL;
308 void Read (SvStream& s)
310 sal_uInt32 header;
312 s >> header >> parts;
314 SAL_INFO ("cppcanvas.emf", "EMF+\tregion");
315 SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " parts: " << parts << std::dec );
317 if (parts) {
318 if( parts<0 || sal_uInt32(parts)>SAL_MAX_INT32/sizeof(sal_Int32) )
319 parts = SAL_MAX_INT32/sizeof(sal_Int32);
321 combineMode = new sal_Int32 [parts];
323 for (int i = 0; i < parts; i ++) {
324 s >> combineMode [i];
325 SAL_INFO ("cppcanvas.emf", "EMF+\tcombine mode [" << i << "]: 0x" << std::hex << combineMode [i] << std::dec);
329 s >> initialState;
330 SAL_INFO ("cppcanvas.emf", "EMF+\tinitial state: 0x" << std::hex << initialState << std::dec);
334 struct EMFPBrush : public EMFPObject
336 ::Color solidColor;
337 sal_uInt32 type;
338 sal_uInt32 additionalFlags;
340 /* linear gradient */
341 sal_Int32 wrapMode;
342 float areaX, areaY, areaWidth, areaHeight;
343 ::Color secondColor; // first color is stored in solidColor;
344 XForm transformation;
345 bool hasTransformation;
346 sal_Int32 blendPoints;
347 float* blendPositions;
348 float* blendFactors;
349 sal_Int32 colorblendPoints;
350 float* colorblendPositions;
351 ::Color* colorblendColors;
352 sal_Int32 surroundColorsNumber;
353 ::Color* surroundColors;
354 EMFPPath *path;
356 public:
357 EMFPBrush ()
359 blendPositions = NULL;
360 colorblendPositions = NULL;
361 colorblendColors = NULL;
362 surroundColors = NULL;
363 path = NULL;
364 hasTransformation = false;
367 ~EMFPBrush ()
369 if (blendPositions != NULL) {
370 delete[] blendPositions;
371 blendPositions = NULL;
373 if (colorblendPositions != NULL) {
374 delete[] colorblendPositions;
375 colorblendPositions = NULL;
377 if (colorblendColors != NULL) {
378 delete[] colorblendColors;
379 colorblendColors = NULL;
381 if (surroundColors != NULL) {
382 delete[] surroundColors;
383 surroundColors = NULL;
385 if (path) {
386 delete path;
387 path = NULL;
391 sal_uInt32 GetType() const { return type; }
392 const ::Color& GetColor() const { return solidColor; }
394 void Read (SvStream& s, ImplRenderer& rR)
396 sal_uInt32 header;
398 s >> header >> type;
400 SAL_INFO ("cppcanvas.emf", "EMF+\tbrush");
401 SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec);
403 switch (type) {
404 case 0:
406 sal_uInt32 color;
408 s >> color;
409 solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
410 SAL_INFO ("cppcanvas.emf", "EMF+\tsolid color: 0x" << std::hex << color << std::dec);
412 break;
414 // path gradient
415 case 3:
417 s >> additionalFlags >> wrapMode;
419 SAL_INFO ("cppcanvas.emf", "EMF+\tpath gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec);
421 sal_uInt32 color;
423 s >> color;
424 solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
425 SAL_INFO("cppcanvas.emf", "EMF+\tcenter color: 0x" << std::hex << color << std::dec);
427 s >> areaX >> areaY;
428 SAL_INFO("cppcanvas.emf", "EMF+\tcenter point: " << areaX << "," << areaY);
430 s >> surroundColorsNumber;
431 SAL_INFO("cppcanvas.emf", "EMF+\tsurround colors: " << surroundColorsNumber);
433 if( surroundColorsNumber<0 || sal_uInt32(surroundColorsNumber)>SAL_MAX_INT32/sizeof(::Color) )
434 surroundColorsNumber = SAL_MAX_INT32/sizeof(::Color);
436 surroundColors = new ::Color [surroundColorsNumber];
437 for (int i = 0; i < surroundColorsNumber; i++) {
438 s >> color;
439 surroundColors[i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
440 if (i == 0)
441 secondColor = surroundColors [0];
442 SAL_INFO("cppcanvas.emf", "EMF+\tsurround color[" << i << "]: 0x" << std::hex << color << std::dec);
445 if (additionalFlags & 0x01) {
446 sal_Int32 pathLength;
448 s >> pathLength;
449 SAL_INFO("cppcanvas.emf", "EMF+\tpath length: " << pathLength);
451 sal_uInt32 pos = s.Tell ();
452 #if OSL_DEBUG_LEVEL > 1
453 dumpWords (s, 32);
454 #endif
456 sal_uInt32 pathHeader;
457 sal_Int32 pathPoints, pathFlags;
458 s >> pathHeader >> pathPoints >> pathFlags;
460 SAL_INFO("cppcanvas.emf", "EMF+\tpath (brush path gradient)");
461 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec );
463 path = new EMFPPath (pathPoints);
464 path->Read (s, pathFlags, rR);
466 s.Seek (pos + pathLength);
468 const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (path->GetPolygon (rR, false)));
469 areaWidth = aBounds.getWidth ();
470 areaHeight = aBounds.getHeight ();
472 SAL_INFO("cppcanvas.emf", "EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << " " << aBounds.getWidth () << "x" << aBounds.getHeight ());
475 if (additionalFlags & 0x02) {
476 SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
477 s >> transformation;
478 hasTransformation = true;
479 SAL_INFO("cppcanvas.emf",
480 "EMF+\tm11: " << transformation.eM11 << " m12: " << transformation.eM12 <<
481 "\nEMF+\tm21: " << transformation.eM21 << " m22: " << transformation.eM22 <<
482 "\nEMF+\tdx: " << transformation.eDx << " dy: " << transformation.eDy);
485 if (additionalFlags & 0x08) {
486 s >> blendPoints;
487 SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
488 if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
489 blendPoints = SAL_MAX_INT32/(2*sizeof(float));
490 blendPositions = new float [2*blendPoints];
491 blendFactors = blendPositions + blendPoints;
492 for (int i=0; i < blendPoints; i ++) {
493 s >> blendPositions [i];
494 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions [i]);
496 for (int i=0; i < blendPoints; i ++) {
497 s >> blendFactors [i];
498 SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors [i]);
502 if (additionalFlags & 0x04) {
503 s >> colorblendPoints;
504 SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
505 if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
506 colorblendPoints = SAL_MAX_INT32/sizeof(float);
507 if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
508 colorblendPoints = SAL_MAX_INT32/sizeof(::Color);
509 colorblendPositions = new float [colorblendPoints];
510 colorblendColors = new ::Color [colorblendPoints];
511 for (int i=0; i < colorblendPoints; i ++) {
512 s >> colorblendPositions [i];
513 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions [i]);
515 for (int i=0; i < colorblendPoints; i ++) {
516 s >> color;
517 colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
518 SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
521 } else {
522 #if OSL_DEBUG_LEVEL > 1
523 dumpWords (s, 1024);
524 #endif
526 break;
528 // linear gradient
529 case 4:
531 s >> additionalFlags >> wrapMode;
533 SAL_INFO("cppcanvas.emf", "EMF+\tlinear gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec);
535 s >> areaX >> areaY >> areaWidth >> areaHeight;
537 SAL_INFO("cppcanvas.emf", "EMF+\tarea: " << areaX << "," << areaY << " - " << areaWidth << "x" << areaHeight);
539 sal_uInt32 color;
541 s >> color;
542 solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
543 SAL_INFO("cppcanvas.emf", "EMF+\tfirst color: 0x" << std::hex << color << std::dec);
545 s >> color;
546 secondColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
547 SAL_INFO("cppcanvas.emf", "EMF+\tsecond color: 0x" << std::hex << color << std::dec);
549 // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
550 s >> color;
551 s >> color;
553 if (additionalFlags & 0x02) {
554 SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
555 s >> transformation;
556 hasTransformation = true;
557 SAL_INFO("cppcanvas.emf",
558 "EMF+\tm11: " << transformation.eM11 << " m12: " << transformation.eM12 <<
559 "\nEMF+\tm21: " << transformation.eM21 << " m22: " << transformation.eM22 <<
560 "\nEMF+\tdx: " << transformation.eDx << " dy: " << transformation.eDy);
562 if (additionalFlags & 0x08) {
563 s >> blendPoints;
564 SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
565 if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
566 blendPoints = SAL_MAX_INT32/(2*sizeof(float));
567 blendPositions = new float [2*blendPoints];
568 blendFactors = blendPositions + blendPoints;
569 for (int i=0; i < blendPoints; i ++) {
570 s >> blendPositions [i];
571 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions [i]);
573 for (int i=0; i < blendPoints; i ++) {
574 s >> blendFactors [i];
575 SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors [i]);
579 if (additionalFlags & 0x04) {
580 s >> colorblendPoints;
581 SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
582 if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
583 colorblendPoints = SAL_MAX_INT32/sizeof(float);
584 if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
585 colorblendPoints = sal_uInt32(SAL_MAX_INT32)/sizeof(::Color);
586 colorblendPositions = new float [colorblendPoints];
587 colorblendColors = new ::Color [colorblendPoints];
588 for (int i=0; i < colorblendPoints; i ++) {
589 s >> colorblendPositions [i];
590 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions [i]);
592 for (int i=0; i < colorblendPoints; i ++) {
593 s >> color;
594 colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
595 SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
599 break;
601 default:
602 SAL_INFO("cppcanvas.emf", "EMF+\tunhandled brush type: " << std::hex << type << std::dec);
607 /// Convert stroke caps between EMF+ and rendering API
608 sal_Int8 lcl_convertStrokeCap(sal_uInt32 nEmfStroke)
610 switch (nEmfStroke)
612 case EmfPlusLineCapTypeSquare: return rendering::PathCapType::SQUARE;
613 case EmfPlusLineCapTypeRound: return rendering::PathCapType::ROUND;
616 // we have no mapping for EmfPlusLineCapTypeTriangle = 0x00000003,
617 // so return BUTT always
618 return rendering::PathCapType::BUTT;
621 struct EMFPCustomLineCap : public EMFPObject
623 sal_uInt32 type;
624 sal_uInt32 strokeStartCap, strokeEndCap, strokeJoin;
625 float miterLimit;
626 basegfx::B2DPolyPolygon polygon;
627 bool mbIsFilled;
629 public:
630 EMFPCustomLineCap() : EMFPObject()
634 ~EMFPCustomLineCap()
638 void SetAttributes(rendering::StrokeAttributes& aAttributes)
640 aAttributes.StartCapType = lcl_convertStrokeCap(strokeStartCap);
641 aAttributes.EndCapType = lcl_convertStrokeCap(strokeEndCap);
643 switch (strokeJoin)
645 case EmfPlusLineJoinTypeMiter: // fall-through
646 case EmfPlusLineJoinTypeMiterClipped: aAttributes.JoinType = rendering::PathJoinType::MITER; break;
647 case EmfPlusLineJoinTypeBevel: aAttributes.JoinType = rendering::PathJoinType::BEVEL; break;
648 case EmfPlusLineJoinTypeRound: aAttributes.JoinType = rendering::PathJoinType::ROUND; break;
651 aAttributes.MiterLimit = miterLimit;
654 void ReadPath(SvStream& s, ImplRenderer& rR, bool bFill)
656 sal_Int32 pathLength;
657 s >> pathLength;
658 SAL_INFO("cppcanvas.emf", "EMF+\t\tpath length: " << pathLength);
660 sal_uInt32 pathHeader;
661 sal_Int32 pathPoints, pathFlags;
662 s >> pathHeader >> pathPoints >> pathFlags;
664 SAL_INFO("cppcanvas.emf", "EMF+\t\tpath (custom cap line path)");
665 SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec );
667 EMFPPath path(pathPoints);
668 path.Read(s, pathFlags, rR);
670 polygon = path.GetPolygon(rR, false);
671 mbIsFilled = bFill;
673 // transformation to convert the path to what LibreOffice
674 // expects
675 B2DHomMatrix aMatrix;
676 aMatrix.scale(1.0, -1.0);
678 polygon.transform(aMatrix);
681 void Read (SvStream& s, ImplRenderer& rR)
683 sal_uInt32 header;
685 s >> header >> type;
687 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustom cap");
688 SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << header << " type: " << type << std::dec);
690 if (type == EmfPlusCustomLineCapDataTypeDefault)
692 sal_uInt32 customLineCapDataFlags, baseCap;
693 float baseInset;
694 float widthScale;
695 float fillHotSpotX, fillHotSpotY, strokeHotSpotX, strokeHotSpotY;
697 s >> customLineCapDataFlags >> baseCap >> baseInset
698 >> strokeStartCap >> strokeEndCap >> strokeJoin
699 >> miterLimit >> widthScale
700 >> fillHotSpotX >> fillHotSpotY >> strokeHotSpotX >> strokeHotSpotY;
702 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomLineCapDataFlags: 0x" << std::hex << customLineCapDataFlags);
703 SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseCap: 0x" << std::hex << baseCap);
704 SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseInset: " << baseInset);
705 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeStartCap: 0x" << std::hex << strokeStartCap);
706 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeEndCap: 0x" << std::hex << strokeEndCap);
707 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeJoin: 0x" << std::hex << strokeJoin);
708 SAL_INFO("cppcanvas.emf", "EMF+\t\tmiterLimit: " << miterLimit);
709 SAL_INFO("cppcanvas.emf", "EMF+\t\twidthScale: " << widthScale);
711 if (customLineCapDataFlags & EmfPlusCustomLineCapDataFillPath)
713 ReadPath(s, rR, true);
716 if (customLineCapDataFlags & EmfPlusCustomLineCapDataLinePath)
718 ReadPath(s, rR, false);
721 else if (type == EmfPlusCustomLineCapDataTypeAdjustableArrow)
723 // TODO only reads the data, does not use them [I've had
724 // no test document to be able to implement it]
726 sal_Int32 width, height, middleInset, fillState, lineStartCap;
727 sal_Int32 lineEndCap, lineJoin, widthScale;
728 float fillHotSpotX, fillHotSpotY, lineHotSpotX, lineHotSpotY;
730 s >> width >> height >> middleInset >> fillState >> lineStartCap
731 >> lineEndCap >> lineJoin >> miterLimit >> widthScale
732 >> fillHotSpotX >> fillHotSpotY >> lineHotSpotX >> lineHotSpotY;
734 SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - actually read EmfPlusCustomLineCapArrowData object (section 2.2.2.12)");
739 struct EMFPPen : public EMFPBrush
741 XForm transformation;
742 float width;
743 sal_Int32 startCap;
744 sal_Int32 endCap;
745 sal_Int32 lineJoin;
746 float mitterLimit;
747 sal_Int32 dashStyle;
748 sal_Int32 dashCap;
749 float dashOffset;
750 sal_Int32 dashPatternLen;
751 float *dashPattern;
752 sal_Int32 alignment;
753 sal_Int32 compoundArrayLen;
754 float *compoundArray;
755 sal_Int32 customStartCapLen;
756 EMFPCustomLineCap *customStartCap;
757 sal_Int32 customEndCapLen;
758 EMFPCustomLineCap *customEndCap;
760 public:
761 EMFPPen () : EMFPBrush ()
763 dashPattern = NULL;
764 compoundArray = NULL;
765 customStartCap = NULL;
766 customEndCap = NULL;
769 ~EMFPPen ()
771 delete[] dashPattern;
772 delete[] compoundArray;
773 delete customStartCap;
774 delete customEndCap;
777 void SetStrokeWidth(rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
779 #if OSL_DEBUG_LEVEL > 1
780 if (width == 0.0) {
781 SAL_INFO ("cppcanvas.emf", "TODO: pen with zero width - using minimal which might not be correct\n");
783 #endif
784 rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getX());
787 void SetStrokeDashing(rendering::StrokeAttributes& rStrokeAttributes)
789 if (dashStyle != EmfPlusLineStyleSolid)
791 const float dash[] = {3, 3};
792 const float dot[] = {1, 3};
793 const float dashdot[] = {3, 3, 1, 3};
794 const float dashdotdot[] = {3, 3, 1, 3, 1, 3};
796 sal_Int32 nLen = 0;
797 const float *pPattern;
798 switch (dashStyle)
800 case EmfPlusLineStyleDash: nLen = SAL_N_ELEMENTS(dash); pPattern = dash; break;
801 case EmfPlusLineStyleDot: nLen = SAL_N_ELEMENTS(dot); pPattern = dot; break;
802 case EmfPlusLineStyleDashDot: nLen = SAL_N_ELEMENTS(dashdot); pPattern = dashdot; break;
803 case EmfPlusLineStyleDashDotDot: nLen = SAL_N_ELEMENTS(dashdotdot); pPattern = dashdotdot; break;
804 case EmfPlusLineStyleCustom: nLen = dashPatternLen; pPattern = dashPattern; break;
806 if (nLen > 0)
808 uno::Sequence<double> aDashArray(nLen);
809 for (int i = 0; i < nLen; ++i)
810 aDashArray[i] = pPattern[i];
812 rStrokeAttributes.DashArray = aDashArray;
817 void Read (SvStream& s, ImplRenderer& rR, sal_Int32, sal_Int32 )
819 sal_uInt32 header, unknown, penFlags, unknown2;
820 int i;
822 s >> header >> unknown >> penFlags >> unknown2 >> width;
824 SAL_INFO("cppcanvas.emf", "EMF+\tpen");
825 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " unknown: 0x" << unknown <<
826 " additional flags: 0x" << penFlags << " unknown: 0x" << unknown2 << " width: " << std::dec << width );
828 if (penFlags & 1)
829 s >> transformation;
831 if (penFlags & 2)
833 s >> startCap;
834 SAL_INFO("cppcanvas.emf", "EMF+\t\tstartCap: 0x" << std::hex << startCap);
836 else
837 startCap = 0;
839 if (penFlags & 4)
841 s >> endCap;
842 SAL_INFO("cppcanvas.emf", "EMF+\t\tendCap: 0x" << std::hex << endCap);
844 else
845 endCap = 0;
847 if (penFlags & 8)
848 s >> lineJoin;
849 else
850 lineJoin = 0;
852 if (penFlags & 16)
853 s >> mitterLimit;
854 else
855 mitterLimit = 0;
857 if (penFlags & 32)
859 s >> dashStyle;
860 SAL_INFO("cppcanvas.emf", "EMF+\t\tdashStyle: 0x" << std::hex << dashStyle);
862 else
863 dashStyle = 0;
865 if (penFlags & 64)
866 s >> dashCap;
867 else
868 dashCap = 0;
870 if (penFlags & 128)
871 s >> dashOffset;
872 else
873 dashOffset = 0;
875 if (penFlags & 256)
877 dashStyle = EmfPlusLineStyleCustom;
879 s >> dashPatternLen;
880 SAL_INFO("cppcanvas.emf", "EMF+\t\tdashPatternLen: " << dashPatternLen);
882 if( dashPatternLen<0 || sal_uInt32(dashPatternLen)>SAL_MAX_INT32/sizeof(float) )
883 dashPatternLen = SAL_MAX_INT32/sizeof(float);
884 dashPattern = new float [dashPatternLen];
885 for (i = 0; i < dashPatternLen; i++)
887 s >> dashPattern [i];
888 SAL_INFO("cppcanvas.emf", "EMF+\t\t\tdashPattern[" << i << "]: " << dashPattern[i]);
891 else
892 dashPatternLen = 0;
894 if (penFlags & 512)
895 s >> alignment;
896 else
897 alignment = 0;
899 if (penFlags & 1024) {
900 s >> compoundArrayLen;
901 if( compoundArrayLen<0 || sal_uInt32(compoundArrayLen)>SAL_MAX_INT32/sizeof(float) )
902 compoundArrayLen = SAL_MAX_INT32/sizeof(float);
903 compoundArray = new float [compoundArrayLen];
904 for (i = 0; i < compoundArrayLen; i++)
905 s >> compoundArray [i];
906 } else
907 compoundArrayLen = 0;
909 if (penFlags & 2048)
911 s >> customStartCapLen;
912 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomStartCapLen: " << customStartCapLen);
913 sal_uInt32 pos = s.Tell();
915 customStartCap = new EMFPCustomLineCap();
916 customStartCap->Read(s, rR);
918 // maybe we don't read everything yet, play it safe ;-)
919 s.Seek(pos + customStartCapLen);
921 else
922 customStartCapLen = 0;
924 if (penFlags & 4096)
926 s >> customEndCapLen;
927 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomEndCapLen: " << customEndCapLen);
928 sal_uInt32 pos = s.Tell();
930 customEndCap = new EMFPCustomLineCap();
931 customEndCap->Read(s, rR);
933 // maybe we don't read everything yet, play it safe ;-)
934 s.Seek(pos + customEndCapLen);
936 else
937 customEndCapLen = 0;
939 EMFPBrush::Read (s, rR);
943 struct EMFPImage : public EMFPObject
945 sal_uInt32 type;
946 sal_Int32 width;
947 sal_Int32 height;
948 sal_Int32 stride;
949 sal_Int32 pixelFormat;
950 Graphic graphic;
953 void Read (SvMemoryStream &s, sal_uInt32 dataSize, sal_Bool bUseWholeStream)
955 sal_uInt32 header, unknown;
957 s >> header >> type;
959 SAL_INFO("cppcanvas.emf", "EMF+\timage\nEMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec );
961 if (type == 1) { // bitmap
962 s >> width >> height >> stride >> pixelFormat >> unknown;
963 SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << width << " height: " << height << " stride: " << "pixelFormat: 0x" << std::hex << pixelFormat << std::dec);
964 if (width == 0) { // non native formats
965 GraphicFilter filter;
967 filter.ImportGraphic (graphic, OUString(), s);
968 SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << graphic.GetBitmap().GetSizePixel().Width() << " height: " << graphic.GetBitmap().GetSizePixel().Height());
971 } else if (type == 2) {
972 sal_Int32 mfType, mfSize;
974 s >> mfType >> mfSize;
975 SAL_INFO("cppcanvas.emf", "EMF+\tmetafile type: " << mfType << " dataSize: " << mfSize << " real size calculated from record dataSize: " << dataSize - 16);
977 GraphicFilter filter;
978 // workaround buggy metafiles, which have wrong mfSize set (n#705956 for example)
979 SvMemoryStream mfStream (((char *)s.GetData()) + s.Tell(), bUseWholeStream ? s.remainingSize() : dataSize - 16, STREAM_READ);
981 filter.ImportGraphic (graphic, OUString(), mfStream);
983 // debug code - write the stream to debug file /tmp/emf-stream.emf
984 #if OSL_DEBUG_LEVEL > 1
985 mfStream.Seek(0);
986 static sal_Int32 emfp_debug_stream_number = 0;
987 OUString emfp_debug_filename = "/tmp/emf-embedded-stream" +
988 OUString::number(emfp_debug_stream_number++) + ".emf";
990 SvFileStream file( emfp_debug_filename, STREAM_WRITE | STREAM_TRUNC );
992 mfStream >> file;
993 file.Flush();
994 file.Close();
995 #endif
1000 struct EMFPFont : public EMFPObject
1002 sal_uInt32 version;
1003 float emSize;
1004 sal_uInt32 sizeUnit;
1005 sal_Int32 fontFlags;
1006 OUString family;
1008 void Read (SvMemoryStream &s)
1010 sal_uInt32 header;
1011 sal_uInt32 reserved;
1012 sal_uInt32 length;
1014 s >> header >> emSize >> sizeUnit >> fontFlags >> reserved >> length;
1016 OSL_ASSERT( ( header >> 12 ) == 0xdbc01 );
1018 SAL_INFO("cppcanvas.emf", "EMF+\tfont\n"
1019 << "EMF+\theader: 0x" << std::hex << (header >> 12) << " version: 0x" << (header & 0x1fff) << " size: " << std::dec << emSize << " unit: 0x" << std::hex << sizeUnit << std::dec);
1020 SAL_INFO("cppcanvas.emf", "EMF+\tflags: 0x" << std::hex << fontFlags << " reserved: 0x" << reserved << " length: 0x" << std::hex << length << std::dec);
1022 if( length > 0 && length < 0x4000 ) {
1023 sal_Unicode *chars = (sal_Unicode *) alloca( sizeof( sal_Unicode ) * length );
1025 for( sal_uInt32 i = 0; i < length; i++ )
1026 s >> chars[ i ];
1028 family = OUString( chars, length );
1029 SAL_INFO("cppcanvas.emf", "EMF+\tfamily: " << OUStringToOString( family, RTL_TEXTENCODING_UTF8).getStr()); // TODO: can we just use family?
1034 void ImplRenderer::ReadRectangle (SvStream& s, float& x, float& y, float &width, float& height, bool bCompressed)
1036 if (bCompressed) {
1037 sal_Int16 ix, iy, iw, ih;
1039 s >> ix >> iy >> iw >> ih;
1041 x = ix;
1042 y = iy;
1043 width = iw;
1044 height = ih;
1045 } else
1046 s >> x >> y >> width >> height;
1049 void ImplRenderer::ReadPoint (SvStream& s, float& x, float& y, sal_uInt32 flags)
1051 if (flags & 0x4000) {
1052 sal_Int16 ix, iy;
1054 s >> ix >> iy;
1056 x = ix;
1057 y = iy;
1058 } else
1059 s >> x >> y;
1062 void ImplRenderer::MapToDevice (double& x, double& y)
1064 // TODO: other units
1065 x = 100*nMmX*x/nPixX;
1066 y = 100*nMmY*y/nPixY;
1069 ::basegfx::B2DPoint ImplRenderer::Map (double ix, double iy)
1071 double x, y;
1073 x = ix*aWorldTransform.eM11 + iy*aWorldTransform.eM21 + aWorldTransform.eDx;
1074 y = ix*aWorldTransform.eM12 + iy*aWorldTransform.eM22 + aWorldTransform.eDy;
1076 MapToDevice (x, y);
1078 x -= nFrameLeft;
1079 y -= nFrameTop;
1081 x *= aBaseTransform.eM11;
1082 y *= aBaseTransform.eM22;
1084 return ::basegfx::B2DPoint (x, y);
1087 ::basegfx::B2DSize ImplRenderer::MapSize (double iwidth, double iheight)
1089 double w, h;
1091 w = iwidth*aWorldTransform.eM11 + iheight*aWorldTransform.eM21;
1092 h = iwidth*aWorldTransform.eM12 + iheight*aWorldTransform.eM22;
1094 MapToDevice (w, h);
1096 w *= aBaseTransform.eM11;
1097 h *= aBaseTransform.eM22;
1099 return ::basegfx::B2DSize (w, h);
1102 #define COLOR(x) \
1103 ::vcl::unotools::colorToDoubleSequence( ::Color (0xff - (x >> 24), \
1104 (x >> 16) & 0xff, \
1105 (x >> 8) & 0xff, \
1106 x & 0xff), \
1107 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
1109 void ImplRenderer::EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
1110 OutDevState& rState, const CanvasSharedPtr& rCanvas, bool isColor, sal_uInt32 brushIndexOrColor)
1112 ::basegfx::B2DPolyPolygon localPolygon (polygon);
1114 SAL_INFO("cppcanvas.emf", "EMF+\tfill polygon");
1116 localPolygon.transform( rState.mapModeTransform );
1118 ActionSharedPtr pPolyAction;
1120 if (isColor) {
1121 SAL_INFO("cppcanvas.emf", "EMF+\t\tcolor fill:0x" << std::hex << brushIndexOrColor << std::dec);
1122 rState.isFillColorSet = true;
1123 rState.isLineColorSet = false;
1125 rState.fillColor = COLOR(brushIndexOrColor);
1127 pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) );
1129 } else {
1130 rState.isFillColorSet = true;
1131 // extract UseBrush
1132 EMFPBrush* brush = (EMFPBrush*) aObjects [brushIndexOrColor & 0xff];
1133 SAL_INFO("cppcanvas.emf", "EMF+\tbrush fill slot: " << brushIndexOrColor << " (type: " << brush->GetType () << ")");
1135 // give up in case something wrong happened
1136 if( !brush )
1137 return;
1139 rState.isFillColorSet = false;
1140 rState.isLineColorSet = false;
1142 if (brush->type == 3 || brush->type == 4) {
1144 if (brush->type == 3 && !(brush->additionalFlags & 0x1))
1145 return; // we are unable to parse these brushes yet
1147 ::basegfx::B2DHomMatrix aTextureTransformation;
1148 ::basegfx::B2DHomMatrix aWorldTransformation;
1149 ::basegfx::B2DHomMatrix aBaseTransformation;
1150 rendering::Texture aTexture;
1152 aWorldTransformation.set (0, 0, aWorldTransform.eM11);
1153 aWorldTransformation.set (0, 1, aWorldTransform.eM21);
1154 aWorldTransformation.set (0, 2, aWorldTransform.eDx);
1155 aWorldTransformation.set (1, 0, aWorldTransform.eM12);
1156 aWorldTransformation.set (1, 1, aWorldTransform.eM22);
1157 aWorldTransformation.set (1, 2, aWorldTransform.eDy);
1159 aBaseTransformation.set (0, 0, aBaseTransform.eM11);
1160 aBaseTransformation.set (0, 1, aBaseTransform.eM21);
1161 aBaseTransformation.set (0, 2, aBaseTransform.eDx);
1162 aBaseTransformation.set (1, 0, aBaseTransform.eM12);
1163 aBaseTransformation.set (1, 1, aBaseTransform.eM22);
1164 aBaseTransformation.set (1, 2, aBaseTransform.eDy);
1166 if (brush->type == 4) {
1167 aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
1168 aTextureTransformation.translate (brush->areaX, brush->areaY);
1169 } else {
1170 aTextureTransformation.translate (-0.5, -0.5);
1171 aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
1172 aTextureTransformation.translate (brush->areaX,brush->areaY);
1175 if (brush->hasTransformation) {
1176 ::basegfx::B2DHomMatrix aTransformation;
1178 aTransformation.set (0, 0, brush->transformation.eM11);
1179 aTransformation.set (0, 1, brush->transformation.eM21);
1180 aTransformation.set (0, 2, brush->transformation.eDx);
1181 aTransformation.set (1, 0, brush->transformation.eM12);
1182 aTransformation.set (1, 1, brush->transformation.eM22);
1183 aTransformation.set (1, 2, brush->transformation.eDy);
1185 aTextureTransformation *= aTransformation;
1188 aTextureTransformation *= aWorldTransformation;
1189 aTextureTransformation.scale (100.0*nMmX/nPixX, 100.0*nMmY/nPixY);
1190 aTextureTransformation.translate (-nFrameLeft, -nFrameTop);
1191 aTextureTransformation *= rState.mapModeTransform;
1192 aTextureTransformation *= aBaseTransformation;
1194 aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
1195 aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
1196 aTexture.Alpha = 1.0;
1198 basegfx::ODFGradientInfo aGradInfo;
1199 OUString aGradientService;
1201 const uno::Sequence< double > aStartColor(
1202 ::vcl::unotools::colorToDoubleSequence( brush->solidColor,
1203 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
1204 const uno::Sequence< double > aEndColor(
1205 ::vcl::unotools::colorToDoubleSequence( brush->secondColor,
1206 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
1207 uno::Sequence< uno::Sequence < double > > aColors (2);
1208 uno::Sequence< double > aStops (2);
1210 if (brush->blendPositions) {
1211 SAL_INFO("cppcanvas.emf", "EMF+\t\tuse blend");
1212 aColors.realloc (brush->blendPoints);
1213 aStops.realloc (brush->blendPoints);
1214 int length = aStartColor.getLength ();
1215 uno::Sequence< double > aColor (length);
1217 OSL_ASSERT (length == aEndColor.getLength());
1219 for (int i = 0; i < brush->blendPoints; i++) {
1220 aStops[i] = brush->blendPositions [i];
1222 for (int j = 0; j < length; j++) {
1223 if (brush->type == 4) {
1224 aColor [j] = aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i];
1225 } else
1226 aColor [j] = aStartColor [j]*brush->blendFactors[i] + aEndColor [j]*(1 - brush->blendFactors[i]);
1229 aColors[i] = aColor;
1231 } else if (brush->colorblendPositions) {
1232 SAL_INFO("cppcanvas.emf", "EMF+\t\tuse color blend");
1233 aColors.realloc (brush->colorblendPoints);
1234 aStops.realloc (brush->colorblendPoints);
1236 for (int i = 0; i < brush->colorblendPoints; i++) {
1237 aStops[i] = brush->colorblendPositions [i];
1238 aColors[(brush->type == 4) ? i : brush->colorblendPoints - 1 - i] = ::vcl::unotools::colorToDoubleSequence( brush->colorblendColors [i],
1239 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
1241 } else {
1242 aStops[0] = 0.0;
1243 aStops[1] = 1.0;
1245 if (brush->type == 4) {
1246 aColors[0] = aStartColor;
1247 aColors[1] = aEndColor;
1248 } else {
1249 aColors[1] = aStartColor;
1250 aColors[0] = aEndColor;
1254 SAL_INFO("cppcanvas.emf", "EMF+\t\tset gradient");
1255 basegfx::B2DRange aBoundsRectangle (0, 0, 1, 1);
1256 if (brush->type == 4) {
1257 aGradientService = "LinearGradient";
1258 aGradInfo = basegfx::tools::createLinearODFGradientInfo(
1259 aBoundsRectangle,
1260 aStops.getLength(),
1264 } else {
1265 aGradientService = "EllipticalGradient";
1266 aGradInfo = basegfx::tools::createEllipticalODFGradientInfo(
1267 aBoundsRectangle,
1268 ::basegfx::B2DVector( 0, 0 ),
1269 aStops.getLength(),
1274 uno::Reference< lang::XMultiServiceFactory > xFactory(
1275 rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
1277 if( xFactory.is() ) {
1278 uno::Sequence<uno::Any> args( 3 );
1279 beans::PropertyValue aProp;
1280 aProp.Name = "Colors";
1281 aProp.Value <<= aColors;
1282 args[0] <<= aProp;
1283 aProp.Name = "Stops";
1284 aProp.Value <<= aStops;
1285 args[1] <<= aProp;
1286 aProp.Name = "AspectRatio";
1287 aProp.Value <<= static_cast<sal_Int32>(1);
1288 args[2] <<= aProp;
1290 aTexture.Gradient.set(
1291 xFactory->createInstanceWithArguments( aGradientService,
1292 args ),
1293 uno::UNO_QUERY);
1296 ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
1297 aTextureTransformation );
1299 if( aTexture.Gradient.is() )
1300 pPolyAction =
1301 ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon,
1302 rParms.mrCanvas,
1303 rState,
1304 aTexture ) );
1308 if( pPolyAction )
1310 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd poly action");
1312 maActions.push_back(
1313 MtfAction(
1314 pPolyAction,
1315 rParms.mrCurrActionIndex ) );
1317 rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1321 double ImplRenderer::EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon& rPolygon, double fPolyLength,
1322 const ::basegfx::B2DPolyPolygon& rLineCap, bool bIsFilled, bool bStart, const rendering::StrokeAttributes& rAttributes,
1323 const ActionFactoryParameters& rParms, OutDevState& rState)
1325 if (!rLineCap.count())
1326 return 0.0;
1328 // it seems the line caps in EMF+ are 4*larger than what
1329 // LibreOffice expects, and the mapping in
1330 // createAreaGeometryForLineStartEnd scales that down, so
1331 // correct it
1332 // [unfortunately found no proof for this in the spec :-( - please
1333 // feel free to correct this if it causes trouble]
1334 double fWidth = rAttributes.StrokeWidth*4;
1336 basegfx::B2DPolyPolygon aArrow(basegfx::tools::createAreaGeometryForLineStartEnd(
1337 rPolygon, rLineCap, bStart,
1338 fWidth, fPolyLength, 0, NULL, rAttributes.StrokeWidth));
1340 // createAreaGeometryForLineStartEnd from some reason always sets
1341 // the path as closed, correct it
1342 aArrow.setClosed(rLineCap.isClosed());
1344 ActionSharedPtr pAction(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState, rAttributes));
1345 if (pAction)
1347 maActions.push_back(MtfAction(pAction, rParms.mrCurrActionIndex));
1348 rParms.mrCurrActionIndex += pAction->getActionCount()-1;
1351 if (bIsFilled)
1353 bool bWasFillColorSet = rState.isFillColorSet;
1354 rState.isFillColorSet = true;
1355 rState.fillColor = rState.lineColor;
1356 ActionSharedPtr pAction2(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState));
1357 if (pAction2)
1359 maActions.push_back(MtfAction(pAction2, rParms.mrCurrActionIndex));
1360 rParms.mrCurrActionIndex += pAction2->getActionCount()-1;
1362 rState.isFillColorSet = bWasFillColorSet;
1365 return rAttributes.StrokeWidth;
1368 void ImplRenderer::EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
1369 OutDevState& rState, const CanvasSharedPtr& rCanvas, sal_uInt32 penIndex)
1371 EMFPPen* pen = (EMFPPen*) aObjects [penIndex & 0xff];
1373 SAL_WARN_IF( !pen, "cppcanvas.emf", "emf+ missing pen" );
1375 if (pen)
1377 rState.isFillColorSet = false;
1378 rState.isLineColorSet = true;
1379 rState.lineColor = ::vcl::unotools::colorToDoubleSequence (pen->GetColor (),
1380 rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace());
1382 basegfx::B2DPolyPolygon aPolyPolygon(polygon);
1383 aPolyPolygon.transform(rState.mapModeTransform);
1384 rendering::StrokeAttributes aCommonAttributes;
1386 // some attributes are common for the polygon, and the line
1387 // starts & ends - like the stroke width
1388 pen->SetStrokeWidth(aCommonAttributes, *this, rState);
1390 // but eg. dashing has to be additionally set only on the
1391 // polygon
1392 rendering::StrokeAttributes aPolygonAttributes(aCommonAttributes);
1393 pen->SetStrokeDashing(aPolygonAttributes);
1395 basegfx::B2DPolyPolygon aFinalPolyPolygon;
1397 // render line starts & ends if present
1398 if (!pen->customStartCap && !pen->customEndCap)
1399 aFinalPolyPolygon = aPolyPolygon;
1400 else
1402 for (sal_uInt32 i = 0; i < aPolyPolygon.count(); ++i)
1404 basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(i));
1406 if (!aPolygon.isClosed())
1408 double fStart = 0.0;
1409 double fEnd = 0.0;
1410 double fPolyLength = basegfx::tools::getLength(aPolygon);
1412 // line start
1413 if (pen->customStartCap)
1415 rendering::StrokeAttributes aAttributes(aCommonAttributes);
1416 pen->customStartCap->SetAttributes(aAttributes);
1418 fStart = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon,
1419 pen->customStartCap->mbIsFilled,
1420 true, aAttributes, rParms, rState);
1423 // line end
1424 if (pen->customEndCap)
1426 rendering::StrokeAttributes aAttributes(aCommonAttributes);
1427 pen->customEndCap->SetAttributes(aAttributes);
1429 fEnd = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon,
1430 pen->customEndCap->mbIsFilled,
1431 false, aAttributes, rParms, rState);
1434 // build new poly, consume something from the old poly
1435 if (fStart != 0.0 || fEnd != 0.0)
1436 aPolygon = basegfx::tools::getSnippetAbsolute(aPolygon, fStart, fPolyLength - fEnd, fPolyLength);
1439 aFinalPolyPolygon.append(aPolygon);
1443 // finally render the polygon
1444 ActionSharedPtr pPolyAction(internal::PolyPolyActionFactory::createPolyPolyAction(aFinalPolyPolygon, rParms.mrCanvas, rState, aPolygonAttributes));
1445 if( pPolyAction )
1447 maActions.push_back(MtfAction(pPolyAction, rParms.mrCurrActionIndex));
1448 rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1453 void ImplRenderer::processObjectRecord(SvMemoryStream& rObjectStream, sal_uInt16 flags, sal_uInt32 dataSize, sal_Bool bUseWholeStream)
1455 sal_uInt32 index;
1457 SAL_INFO("cppcanvas.emf", "EMF+ Object slot: " << (flags & 0xff) << " flags: " << (flags & 0xff00));
1459 index = flags & 0xff;
1460 if (aObjects [index] != NULL) {
1461 delete aObjects [index];
1462 aObjects [index] = NULL;
1465 switch (flags & 0x7f00) {
1466 case EmfPlusObjectTypeBrush:
1468 EMFPBrush *brush;
1469 aObjects [index] = brush = new EMFPBrush ();
1470 brush->Read (rObjectStream, *this);
1472 break;
1474 case EmfPlusObjectTypePen:
1476 EMFPPen *pen;
1477 aObjects [index] = pen = new EMFPPen ();
1478 pen->Read (rObjectStream, *this, nHDPI, nVDPI);
1480 break;
1482 case EmfPlusObjectTypePath:
1483 sal_uInt32 header, pathFlags;
1484 sal_Int32 points;
1486 rObjectStream >> header >> points >> pathFlags;
1488 SAL_INFO("cppcanvas.emf", "EMF+\tpath");
1489 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " points: " << std::dec << points << " additional flags: 0x" << std::hex << pathFlags << std::dec);
1491 EMFPPath *path;
1492 aObjects [index] = path = new EMFPPath (points);
1493 path->Read (rObjectStream, pathFlags, *this);
1495 break;
1496 case EmfPlusObjectTypeRegion: {
1497 EMFPRegion *region;
1499 aObjects [index] = region = new EMFPRegion ();
1500 region->Read (rObjectStream);
1502 break;
1504 case EmfPlusObjectTypeImage:
1506 EMFPImage *image;
1507 aObjects [index] = image = new EMFPImage ();
1508 image->Read (rObjectStream, dataSize, bUseWholeStream);
1510 break;
1512 case EmfPlusObjectTypeFont:
1514 EMFPFont *font;
1515 aObjects [index] = font = new EMFPFont ();
1516 font->Read (rObjectStream);
1518 break;
1520 default:
1521 SAL_INFO("cppcanvas.emf", "EMF+\tObject unhandled flags: 0x" << std::hex << (flags & 0xff00) << std::dec);
1522 break;
1526 double ImplRenderer::setFont (sal_uInt8 objectId, const ActionFactoryParameters& rParms, OutDevState& rState)
1528 EMFPFont *font = (EMFPFont*) aObjects[ objectId ];
1530 rendering::FontRequest aFontRequest;
1531 aFontRequest.FontDescription.FamilyName = font->family;
1532 double cellSize = font->emSize;
1533 aFontRequest.CellSize = (rState.mapModeTransform*MapSize( cellSize, 0 )).getX();
1534 rState.xFont = rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest,
1535 uno::Sequence< beans::PropertyValue >(),
1536 geometry::Matrix2D() );
1538 return cellSize;
1541 void ImplRenderer::GraphicStatePush(GraphicStateMap& map, sal_Int32 index, OutDevState& rState)
1543 GraphicStateMap::iterator iter = map.find( index );
1545 if ( iter != map.end() )
1547 EmfPlusGraphicState state = iter->second;
1548 map.erase( iter );
1550 SAL_INFO("cppcanvas.emf", "stack index: " << index << " found and erased");
1553 EmfPlusGraphicState state;
1555 state.aWorldTransform = aWorldTransform;
1556 state.aDevState = rState;
1558 map[ index ] = state;
1561 void ImplRenderer::GraphicStatePop(GraphicStateMap& map, sal_Int32 index, OutDevState& rState)
1563 GraphicStateMap::iterator iter = map.find( index );
1565 if ( iter != map.end() )
1567 SAL_INFO("cppcanvas.emf", "stack index: " << index << " found");
1569 EmfPlusGraphicState state = iter->second;
1571 aWorldTransform = state.aWorldTransform;
1572 rState.clip = state.aDevState.clip;
1573 rState.clipRect = state.aDevState.clipRect;
1574 rState.xClipPoly = state.aDevState.xClipPoly;
1578 void ImplRenderer::processEMFPlus( MetaCommentAction* pAct, const ActionFactoryParameters& rFactoryParms,
1579 OutDevState& rState, const CanvasSharedPtr& rCanvas )
1581 sal_uInt32 length = pAct->GetDataSize ();
1582 SvMemoryStream rMF ((void*) pAct->GetData (), length, STREAM_READ);
1584 #if OSL_DEBUG_LEVEL > 2
1585 SAL_INFO("cppcanvas.emf", "EMF+\tDump of EMF+ record");
1586 dumpWords(rMF, length);
1587 #endif
1588 length -= 4;
1590 while (length > 0) {
1591 sal_uInt16 type, flags;
1592 sal_uInt32 size, dataSize;
1593 sal_uInt32 next;
1595 rMF >> type >> flags >> size >> dataSize;
1597 next = rMF.Tell() + ( size - 12 );
1599 if (size < 12) {
1600 SAL_INFO("cppcanvas.emf", "Size field is less than 12 bytes");
1603 SAL_INFO("cppcanvas.emf", "EMF+ record size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
1605 if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000))) {
1606 if (!mbMultipart) {
1607 mbMultipart = true;
1608 mMFlags = flags;
1609 mMStream.Seek(0);
1612 // 1st 4 bytes are unknown
1613 mMStream.Write (((const char *)rMF.GetData()) + rMF.Tell() + 4, dataSize - 4);
1614 SAL_INFO("cppcanvas.emf", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
1615 } else {
1616 if (mbMultipart) {
1617 SAL_INFO("cppcanvas.emf", "EMF+ multipart record flags: " << mMFlags);
1618 mMStream.Seek (0);
1619 processObjectRecord (mMStream, mMFlags, dataSize, sal_True);
1621 mbMultipart = false;
1624 if (type != EmfPlusRecordTypeObject || !(flags & 0x8000))
1626 switch (type) {
1627 case EmfPlusRecordTypeHeader:
1628 sal_uInt32 header, version;
1630 rMF >> header >> version >> nHDPI >> nVDPI;
1632 SAL_INFO("cppcanvas.emf", "EMF+ Header");
1633 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " version: " << std::dec << version << " horizontal DPI: " << nHDPI << " vertical DPI: " << nVDPI << " dual: " << (flags & 1));
1635 break;
1636 case EmfPlusRecordTypeEndOfFile:
1637 SAL_INFO("cppcanvas.emf", "EMF+ EndOfFile");
1638 break;
1639 case EmfPlusRecordTypeGetDC:
1640 SAL_INFO("cppcanvas.emf", "EMF+ GetDC");
1641 SAL_INFO("cppcanvas.emf", "EMF+\talready used in svtools wmf/emf filter parser");
1642 break;
1643 case EmfPlusRecordTypeObject:
1644 processObjectRecord (rMF, flags, dataSize);
1645 break;
1646 case EmfPlusRecordTypeFillPie:
1648 sal_uInt32 brushIndexOrColor;
1649 float startAngle, sweepAngle;
1651 rMF >> brushIndexOrColor >> startAngle >> sweepAngle;
1653 SAL_INFO("cppcanvas.emf", "EMF+ FillPie colorOrIndex: " << brushIndexOrColor << " startAngle: " << startAngle << " sweepAngle: " << sweepAngle);
1655 float dx, dy, dw, dh;
1657 ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1659 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1661 startAngle = 2*M_PI*startAngle/360;
1662 sweepAngle = 2*M_PI*sweepAngle/360;
1664 B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
1665 B2DSize mappedSize( MapSize (dw/2, dh/2));
1667 float endAngle = startAngle + sweepAngle;
1668 startAngle = fmodf(startAngle, static_cast<float>(M_PI*2));
1669 if (startAngle < 0)
1670 startAngle += static_cast<float>(M_PI*2);
1671 endAngle = fmodf(endAngle, static_cast<float>(M_PI*2));
1672 if (endAngle < 0)
1673 endAngle += static_cast<float>(M_PI*2);
1675 if (sweepAngle < 0)
1676 std::swap (endAngle, startAngle);
1678 SAL_INFO("cppcanvas.emf", "EMF+ adjusted angles: start " <<
1679 (360.0*startAngle/M_PI) << ", end: " << (360.0*endAngle/M_PI));
1681 B2DPolygon polygon = tools::createPolygonFromEllipseSegment (mappedCenter, mappedSize.getX (), mappedSize.getY (), startAngle, endAngle);
1682 polygon.append (mappedCenter);
1683 polygon.setClosed (true);
1685 B2DPolyPolygon polyPolygon (polygon);
1686 EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1688 break;
1689 case EmfPlusRecordTypeFillPath:
1691 sal_uInt32 index = flags & 0xff;
1692 sal_uInt32 brushIndexOrColor;
1694 rMF >> brushIndexOrColor;
1696 SAL_INFO("cppcanvas.emf", "EMF+ FillPath slot: " << index);
1698 EMFPPlusFillPolygon (((EMFPPath*) aObjects [index])->GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1700 break;
1701 case EmfPlusRecordTypeDrawEllipse:
1702 case EmfPlusRecordTypeFillEllipse:
1704 // Intentionally very bogus initial value to avoid MSVC complaining about potentially uninitialized local
1705 // variable. As long as the code stays as intended, this variable will be assigned a (real) value in the case
1706 // when it is later used.
1707 sal_uInt32 brushIndexOrColor = 1234567;
1709 if ( type == EmfPlusRecordTypeFillEllipse )
1710 rMF >> brushIndexOrColor;
1712 SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeFillEllipse ? "Fill" : "Draw") << "Ellipse slot: " << (flags & 0xff));
1714 float dx, dy, dw, dh;
1716 ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1718 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1720 B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
1721 B2DSize mappedSize( MapSize (dw/2, dh/2));
1723 ::basegfx::B2DPolyPolygon polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromEllipse( mappedCenter, mappedSize.getX (), mappedSize.getY () ) ) );
1725 if ( type == EmfPlusRecordTypeFillEllipse )
1726 EMFPPlusFillPolygon( polyPolygon,
1727 rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor );
1728 else
1729 EMFPPlusDrawPolygon( polyPolygon,
1730 rFactoryParms, rState, rCanvas, flags & 0xff );
1732 break;
1733 case EmfPlusRecordTypeFillRects:
1735 SAL_INFO("cppcanvas.emf", "EMF+ FillRects");
1737 sal_uInt32 brushIndexOrColor;
1738 sal_Int32 rectangles;
1739 bool isColor = (flags & 0x8000);
1740 ::basegfx::B2DPolygon polygon;
1742 rMF >> brushIndexOrColor >> rectangles;
1744 SAL_INFO("cppcanvas.emf", "EMF+\t" << ((flags & 0x8000) ? "color" : "brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
1746 for (int i=0; i < rectangles; i++) {
1747 if (flags & 0x4000) {
1748 /* 16bit integers */
1749 sal_Int16 x, y, width, height;
1751 rMF >> x >> y >> width >> height;
1753 polygon.append (Map (x, y));
1754 polygon.append (Map (x + width, y));
1755 polygon.append (Map (x + width, y + height));
1756 polygon.append (Map (x, y + height));
1758 SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x << "," << " " << width << "x" << height);
1759 } else {
1760 /* Single's */
1761 float x, y, width, height;
1763 rMF >> x >> y >> width >> height;
1765 polygon.append (Map (x, y));
1766 polygon.append (Map (x + width, y));
1767 polygon.append (Map (x + width, y + height));
1768 polygon.append (Map (x, y + height));
1770 SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x << "," << " " << width << "x" << height);
1773 ::basegfx::B2DPolyPolygon polyPolygon (polygon);
1775 EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, isColor, brushIndexOrColor);
1777 break;
1779 case EmfPlusRecordTypeFillPolygon:
1781 sal_uInt8 index = flags & 0xff;
1782 sal_uInt32 brushIndexOrColor;
1783 sal_Int32 points;
1785 rMF >> brushIndexOrColor;
1786 rMF >> points;
1788 SAL_INFO("cppcanvas.emf", "EMF+ FillPolygon in slot: " << +index << " points: " << points);
1789 SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags & 0x8000) ? "color" : "brush index") << " 0x" << std::hex << brushIndexOrColor << std::dec);
1791 EMFPPath path (points, true);
1792 path.Read (rMF, flags, *this);
1794 EMFPPlusFillPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1796 break;
1798 case EmfPlusRecordTypeDrawLines:
1800 sal_uInt32 points;
1802 rMF >> points;
1804 SAL_INFO("cppcanvas.emf", "EMF+ DrawLines in slot: " << (flags && 0xff) << " points: " << points);
1806 EMFPPath path (points, true);
1807 path.Read (rMF, flags, *this);
1809 EMFPPlusDrawPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags);
1811 break;
1813 case EmfPlusRecordTypeDrawPath:
1815 sal_uInt32 penIndex;
1817 rMF >> penIndex;
1819 SAL_INFO("cppcanvas.emf", "EMF+ DrawPath");
1820 SAL_INFO("cppcanvas.emf", "EMF+\tpen: " << penIndex);
1822 EMFPPath* path = (EMFPPath*) aObjects [flags & 0xff];
1823 SAL_WARN_IF( !path, "cppcanvas.emf", "EmfPlusRecordTypeDrawPath missing path" );
1825 EMFPPlusDrawPolygon (path->GetPolygon (*this), rFactoryParms, rState, rCanvas, penIndex);
1827 break;
1829 case EmfPlusRecordTypeDrawImage:
1830 case EmfPlusRecordTypeDrawImagePoints:
1832 sal_uInt32 attrIndex;
1833 sal_Int32 sourceUnit;
1835 rMF >> attrIndex >> sourceUnit;
1837 SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << "attributes index: " << attrIndex << "source unit: " << sourceUnit);
1838 SAL_INFO("cppcanvas.emf", "EMF+\tTODO: use image attributes");
1840 if (sourceUnit == 2 && aObjects [flags & 0xff]) { // we handle only GraphicsUnit.Pixel now
1841 EMFPImage& image = *(EMFPImage *) aObjects [flags & 0xff];
1842 float sx, sy, sw, sh;
1843 sal_Int32 aCount;
1845 ReadRectangle (rMF, sx, sy, sw, sh);
1846 Rectangle aSource(Point(sx, sy), Size(sw, sh));
1848 SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << " source rectangle: " << sx << "," << sy << " " << sw << "x" << sh);
1850 ::basegfx::B2DPoint aDstPoint;
1851 ::basegfx::B2DSize aDstSize;
1852 bool bValid = false;
1854 if (type == EmfPlusRecordTypeDrawImagePoints) {
1855 rMF >> aCount;
1857 if( aCount == 3) { // TODO: now that we now that this value is count we should support it better
1858 float x1, y1, x2, y2, x3, y3;
1860 ReadPoint (rMF, x1, y1, flags);
1861 ReadPoint (rMF, x2, y2, flags);
1862 ReadPoint (rMF, x3, y3, flags);
1864 SAL_INFO("cppcanvas.emf", "EMF+ destination points: " << x1 << "," << y1 << " " << x2 << "," << y2 << " " << x3 << "," << y3);
1865 SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << x1 << "," << y1 << " " << x2 - x1 << "x" << y3 - y1);
1867 aDstPoint = Map (x1, y1);
1868 aDstSize = MapSize(x2 - x1, y3 - y1);
1870 bValid = true;
1872 } else if (type == EmfPlusRecordTypeDrawImage) {
1873 float dx, dy, dw, dh;
1875 ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1877 SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
1879 aDstPoint = Map (dx, dy);
1880 aDstSize = MapSize(dw, dh);
1882 bValid = true;
1885 if (bValid) {
1886 BitmapEx aBmp( image.graphic.GetBitmapEx () );
1887 aBmp.Crop( aSource );
1889 Size aSize( aBmp.GetSizePixel() );
1890 SAL_INFO("cppcanvas.emf", "EMF+ bitmap size: " << aSize.Width() << "x" << aSize.Height());
1891 if( aSize.Width() > 0 && aSize.Height() > 0 ) {
1892 ActionSharedPtr pBmpAction (
1893 internal::BitmapActionFactory::createBitmapAction (
1894 aBmp,
1895 rState.mapModeTransform * aDstPoint,
1896 rState.mapModeTransform * aDstSize,
1897 rCanvas,
1898 rState));
1900 if( pBmpAction ) {
1901 maActions.push_back( MtfAction( pBmpAction,
1902 rFactoryParms.mrCurrActionIndex ) );
1904 rFactoryParms.mrCurrActionIndex += pBmpAction->getActionCount()-1;
1906 } else {
1907 SAL_INFO("cppcanvas.emf", "EMF+ warning: empty bitmap");
1909 } else {
1910 SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme)");
1912 } else {
1913 SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme) - possibly unsupported source units for crop rectangle");
1915 break;
1917 case EmfPlusRecordTypeDrawString:
1919 SAL_INFO("cppcanvas.emf", "EMF+ DrawString");
1921 sal_uInt32 brushId;
1922 sal_uInt32 formatId;
1923 sal_uInt32 stringLength;
1925 rMF >> brushId >> formatId >> stringLength;
1926 SAL_INFO("cppcanvas.emf", "EMF+ DrawString brushId: " << brushId << " formatId: " << formatId << " length: " << stringLength);
1928 if (flags & 0x8000) {
1929 float lx, ly, lw, lh;
1931 rMF >> lx >> ly >> lw >> lh;
1933 SAL_INFO("cppcanvas.emf", "EMF+ DrawString layoutRect: " << lx << "," << ly << " - " << lw << "x" << lh);
1935 OUString text = read_uInt16s_ToOUString(rMF, stringLength);
1937 double cellSize = setFont (flags & 0xff, rFactoryParms, rState);
1938 rState.textColor = COLOR( brushId );
1940 ::basegfx::B2DPoint point( Map( lx + 0.15*cellSize, ly + cellSize ) );
1942 ActionSharedPtr pTextAction(
1943 TextActionFactory::createTextAction(
1944 // position is just rough guess for now
1945 // we should calculate it exactly from layoutRect or font
1946 ::vcl::unotools::pointFromB2DPoint ( point ),
1947 ::Size(),
1948 ::Color(),
1949 ::Size(),
1950 ::Color(),
1951 text,
1953 stringLength,
1954 NULL,
1955 rFactoryParms.mrVDev,
1956 rFactoryParms.mrCanvas,
1957 rState,
1958 rFactoryParms.mrParms,
1959 false ) );
1960 if( pTextAction )
1962 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
1964 maActions.push_back(
1965 MtfAction(
1966 pTextAction,
1967 rFactoryParms.mrCurrActionIndex ) );
1969 rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
1971 } else {
1972 SAL_INFO("cppcanvas.emf", "EMF+ DrawString TODO - drawing with brush not yet supported");
1975 break;
1976 case EmfPlusRecordTypeSetPageTransform:
1977 rMF >> fPageScale;
1979 SAL_INFO("cppcanvas.emf", "EMF+ SetPageTransform");
1980 SAL_INFO("cppcanvas.emf", "EMF+\tscale: " << fPageScale << " unit: " << flags);
1981 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1982 break;
1983 case EmfPlusRecordTypeSetRenderingOrigin:
1984 rMF >> nOriginX >> nOriginY;
1985 SAL_INFO("cppcanvas.emf", "EMF+ SetRenderingOrigin");
1986 SAL_INFO("cppcanvas.emf", "EMF+\torigin [x,y]: " << nOriginX << "," << nOriginY);
1987 break;
1988 case EmfPlusRecordTypeSetTextRenderingHint:
1989 SAL_INFO("cppcanvas.emf", "EMF+ SetTextRenderingHint");
1990 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1991 break;
1992 case EmfPlusRecordTypeSetAntiAliasMode:
1993 SAL_INFO("cppcanvas.emf", "EMF+ SetAntiAliasMode");
1994 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1995 break;
1996 case EmfPlusRecordTypeSetInterpolationMode:
1997 SAL_INFO("cppcanvas.emf", "EMF+ InterpolationMode");
1998 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1999 break;
2000 case EmfPlusRecordTypeSetPixelOffsetMode:
2001 SAL_INFO("cppcanvas.emf", "EMF+ SetPixelOffsetMode");
2002 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2003 break;
2004 case EmfPlusRecordTypeSetCompositingQuality:
2005 SAL_INFO("cppcanvas.emf", "EMF+ SetCompositingQuality");
2006 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2007 break;
2008 case EmfPlusRecordTypeSave:
2010 sal_uInt32 stackIndex;
2012 rMF >> stackIndex;
2014 SAL_INFO("cppcanvas.emf", "EMF+ Save stack index: " << stackIndex);
2016 GraphicStatePush( mGSStack, stackIndex, rState );
2018 break;
2020 case EmfPlusRecordTypeRestore:
2022 sal_uInt32 stackIndex;
2024 rMF >> stackIndex;
2026 SAL_INFO("cppcanvas.emf", "EMF+ Restore stack index: " << stackIndex);
2028 GraphicStatePop( mGSStack, stackIndex, rState );
2030 break;
2032 case EmfPlusRecordTypeBeginContainerNoParams:
2034 sal_uInt32 stackIndex;
2036 rMF >> stackIndex;
2038 SAL_INFO("cppcanvas.emf", "EMF+ Begin Container No Params stack index: " << stackIndex);
2040 GraphicStatePush( mGSContainerStack, stackIndex, rState );
2042 break;
2043 case EmfPlusRecordTypeEndContainer:
2045 sal_uInt32 stackIndex;
2047 rMF >> stackIndex;
2049 SAL_INFO("cppcanvas.emf", "EMF+ End Container stack index: " << stackIndex);
2051 GraphicStatePop( mGSContainerStack, stackIndex, rState );
2053 break;
2054 case EmfPlusRecordTypeSetWorldTransform: {
2055 SAL_INFO("cppcanvas.emf", "EMF+ SetWorldTransform");
2056 XForm transform;
2057 rMF >> transform;
2058 aWorldTransform.Set (transform);
2059 SAL_INFO("cppcanvas.emf",
2060 "EMF+\tm11: " << aWorldTransform.eM11 << "\tm12: " << aWorldTransform.eM12 <<
2061 "\tm21: " << aWorldTransform.eM21 << "\tm22: " << aWorldTransform.eM22 <<
2062 "\tdx: " << aWorldTransform.eDx << "\tdy: " << aWorldTransform.eDy);
2063 break;
2065 case EmfPlusRecordTypeResetWorldTransform:
2066 SAL_INFO("cppcanvas.emf", "EMF+ ResetWorldTransform");
2067 aWorldTransform.SetIdentity ();
2068 break;
2069 case EmfPlusRecordTypeMultiplyWorldTransform: {
2070 SAL_INFO("cppcanvas.emf", "EMF+ MultiplyWorldTransform");
2071 XForm transform;
2072 rMF >> transform;
2074 SAL_INFO("cppcanvas.emf",
2075 "EMF+\tmatrix m11: " << transform.eM11 << "m12: " << transform.eM12 <<
2076 "EMF+\tm21: " << transform.eM21 << "m22: " << transform.eM22 <<
2077 "EMF+\tdx: " << transform.eDx << "dy: " << transform.eDy);
2079 if (flags & 0x2000) // post multiply
2080 aWorldTransform.Multiply (transform);
2081 else { // pre multiply
2082 transform.Multiply (aWorldTransform);
2083 aWorldTransform.Set (transform);
2085 SAL_INFO("cppcanvas.emf",
2086 "EMF+\tm11: " << aWorldTransform.eM11 << "m12: " << aWorldTransform.eM12 <<
2087 "EMF+\tm21: " << aWorldTransform.eM21 << "m22: " << aWorldTransform.eM22 <<
2088 "EMF+\tdx: " << aWorldTransform.eDx << "dy: " << aWorldTransform.eDy);
2089 break;
2091 case EmfPlusRecordTypeSetClipRect:
2093 int combineMode = (flags >> 8) & 0xf;
2095 SAL_INFO("cppcanvas.emf", "EMF+ SetClipRect combine mode: " << combineMode);
2096 #if OSL_DEBUG_LEVEL > 1
2097 if (combineMode > 1) {
2098 SAL_INFO ("cppcanvas.emf", "EMF+ TODO combine mode > 1");
2100 #endif
2102 float dx, dy, dw, dh;
2104 ReadRectangle (rMF, dx, dy, dw, dh, false);
2106 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
2108 B2DPoint mappedPoint (Map (dx, dy));
2109 B2DSize mappedSize( MapSize (dw, dh));
2111 ::basegfx::B2DPolyPolygon polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromRect( ::basegfx::B2DRectangle( mappedPoint.getX(), mappedPoint.getY(),
2112 mappedPoint.getX() + mappedSize.getX(),
2113 mappedPoint.getY() + mappedSize.getY() ) ) ) );
2114 polyPolygon.transform(rState.mapModeTransform);
2116 updateClipping (polyPolygon, rFactoryParms, combineMode == 1);
2118 break;
2120 case EmfPlusRecordTypeSetClipPath:
2122 int combineMode = (flags >> 8) & 0xf;
2124 SAL_INFO("cppcanvas.emf", "EMF+ SetClipPath combine mode: " << combineMode);
2125 SAL_INFO("cppcanvas.emf", "EMF+\tpath in slot: " << (flags & 0xff));
2127 EMFPPath& path = *(EMFPPath*) aObjects [flags & 0xff];
2128 ::basegfx::B2DPolyPolygon& clipPoly (path.GetPolygon (*this));
2130 clipPoly.transform (rState.mapModeTransform);
2131 updateClipping (clipPoly, rFactoryParms, combineMode == 1);
2133 break;
2135 case EmfPlusRecordTypeSetClipRegion: {
2136 int combineMode = (flags >> 8) & 0xf;
2138 SAL_INFO("cppcanvas.emf", "EMF+ SetClipRegion");
2139 SAL_INFO("cppcanvas.emf", "EMF+\tregion in slot: " << (flags & 0xff) << " combine mode: " << combineMode);
2140 EMFPRegion *region = (EMFPRegion*)aObjects [flags & 0xff];
2142 // reset clip
2143 if (region && region->parts == 0 && region->initialState == EmfPlusRegionInitialStateInfinite) {
2144 updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms, combineMode == 1);
2145 } else {
2146 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2148 break;
2150 case EmfPlusRecordTypeDrawDriverString: {
2151 SAL_INFO("cppcanvas.emf", "EMF+ DrawDriverString, flags: 0x" << std::hex << flags << std::dec);
2152 sal_uInt32 brushIndexOrColor;
2153 sal_uInt32 optionFlags;
2154 sal_uInt32 hasMatrix;
2155 sal_uInt32 glyphsCount;
2157 rMF >> brushIndexOrColor >> optionFlags >> hasMatrix >> glyphsCount;
2159 SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags & 0x8000) ? "color" : "brush index") << " 0x" << std::hex << brushIndexOrColor << std::dec);
2160 SAL_INFO("cppcanvas.emf", "EMF+\toption flags: 0x" << std::hex << optionFlags << std::dec);
2161 SAL_INFO("cppcanvas.emf", "EMF+\thas matrix: " << hasMatrix);
2162 SAL_INFO("cppcanvas.emf", "EMF+\tglyphs: " << glyphsCount);
2164 if( ( optionFlags & 1 ) && glyphsCount > 0 ) {
2165 float *charsPosX = new float[glyphsCount];
2166 float *charsPosY = new float[glyphsCount];
2168 OUString text = read_uInt16s_ToOUString(rMF, glyphsCount);
2170 for( sal_uInt32 i=0; i<glyphsCount; i++) {
2171 rMF >> charsPosX[i] >> charsPosY[i];
2172 SAL_INFO("cppcanvas.emf", "EMF+\tglyphPosition[" << i << "]: " << charsPosX[i] << "," << charsPosY[i]);
2175 XForm transform;
2176 if( hasMatrix ) {
2177 rMF >> transform;
2178 SAL_INFO("cppcanvas.emf", "EMF+\tmatrix: " << transform.eM11 << ", " << transform.eM12 << ", " << transform.eM21 << ", " << transform.eM22 << ", " << transform.eDx << ", " << transform.eDy);
2181 // add the text action
2182 setFont (flags & 0xff, rFactoryParms, rState);
2184 if( flags & 0x8000 )
2185 rState.textColor = COLOR( brushIndexOrColor );
2187 ::basegfx::B2DPoint point( Map( charsPosX[0], charsPosY[0] ) );
2189 ActionSharedPtr pTextAction(
2190 TextActionFactory::createTextAction(
2191 ::vcl::unotools::pointFromB2DPoint ( point ),
2192 ::Size(),
2193 ::Color(),
2194 ::Size(),
2195 ::Color(),
2196 text,
2198 glyphsCount,
2199 NULL,
2200 rFactoryParms.mrVDev,
2201 rFactoryParms.mrCanvas,
2202 rState,
2203 rFactoryParms.mrParms,
2204 false ) );
2206 if( pTextAction )
2208 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
2210 maActions.push_back(
2211 MtfAction(
2212 pTextAction,
2213 rFactoryParms.mrCurrActionIndex ) );
2215 rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
2218 delete[] charsPosX;
2219 delete[] charsPosY;
2220 } else {
2221 SAL_INFO("cppcanvas.emf", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
2224 break;
2226 default:
2227 SAL_INFO("cppcanvas.emf", "EMF+ unhandled record type: " << type);
2228 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2232 rMF.Seek (next);
2234 if (size <= length)
2236 length -= size;
2238 else
2240 SAL_WARN("cppcanvas.emf", "ImplRenderer::processEMFPlus: "
2241 "size " << size << " > length " << length);
2242 #if OSL_DEBUG_LEVEL > 1
2243 dumpWords(rMF, length);
2244 #endif
2245 length = 0;
2252 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */