Bump for 3.6-28
[LibreOffice.git] / cppcanvas / source / mtfrenderer / emfplus.cxx
blobd19d496c6b3396dc676db1445ce05efbe2d61fff
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2010 Novell, Inc.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <tools/stream.hxx>
30 #include <vcl/metaact.hxx>
31 #include <vcl/graphicfilter.hxx>
32 #include <basegfx/tools/canvastools.hxx>
33 #include <basegfx/tools/gradienttools.hxx>
34 #include <basegfx/tools/tools.hxx>
35 #include <basegfx/numeric/ftools.hxx>
36 #include <basegfx/point/b2dpoint.hxx>
37 #include <basegfx/vector/b2dsize.hxx>
38 #include <basegfx/range/b2drange.hxx>
39 #include <basegfx/range/b2drectangle.hxx>
40 #include <basegfx/polygon/b2dpolygon.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <basegfx/polygon/b2dpolypolygon.hxx>
43 #include <basegfx/polygon/b2dpolypolygontools.hxx>
44 #include <vcl/canvastools.hxx>
45 #include <rtl/ustring.hxx>
46 #include <sal/alloca.h>
48 #include <com/sun/star/rendering/XCanvas.hpp>
49 #include <com/sun/star/rendering/TexturingMode.hpp>
51 #include <bitmapaction.hxx>
52 #include <implrenderer.hxx>
53 #include <outdevstate.hxx>
54 #include <polypolyaction.hxx>
55 #include <textaction.hxx>
56 #include <stdio.h>
58 #define EmfPlusRecordTypeHeader 16385
59 #define EmfPlusRecordTypeEndOfFile 16386
60 #define EmfPlusRecordTypeGetDC 16388
61 #define EmfPlusRecordTypeObject 16392
62 #define EmfPlusRecordTypeFillRects 16394
63 #define EmfPlusRecordTypeFillPolygon 16396
64 #define EmfPlusRecordTypeDrawLines 16397
65 #define EmfPlusRecordTypeFillPie 16400
66 #define EmfPlusRecordTypeFillPath 16404
67 #define EmfPlusRecordTypeDrawPath 16405
68 #define EmfPlusRecordTypeDrawImagePoints 16411
69 #define EmfPlusRecordTypeDrawString 16412
70 #define EmfPlusRecordTypeSetRenderingOrigin 16413
71 #define EmfPlusRecordTypeSetAntiAliasMode 16414
72 #define EmfPlusRecordTypeSetTextRenderingHint 16415
73 #define EmfPlusRecordTypeSetInterpolationMode 16417
74 #define EmfPlusRecordTypeSetPixelOffsetMode 16418
75 #define EmfPlusRecordTypeSetCompositingQuality 16420
76 #define EmfPlusRecordTypeSave 16421
77 #define EmfPlusRecordTypeSetWorldTransform 16426
78 #define EmfPlusRecordTypeResetWorldTransform 16427
79 #define EmfPlusRecordTypeMultiplyWorldTransform 16428
80 #define EmfPlusRecordTypeSetPageTransform 16432
81 #define EmfPlusRecordTypeSetClipPath 16435
82 #define EmfPlusRecordTypeSetClipRegion 16436
83 #define EmfPlusRecordTypeDrawDriverString 16438
85 #define EmfPlusObjectTypeBrush 0x100
86 #define EmfPlusObjectTypePen 0x200
87 #define EmfPlusObjectTypePath 0x300
88 #define EmfPlusObjectTypeRegion 0x400
89 #define EmfPlusObjectTypeImage 0x500
90 #define EmfPlusObjectTypeFont 0x600
91 #define EmfPlusObjectTypeStringFormat 0x700
92 #define EmfPlusObjectTypeImageAttributes 0x800
94 #define EmfPlusRegionInitialStateRectangle 0x10000000
95 #define EmfPlusRegionInitialStatePath 0x10000001
96 #define EmfPlusRegionInitialStateEmpty 0x10000002
97 #define EmfPlusRegionInitialStateInfinite 0x10000003
99 #if OSL_DEBUG_LEVEL > 1
100 #define EMFP_DEBUG(x) x
101 #else
102 #define EMFP_DEBUG(x)
103 #endif
105 using namespace ::com::sun::star;
106 using namespace ::basegfx;
108 namespace cppcanvas
110 namespace internal
113 EMFP_DEBUG (void dumpWords (SvStream& s, int i)
115 sal_uInt32 pos = s.Tell ();
116 sal_Int16 data;
117 for (; i > 0; i --) {
118 s >> data;
119 printf ("EMF+\tdata: %04hX\n", data);
121 s.Seek (pos);
124 struct EMFPObject
126 virtual ~EMFPObject() {}
129 struct EMFPPath : public EMFPObject
131 ::basegfx::B2DPolyPolygon aPolygon;
132 sal_Int32 nPoints;
133 float* pPoints;
134 sal_uInt8* pPointTypes;
136 public:
137 EMFPPath (sal_Int32 _nPoints, bool bLines = false)
139 if( _nPoints<0 || sal_uInt32(_nPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
140 _nPoints = SAL_MAX_INT32/(2*sizeof(float));
141 nPoints = _nPoints;
142 pPoints = new float [nPoints*2];
143 if (!bLines)
144 pPointTypes = new sal_uInt8 [_nPoints];
145 else
146 pPointTypes = NULL;
149 ~EMFPPath ()
151 delete [] pPoints;
152 delete [] pPointTypes;
155 // TODO: remove rR argument when debug code is not longer needed
156 void Read (SvStream& s, sal_uInt32 pathFlags, ImplRenderer& rR)
158 for (int i = 0; i < nPoints; i ++) {
159 if (pathFlags & 0x4000) {
160 // points are stored in short 16bit integer format
161 sal_uInt16 x, y;
163 s >> x >> y;
164 EMFP_DEBUG (printf ("EMF+\tpoint [x,y]: %hd,%hd\n", x, y));
165 pPoints [i*2] = x;
166 pPoints [i*2 + 1] = y;
167 } else {
168 // points are stored in Single (float) format
169 s >> pPoints [i*2] >> pPoints [i*2 + 1];
170 EMFP_DEBUG (printf ("EMF+\tpoint [x,y]: %f,%f\n", pPoints [i*2], pPoints [i*2 + 1]));
174 if (pPointTypes)
175 for (int i = 0; i < nPoints; i ++) {
176 s >> pPointTypes [i];
177 EMFP_DEBUG (printf ("EMF+\tpoint type: %x\n", pPointTypes [i]));
180 aPolygon.clear ();
182 // debug code
183 const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (GetPolygon (rR)));
184 EMFP_DEBUG (printf ("EMF+\tpolygon bounding box: %f,%f %fx%f (mapped)\n", aBounds.getMinX (), aBounds.getMinY (), aBounds.getWidth (), aBounds.getHeight ()));
187 ::basegfx::B2DPolyPolygon& GetPolygon (ImplRenderer& rR, bool bMapIt = true)
189 ::basegfx::B2DPolygon polygon;
191 aPolygon.clear ();
193 int last_normal = 0, p = 0;
194 ::basegfx::B2DPoint prev, mapped;
195 bool hasPrev = false;
196 for (int i = 0; i < nPoints; i ++) {
197 if (p && pPointTypes && (pPointTypes [i] == 0)) {
198 aPolygon.append (polygon);
199 last_normal = i;
200 p = 0;
201 polygon.clear ();
204 if (bMapIt)
205 mapped = rR.Map (pPoints [i*2], pPoints [i*2 + 1]);
206 else
207 mapped = ::basegfx::B2DPoint (pPoints [i*2], pPoints [i*2 + 1]);
208 //EMFP_DEBUG (printf ("polygon point: %f,%f mapped: %f,%f\n", pPoints [i*2], pPoints [i*2 + 1], mapped.getX (), mapped.getY ()));
209 if (pPointTypes) {
210 if ((pPointTypes [i] & 0x07) == 3) {
211 if (((i - last_normal )% 3) == 1) {
212 polygon.setNextControlPoint (p - 1, mapped);
213 EMFP_DEBUG (printf ("polygon append next: %d mapped: %f,%f\n", p - 1, mapped.getX (), mapped.getY ()));
214 continue;
215 } else if (((i - last_normal) % 3) == 2) {
216 prev = mapped;
217 hasPrev = true;
218 continue;
220 } else
221 last_normal = i;
223 polygon.append (mapped);
224 EMFP_DEBUG (printf ("polygon append point: %f,%f mapped: %f,%f\n", pPoints [i*2], pPoints [i*2 + 1], mapped.getX (), mapped.getY ()));
225 if (hasPrev) {
226 polygon.setPrevControlPoint (p, prev);
227 EMFP_DEBUG (printf ("polygon append prev: %d mapped: %f,%f\n", p, prev.getX (), prev.getY ()));
228 hasPrev = false;
230 p ++;
231 if (pPointTypes && (pPointTypes [i] & 0x80)) { // closed polygon
232 polygon.setClosed (true);
233 aPolygon.append (polygon);
234 EMFP_DEBUG (printf ("close polygon\n"));
235 last_normal = i + 1;
236 p = 0;
237 polygon.clear ();
241 if (polygon.count ())
242 aPolygon.append (polygon);
244 EMFP_DEBUG (
245 for (unsigned int i=0; i<aPolygon.count(); i++) {
246 polygon = aPolygon.getB2DPolygon(i);
247 printf ("polygon: %d\n", i);
248 for (unsigned int j=0; j<polygon.count(); j++) {
249 ::basegfx::B2DPoint point = polygon.getB2DPoint(j);
250 printf ("point: %f,%f\n", point.getX(), point.getY());
251 if (polygon.isPrevControlPointUsed(j)) {
252 point = polygon.getPrevControlPoint(j);
253 printf ("prev: %f,%f\n", point.getX(), point.getY());
255 if (polygon.isNextControlPointUsed(j)) {
256 point = polygon.getNextControlPoint(j);
257 printf ("next: %f,%f\n", point.getX(), point.getY());
263 return aPolygon;
267 struct EMFPRegion : public EMFPObject
269 sal_Int32 parts;
270 sal_Int32 *combineMode;
271 sal_Int32 initialState;
272 EMFPPath *initialPath;
273 float ix, iy, iw, ih;
275 EMFPRegion ()
277 combineMode = NULL;
278 initialPath = NULL;
281 ~EMFPRegion ()
283 if (combineMode) {
284 delete [] combineMode;
285 combineMode = NULL;
287 if (initialPath) {
288 delete initialPath;
289 initialPath = NULL;
293 void Read (SvStream& s)
295 sal_uInt32 header;
297 s >> header >> parts;
299 EMFP_DEBUG (printf ("EMF+\tregion\n"));
300 EMFP_DEBUG (printf ("EMF+\theader: 0x%08x parts: %d\n", (unsigned int)header, (int)parts));
302 if (parts) {
303 if( parts<0 || sal_uInt32(parts)>SAL_MAX_INT32/sizeof(sal_Int32) )
304 parts = SAL_MAX_INT32/sizeof(sal_Int32);
306 combineMode = new sal_Int32 [parts];
308 for (int i = 0; i < parts; i ++) {
309 s >> combineMode [i];
310 EMFP_DEBUG (printf ("EMF+\tcombine mode [%d]: 0x%08x\n", i,(unsigned int)combineMode [i]));
314 s >> initialState;
315 EMFP_DEBUG (printf ("EMF+\tinitial state: 0x%d\n",(int) initialState));
319 struct EMFPBrush : public EMFPObject
321 ::Color solidColor;
322 sal_uInt32 type;
323 sal_uInt32 additionalFlags;
325 /* linear gradient */
326 sal_Int32 wrapMode;
327 float areaX, areaY, areaWidth, areaHeight;
328 ::Color secondColor; // first color is stored in solidColor;
329 XForm transformation;
330 bool hasTransformation;
331 sal_Int32 blendPoints;
332 float* blendPositions;
333 float* blendFactors;
334 sal_Int32 colorblendPoints;
335 float* colorblendPositions;
336 ::Color* colorblendColors;
337 sal_Int32 surroundColorsNumber;
338 ::Color* surroundColors;
339 EMFPPath *path;
341 public:
342 EMFPBrush ()
344 blendPositions = NULL;
345 colorblendPositions = NULL;
346 colorblendColors = NULL;
347 surroundColors = NULL;
348 path = NULL;
349 hasTransformation = false;
352 ~EMFPBrush ()
354 if (blendPositions != NULL) {
355 delete[] blendPositions;
356 blendPositions = NULL;
358 if (colorblendPositions != NULL) {
359 delete[] colorblendPositions;
360 colorblendPositions = NULL;
362 if (colorblendColors != NULL) {
363 delete[] colorblendColors;
364 colorblendColors = NULL;
366 if (surroundColors != NULL) {
367 delete[] surroundColors;
368 surroundColors = NULL;
370 if (path) {
371 delete path;
372 path = NULL;
376 sal_uInt32 GetType() const { return type; }
377 const ::Color& GetColor() const { return solidColor; }
379 void Read (SvStream& s, ImplRenderer& rR)
381 sal_uInt32 header;
383 s >> header >> type;
385 EMFP_DEBUG (printf ("EMF+\tbrush\nEMF+\theader: 0x%08x type: %d\n",(unsigned int) header,(int) type));
387 switch (type) {
388 case 0:
390 sal_uInt32 color;
392 s >> color;
393 solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
394 EMFP_DEBUG (printf ("EMF+\tsolid color: 0x%08x\n", (unsigned int)color));
396 break;
398 // path gradient
399 case 3:
401 s >> additionalFlags >> wrapMode;
403 EMFP_DEBUG (printf ("EMF+\tpath gradient, additional flags: 0x%02x\n",(unsigned int) additionalFlags));
405 sal_uInt32 color;
407 s >> color;
408 solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
409 EMFP_DEBUG (printf ("EMF+\tcenter color: 0x%08x\n",(unsigned int) color));
411 s >> areaX >> areaY;
412 EMFP_DEBUG (printf ("EMF+\tcenter point: %f,%f\n", areaX, areaY));
414 s >> surroundColorsNumber;
415 EMFP_DEBUG (printf ("EMF+\tsurround colors: %d\n",(int) surroundColorsNumber));
417 if( surroundColorsNumber<0 || sal_uInt32(surroundColorsNumber)>SAL_MAX_INT32/sizeof(::Color) )
418 surroundColorsNumber = SAL_MAX_INT32/sizeof(::Color);
420 surroundColors = new ::Color [surroundColorsNumber];
421 for (int i = 0; i < surroundColorsNumber; i++) {
422 s >> color;
423 surroundColors[i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
424 if (i == 0)
425 secondColor = surroundColors [0];
426 EMFP_DEBUG (printf ("EMF+\tsurround color[%d]: 0x%08x\n", i, (unsigned int)color));
429 if (additionalFlags & 0x01) {
430 sal_Int32 pathLength;
432 s >> pathLength;
433 EMFP_DEBUG (printf ("EMF+\tpath length: %d\n", (int)pathLength));
435 sal_uInt32 pos = s.Tell ();
436 EMFP_DEBUG (dumpWords (s, 32));
438 sal_uInt32 pathHeader;
439 sal_Int32 pathPoints, pathFlags;
440 s >> pathHeader >> pathPoints >> pathFlags;
442 EMFP_DEBUG (printf ("EMF+\tpath (brush path gradient)\n"));
443 EMFP_DEBUG (printf ("EMF+\theader: 0x%08x points: %d additional flags: 0x%d\n", (unsigned int)pathHeader, (int)pathPoints, (int)pathFlags));
445 path = new EMFPPath (pathPoints);
446 path->Read (s, pathFlags, rR);
448 s.Seek (pos + pathLength);
450 const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (path->GetPolygon (rR, false)));
451 areaWidth = aBounds.getWidth ();
452 areaHeight = aBounds.getHeight ();
454 EMFP_DEBUG (printf ("EMF+\tpolygon bounding box: %f,%f %fx%f\n", aBounds.getMinX (), aBounds.getMinY (), aBounds.getWidth (), aBounds.getHeight ()));
457 if (additionalFlags & 0x02) {
458 EMFP_DEBUG (printf ("EMF+\tuse transformation\n"));
459 s >> transformation;
460 hasTransformation = true;
461 EMFP_DEBUG (printf ("EMF+\tm11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n",
462 transformation.eM11, transformation.eM12,
463 transformation.eM21, transformation.eM22,
464 transformation.eDx, transformation.eDy));
466 if (additionalFlags & 0x08) {
467 s >> blendPoints;
468 EMFP_DEBUG (printf ("EMF+\tuse blend, points: %d\n", (int)blendPoints));
469 if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
470 blendPoints = SAL_MAX_INT32/(2*sizeof(float));
471 blendPositions = new float [2*blendPoints];
472 blendFactors = blendPositions + blendPoints;
473 for (int i=0; i < blendPoints; i ++) {
474 s >> blendPositions [i];
475 EMFP_DEBUG (printf ("EMF+\tposition[%d]: %f\n", i, blendPositions [i]));
477 for (int i=0; i < blendPoints; i ++) {
478 s >> blendFactors [i];
479 EMFP_DEBUG (printf ("EMF+\tfactor[%d]: %f\n", i, blendFactors [i]));
483 if (additionalFlags & 0x04) {
484 s >> colorblendPoints;
485 EMFP_DEBUG (printf ("EMF+\tuse color blend, points: %d\n", (int)colorblendPoints));
486 if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
487 colorblendPoints = SAL_MAX_INT32/sizeof(float);
488 if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
489 colorblendPoints = SAL_MAX_INT32/sizeof(::Color);
490 colorblendPositions = new float [colorblendPoints];
491 colorblendColors = new ::Color [colorblendPoints];
492 for (int i=0; i < colorblendPoints; i ++) {
493 s >> colorblendPositions [i];
494 EMFP_DEBUG (printf ("EMF+\tposition[%d]: %f\n", i, colorblendPositions [i]));
496 for (int i=0; i < colorblendPoints; i ++) {
497 s >> color;
498 colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
499 EMFP_DEBUG (printf ("EMF+\tcolor[%d]: 0x%08x\n", i,(unsigned int) color));
502 } else {
503 EMFP_DEBUG (dumpWords (s, 1024));
505 break;
507 // linear gradient
508 case 4:
510 s >> additionalFlags >> wrapMode;
512 EMFP_DEBUG (printf ("EMF+\tlinear gradient, additional flags: 0x%02x\n", (unsigned int)additionalFlags));
514 s >> areaX >> areaY >> areaWidth >> areaHeight;
516 EMFP_DEBUG (printf ("EMF+\tarea: %f,%f - %fx%f\n", areaX, areaY, areaWidth, areaHeight));
518 sal_uInt32 color;
520 s >> color;
521 solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
522 EMFP_DEBUG (printf ("EMF+\tfirst color: 0x%08x\n", color));
524 s >> color;
525 secondColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
526 EMFP_DEBUG (printf ("EMF+\tsecond color: 0x%08x\n", color));
528 // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
529 s >> color;
530 s >> color;
532 if (additionalFlags & 0x02) {
533 EMFP_DEBUG (printf ("EMF+\tuse transformation\n"));
534 s >> transformation;
535 hasTransformation = true;
536 EMFP_DEBUG (printf ("EMF+\tm11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n",
537 transformation.eM11, transformation.eM12,
538 transformation.eM21, transformation.eM22,
539 transformation.eDx, transformation.eDy));
541 if (additionalFlags & 0x08) {
542 s >> blendPoints;
543 EMFP_DEBUG (printf ("EMF+\tuse blend, points: %d\n", (int)blendPoints));
544 if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
545 blendPoints = SAL_MAX_INT32/(2*sizeof(float));
546 blendPositions = new float [2*blendPoints];
547 blendFactors = blendPositions + blendPoints;
548 for (int i=0; i < blendPoints; i ++) {
549 s >> blendPositions [i];
550 EMFP_DEBUG (printf ("EMF+\tposition[%d]: %f\n", i, blendPositions [i]));
552 for (int i=0; i < blendPoints; i ++) {
553 s >> blendFactors [i];
554 EMFP_DEBUG (printf ("EMF+\tfactor[%d]: %f\n", i, blendFactors [i]));
558 if (additionalFlags & 0x04) {
559 s >> colorblendPoints;
560 EMFP_DEBUG (printf ("EMF+\tuse color blend, points: %d\n", (int)colorblendPoints));
561 if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
562 colorblendPoints = SAL_MAX_INT32/sizeof(float);
563 if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
564 colorblendPoints = sal_uInt32(SAL_MAX_INT32)/sizeof(::Color);
565 colorblendPositions = new float [colorblendPoints];
566 colorblendColors = new ::Color [colorblendPoints];
567 for (int i=0; i < colorblendPoints; i ++) {
568 s >> colorblendPositions [i];
569 EMFP_DEBUG (printf ("EMF+\tposition[%d]: %f\n", i, colorblendPositions [i]));
571 for (int i=0; i < colorblendPoints; i ++) {
572 s >> color;
573 colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
574 EMFP_DEBUG (printf ("EMF+\tcolor[%d]: 0x%08x\n", i, (unsigned int)color));
578 break;
580 default:
581 EMFP_DEBUG (printf ("EMF+\tunhandled brush type: %08x\n", (unsigned int)type));
586 struct EMFPPen : public EMFPBrush
588 XForm transformation;
589 float width;
590 sal_Int32 startCap;
591 sal_Int32 endCap;
592 sal_Int32 lineJoin;
593 float mitterLimit;
594 sal_Int32 dashStyle;
595 sal_Int32 dashCap;
596 float dashOffset;
597 sal_Int32 dashPatternLen;
598 float *dashPattern;
599 sal_Int32 alignment;
600 sal_Int32 compoundArrayLen;
601 float *compoundArray;
602 sal_Int32 customStartCapLen;
603 sal_uInt8 *customStartCap;
604 sal_Int32 customEndCapLen;
605 sal_uInt8 *customEndCap;
607 public:
608 EMFPPen () : EMFPBrush ()
612 void SetStrokeAttributes (rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
614 EMFP_DEBUG (if (width == 0.0) printf ("EMF+\tTODO: pen with zero width - using minimal which might not be correct\n"));
615 rStrokeAttributes.StrokeWidth = (rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getX ();
618 void Read (SvStream& s, ImplRenderer& rR, sal_Int32, sal_Int32 )
620 sal_uInt32 header, unknown, penFlags, unknown2;
621 int i;
623 s >> header >> unknown >> penFlags >> unknown2 >> width;
625 EMFP_DEBUG (printf ("EMF+\tpen\nEMF+\theader: 0x%08x unknown: 0x%08x additional flags: 0x%08x unknown: 0x%08x width: %f\n", (unsigned int)header, (unsigned int)unknown, (unsigned int)penFlags,(unsigned int) unknown2, width));
627 if (penFlags & 1)
628 s >> transformation;
630 if (penFlags & 2)
631 s >> startCap;
632 else
633 startCap = 0;
635 if (penFlags & 4)
636 s >> endCap;
637 else
638 endCap = 0;
640 if (penFlags & 8)
641 s >> lineJoin;
642 else
643 lineJoin = 0;
645 if (penFlags & 16)
646 s >> mitterLimit;
647 else
648 mitterLimit = 0;
650 if (penFlags & 32)
651 s >> dashStyle;
652 else
653 dashStyle = 0;
655 if (penFlags & 64)
656 s >> dashCap;
657 else
658 dashCap = 0;
660 if (penFlags & 128)
661 s >> dashOffset;
662 else
663 dashOffset = 0;
665 if (penFlags & 256) {
666 s >> dashPatternLen;
667 if( dashPatternLen<0 || sal_uInt32(dashPatternLen)>SAL_MAX_INT32/sizeof(float) )
668 dashPatternLen = SAL_MAX_INT32/sizeof(float);
669 dashPattern = new float [dashPatternLen];
670 for (i = 0; i < dashPatternLen; i++)
671 s >> dashPattern [i];
672 } else
673 dashPatternLen = 0;
675 if (penFlags & 512)
676 s >> alignment;
677 else
678 alignment = 0;
680 if (penFlags & 1024) {
681 s >> compoundArrayLen;
682 if( compoundArrayLen<0 || sal_uInt32(compoundArrayLen)>SAL_MAX_INT32/sizeof(float) )
683 compoundArrayLen = SAL_MAX_INT32/sizeof(float);
684 compoundArray = new float [compoundArrayLen];
685 for (i = 0; i < compoundArrayLen; i++)
686 s >> compoundArray [i];
687 } else
688 compoundArrayLen = 0;
690 if (penFlags & 2048) {
691 s >> customStartCapLen;
692 if( customStartCapLen<0 )
693 customStartCapLen=0;
694 customStartCap = new sal_uInt8 [customStartCapLen];
695 for (i = 0; i < customStartCapLen; i++)
696 s >> customStartCap [i];
697 } else
698 customStartCapLen = 0;
700 if (penFlags & 4096) {
701 s >> customEndCapLen;
702 if( customEndCapLen<0 )
703 customEndCapLen=0;
704 customEndCap = new sal_uInt8 [customEndCapLen];
705 for (i = 0; i < customEndCapLen; i++)
706 s >> customEndCap [i];
707 } else
708 customEndCapLen = 0;
710 EMFPBrush::Read (s, rR);
714 struct EMFPImage : public EMFPObject
716 sal_uInt32 type;
717 sal_Int32 width;
718 sal_Int32 height;
719 sal_Int32 stride;
720 sal_Int32 pixelFormat;
721 Graphic graphic;
724 void Read (SvMemoryStream &s, sal_Bool bUseWholeStream)
726 sal_uInt32 header, unknown;
728 s >> header >> type;
730 EMFP_DEBUG (printf ("EMF+\timage\nEMF+\theader: 0x%08x type: 0x%08x\n", header, type));
732 if (type == 1) { // bitmap
733 s >> width >> height >> stride >> pixelFormat >> unknown;
734 EMFP_DEBUG (printf ("EMF+\tbitmap width: %d height: %d stride: %d pixelFormat: 0x%08x\n", width, height, stride, pixelFormat));
735 if (width == 0) { // non native formats
736 GraphicFilter filter;
738 filter.ImportGraphic (graphic, String (), s);
739 EMFP_DEBUG (printf ("EMF+\tbitmap width: %ld height: %ld\n", graphic.GetBitmap ().GetSizePixel ().Width (), graphic.GetBitmap ().GetSizePixel ().Height ()));
742 } else if (type == 2) {
743 sal_Int32 mfType, mfSize;
745 s >> mfType >> mfSize;
746 EMFP_DEBUG (printf ("EMF+\tmetafile type: %d dataSize: %d\n", mfType, mfSize));
748 GraphicFilter filter;
749 // workaround buggy metafiles, which have wrong mfSize set (n#705956 for example)
750 SvMemoryStream mfStream (((char *)s.GetData()) + s.Tell(), bUseWholeStream ? s.remainingSize() : mfSize, STREAM_READ);
752 filter.ImportGraphic (graphic, String (), mfStream);
754 // debug code - write the stream to debug file /tmp/emf-stream.emf
755 EMFP_DEBUG(
756 mfStream.Seek(0);
757 static int emfp_debug_stream_numnber = 0;
758 rtl::OUString emfp_debug_filename("/tmp/emf-embedded-stream");
759 emfp_debug_filename += rtl::OUString::valueOf(emfp_debug_stream_numnber++);
760 emfp_debug_filename += rtl::OUString(".emf");
762 SvFileStream file( emfp_debug_filename, STREAM_WRITE | STREAM_TRUNC );
764 mfStream >> file;
765 file.Flush();
766 file.Close()
772 struct EMFPFont : public EMFPObject
774 sal_uInt32 version;
775 float emSize;
776 sal_uInt32 sizeUnit;
777 sal_Int32 fontFlags;
778 rtl::OUString family;
780 void Read (SvMemoryStream &s)
782 sal_uInt32 header;
783 sal_uInt32 reserved;
784 sal_uInt32 length;
786 s >> header >> emSize >> sizeUnit >> fontFlags >> reserved >> length;
788 OSL_ASSERT( ( header >> 12 ) == 0xdbc01 );
790 EMFP_DEBUG (printf ("EMF+\tfont\nEMF+\theader: 0x%08x version: 0x%08x size: %f unit: 0x%08x\n",(unsigned int) header >> 12, (unsigned int)header & 0x1fff, emSize, (unsigned int)sizeUnit));
791 EMFP_DEBUG (printf ("EMF+\tflags: 0x%08x reserved: 0x%08x length: 0x%08x\n", (unsigned int)fontFlags, (unsigned int)reserved, (unsigned int)length));
793 if( length > 0 && length < 0x4000 ) {
794 sal_Unicode *chars = (sal_Unicode *) alloca( sizeof( sal_Unicode ) * length );
796 for( sal_uInt32 i = 0; i < length; i++ )
797 s >> chars[ i ];
799 family = ::rtl::OUString( chars, length );
800 EMFP_DEBUG (printf ("EMF+\tfamily: %s\n", rtl::OUStringToOString( family, RTL_TEXTENCODING_UTF8).getStr()));
805 void ImplRenderer::ReadRectangle (SvStream& s, float& x, float& y, float &width, float& height, sal_uInt32 flags)
807 if (flags & 0x4000) {
808 sal_Int16 ix, iy, iw, ih;
810 s >> ix >> iy >> iw >> ih;
812 x = ix;
813 y = iy;
814 width = iw;
815 height = ih;
816 } else
817 s >> x >> y >> width >> height;
820 void ImplRenderer::ReadPoint (SvStream& s, float& x, float& y, sal_uInt32 flags)
822 if (flags & 0x4000) {
823 sal_Int16 ix, iy;
825 s >> ix >> iy;
827 x = ix;
828 y = iy;
829 } else
830 s >> x >> y;
833 void ImplRenderer::MapToDevice (double& x, double& y)
835 // TODO: other untis
836 x = 100*nMmX*x/nPixX;
837 y = 100*nMmY*y/nPixY;
840 ::basegfx::B2DPoint ImplRenderer::Map (double ix, double iy)
842 double x, y;
844 x = ix*aWorldTransform.eM11 + iy*aWorldTransform.eM21 + aWorldTransform.eDx;
845 y = ix*aWorldTransform.eM12 + iy*aWorldTransform.eM22 + aWorldTransform.eDy;
847 MapToDevice (x, y);
849 x -= nFrameLeft;
850 y -= nFrameTop;
852 x *= aBaseTransform.eM11;
853 y *= aBaseTransform.eM22;
855 return ::basegfx::B2DPoint (x, y);
858 ::basegfx::B2DSize ImplRenderer::MapSize (double iwidth, double iheight)
860 double w, h;
862 w = iwidth*aWorldTransform.eM11 + iheight*aWorldTransform.eM21;
863 h = iwidth*aWorldTransform.eM12 + iheight*aWorldTransform.eM22;
865 MapToDevice (w, h);
867 w *= aBaseTransform.eM11;
868 h *= aBaseTransform.eM22;
870 return ::basegfx::B2DSize (w, h);
873 #define COLOR(x) \
874 ::vcl::unotools::colorToDoubleSequence( ::Color (0xff - (x >> 24), \
875 (x >> 16) & 0xff, \
876 (x >> 8) & 0xff, \
877 x & 0xff), \
878 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
879 #define SET_FILL_COLOR(x) \
880 rState.fillColor = COLOR(x);
881 #define SET_LINE_COLOR(x) \
882 rState.lineColor = COLOR(x);
883 #define SET_TEXT_COLOR(x) \
884 rState.textColor = COLOR(x);
886 void ImplRenderer::EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
887 OutDevState& rState, const CanvasSharedPtr& rCanvas, bool isColor, sal_uInt32 brushIndexOrColor)
889 ::basegfx::B2DPolyPolygon localPolygon (polygon);
891 EMFP_DEBUG (printf ("EMF+\tfill polygon\n"));
893 localPolygon.transform( rState.mapModeTransform );
895 ActionSharedPtr pPolyAction;
897 if (isColor) {
898 EMFP_DEBUG (printf ("EMF+\t\tcolor fill\n"));
900 rState.isFillColorSet = true;
901 rState.isLineColorSet = false;
902 SET_FILL_COLOR(brushIndexOrColor);
904 pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) );
906 } else {
907 rState.isFillColorSet = true;
908 // extract UseBrush
909 EMFPBrush* brush = (EMFPBrush*) aObjects [brushIndexOrColor & 0xff];
910 EMFP_DEBUG (printf ("EMF+\tbrush fill slot: %u (type: %u)\n", (unsigned int)brushIndexOrColor, (unsigned int)brush->GetType ()));
912 // give up in case something wrong happened
913 if( !brush )
914 return;
916 rState.isFillColorSet = false;
917 rState.isLineColorSet = false;
919 if (brush->type == 3 || brush->type == 4) {
921 if (brush->type == 3 && !(brush->additionalFlags & 0x1))
922 return; // we are unable to parse these brushes yet
924 ::basegfx::B2DHomMatrix aTextureTransformation;
925 ::basegfx::B2DHomMatrix aWorldTransformation;
926 ::basegfx::B2DHomMatrix aBaseTransformation;
927 rendering::Texture aTexture;
929 aWorldTransformation.set (0, 0, aWorldTransform.eM11);
930 aWorldTransformation.set (0, 1, aWorldTransform.eM21);
931 aWorldTransformation.set (0, 2, aWorldTransform.eDx);
932 aWorldTransformation.set (1, 0, aWorldTransform.eM12);
933 aWorldTransformation.set (1, 1, aWorldTransform.eM22);
934 aWorldTransformation.set (1, 2, aWorldTransform.eDy);
936 aBaseTransformation.set (0, 0, aBaseTransform.eM11);
937 aBaseTransformation.set (0, 1, aBaseTransform.eM21);
938 aBaseTransformation.set (0, 2, aBaseTransform.eDx);
939 aBaseTransformation.set (1, 0, aBaseTransform.eM12);
940 aBaseTransformation.set (1, 1, aBaseTransform.eM22);
941 aBaseTransformation.set (1, 2, aBaseTransform.eDy);
943 if (brush->type == 4) {
944 aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
945 aTextureTransformation.translate (brush->areaX, brush->areaY);
946 } else {
947 aTextureTransformation.translate (-0.5, -0.5);
948 aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
949 aTextureTransformation.translate (brush->areaX,brush->areaY);
952 if (brush->hasTransformation) {
953 ::basegfx::B2DHomMatrix aTransformation;
955 aTransformation.set (0, 0, brush->transformation.eM11);
956 aTransformation.set (0, 1, brush->transformation.eM21);
957 aTransformation.set (0, 2, brush->transformation.eDx);
958 aTransformation.set (1, 0, brush->transformation.eM12);
959 aTransformation.set (1, 1, brush->transformation.eM22);
960 aTransformation.set (1, 2, brush->transformation.eDy);
962 aTextureTransformation *= aTransformation;
965 aTextureTransformation *= aWorldTransformation;
966 aTextureTransformation.scale (100.0*nMmX/nPixX, 100.0*nMmY/nPixY);
967 aTextureTransformation.translate (-nFrameLeft, -nFrameTop);
968 aTextureTransformation *= rState.mapModeTransform;
969 aTextureTransformation *= aBaseTransformation;
971 aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
972 aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
973 aTexture.Alpha = 1.0;
975 basegfx::ODFGradientInfo aGradInfo;
976 rtl::OUString aGradientService;
978 const uno::Sequence< double > aStartColor(
979 ::vcl::unotools::colorToDoubleSequence( brush->solidColor,
980 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
981 const uno::Sequence< double > aEndColor(
982 ::vcl::unotools::colorToDoubleSequence( brush->secondColor,
983 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
984 uno::Sequence< uno::Sequence < double > > aColors (2);
985 uno::Sequence< double > aStops (2);
987 if (brush->blendPositions) {
988 EMFP_DEBUG (printf ("EMF+\t\tuse blend\n"));
989 aColors.realloc (brush->blendPoints);
990 aStops.realloc (brush->blendPoints);
991 int length = aStartColor.getLength ();
992 uno::Sequence< double > aColor (length);
994 OSL_ASSERT (length == aEndColor.getLength());
996 for (int i = 0; i < brush->blendPoints; i++) {
997 aStops[i] = brush->blendPositions [i];
999 for (int j = 0; j < length; j++) {
1000 if (brush->type == 4) {
1001 // // gamma correction
1002 // if (brush->additionalFlags & 0x80)
1003 // aColor [j] = pow (aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i], 1/2.2);
1004 // else
1005 aColor [j] = aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i];
1006 } else
1007 aColor [j] = aStartColor [j]*brush->blendFactors[i] + aEndColor [j]*(1 - brush->blendFactors[i]);
1010 aColors[i] = aColor;
1012 } else if (brush->colorblendPositions) {
1013 EMFP_DEBUG (printf ("EMF+\t\tuse color blend\n"));
1014 aColors.realloc (brush->colorblendPoints);
1015 aStops.realloc (brush->colorblendPoints);
1017 for (int i = 0; i < brush->colorblendPoints; i++) {
1018 aStops[i] = brush->colorblendPositions [i];
1019 aColors[(brush->type == 4) ? i : brush->colorblendPoints - 1 - i] = ::vcl::unotools::colorToDoubleSequence( brush->colorblendColors [i],
1020 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
1022 } else {
1023 aStops[0] = 0.0;
1024 aStops[1] = 1.0;
1026 if (brush->type == 4) {
1027 aColors[0] = aStartColor;
1028 aColors[1] = aEndColor;
1029 } else {
1030 aColors[1] = aStartColor;
1031 aColors[0] = aEndColor;
1035 EMFP_DEBUG (printf ("EMF+\t\tset gradient\n"));
1036 basegfx::B2DRange aBoundsRectangle (0, 0, 1, 1);
1037 if (brush->type == 4) {
1038 aGradientService = "LinearGradient";
1039 basegfx::tools::createLinearODFGradientInfo( aGradInfo,
1040 aBoundsRectangle,
1041 aStops.getLength(),
1043 0 );
1045 } else {
1046 aGradientService = "EllipticalGradient";
1047 basegfx::tools::createEllipticalODFGradientInfo( aGradInfo,
1048 aBoundsRectangle,
1049 ::basegfx::B2DVector( 0, 0 ),
1050 aStops.getLength(),
1052 0 );
1055 uno::Reference< lang::XMultiServiceFactory > xFactory(
1056 rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
1058 if( xFactory.is() ) {
1059 uno::Sequence<uno::Any> args( 3 );
1060 beans::PropertyValue aProp;
1061 aProp.Name = "Colors";
1062 aProp.Value <<= aColors;
1063 args[0] <<= aProp;
1064 aProp.Name = "Stops";
1065 aProp.Value <<= aStops;
1066 args[1] <<= aProp;
1067 aProp.Name = "AspectRatio";
1068 aProp.Value <<= static_cast<sal_Int32>(1);
1069 args[2] <<= aProp;
1071 aTexture.Gradient.set(
1072 xFactory->createInstanceWithArguments( aGradientService,
1073 args ),
1074 uno::UNO_QUERY);
1077 ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
1078 aTextureTransformation );
1080 if( aTexture.Gradient.is() )
1081 pPolyAction =
1082 ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon,
1083 rParms.mrCanvas,
1084 rState,
1085 aTexture ) );
1089 if( pPolyAction )
1091 EMFP_DEBUG (printf ("EMF+\t\tadd poly action\n"));
1093 maActions.push_back(
1094 MtfAction(
1095 pPolyAction,
1096 rParms.mrCurrActionIndex ) );
1098 rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1102 void ImplRenderer::processObjectRecord(SvMemoryStream& rObjectStream, sal_uInt16 flags, sal_Bool bUseWholeStream)
1104 sal_uInt32 index;
1106 EMFP_DEBUG (printf ("EMF+ Object slot: %hd flags: %hx\n", flags & 0xff, flags & 0xff00));
1108 index = flags & 0xff;
1109 if (aObjects [index] != NULL) {
1110 delete aObjects [index];
1111 aObjects [index] = NULL;
1114 switch (flags & 0x7f00) {
1115 case EmfPlusObjectTypeBrush:
1117 EMFPBrush *brush;
1118 aObjects [index] = brush = new EMFPBrush ();
1119 brush->Read (rObjectStream, *this);
1121 break;
1123 case EmfPlusObjectTypePen:
1125 EMFPPen *pen;
1126 aObjects [index] = pen = new EMFPPen ();
1127 pen->Read (rObjectStream, *this, nHDPI, nVDPI);
1129 break;
1131 case EmfPlusObjectTypePath:
1132 sal_uInt32 header, pathFlags;
1133 sal_Int32 points;
1135 rObjectStream >> header >> points >> pathFlags;
1137 EMFP_DEBUG (printf ("EMF+\tpath\n"));
1138 EMFP_DEBUG (printf ("EMF+\theader: 0x%08x points: %d additional flags: 0x%08x\n", (unsigned int)header, (int)points, (unsigned int)pathFlags));
1140 EMFPPath *path;
1141 aObjects [index] = path = new EMFPPath (points);
1142 path->Read (rObjectStream, pathFlags, *this);
1144 break;
1145 case EmfPlusObjectTypeRegion: {
1146 EMFPRegion *region;
1148 aObjects [index] = region = new EMFPRegion ();
1149 region->Read (rObjectStream);
1151 break;
1153 case EmfPlusObjectTypeImage:
1155 EMFPImage *image;
1156 aObjects [index] = image = new EMFPImage ();
1157 image->Read (rObjectStream, bUseWholeStream);
1159 break;
1161 case EmfPlusObjectTypeFont:
1163 EMFPFont *font;
1164 aObjects [index] = font = new EMFPFont ();
1165 font->Read (rObjectStream);
1167 break;
1169 default:
1170 EMFP_DEBUG (printf ("EMF+\tObject unhandled flags: 0x%04x\n", flags & 0xff00));
1171 break;
1175 static XubString readString (SvMemoryStream& rMF, sal_uInt32 stringLength)
1177 sal_uInt16 *chars = new sal_uInt16[stringLength];
1179 for( sal_uInt32 i=0; i<stringLength; i++) {
1180 rMF >> chars[i];
1181 EMFP_DEBUG (printf ("EMF+\tglyph[%u]: 0x%04x\n",
1182 (unsigned int)i, chars[i]));
1185 // create and add the text action
1186 XubString text( chars, stringLength );
1188 delete[] chars;
1190 return text;
1193 double ImplRenderer::setFont (sal_uInt8 objectId, const ActionFactoryParameters& rParms, OutDevState& rState)
1195 EMFPFont *font = (EMFPFont*) aObjects[ objectId ];
1197 rendering::FontRequest aFontRequest;
1198 aFontRequest.FontDescription.FamilyName = font->family;
1199 double cellSize = font->emSize;
1200 aFontRequest.CellSize = (rState.mapModeTransform*MapSize( cellSize, 0 )).getX();
1201 rState.xFont = rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest,
1202 uno::Sequence< beans::PropertyValue >(),
1203 geometry::Matrix2D() );
1205 return cellSize;
1208 void ImplRenderer::processEMFPlus( MetaCommentAction* pAct, const ActionFactoryParameters& rFactoryParms,
1209 OutDevState& rState, const CanvasSharedPtr& rCanvas )
1211 sal_uInt32 length = pAct->GetDataSize ();
1212 SvMemoryStream rMF ((void*) pAct->GetData (), length, STREAM_READ);
1214 length -= 4;
1216 while (length > 0) {
1217 sal_uInt16 type, flags;
1218 sal_uInt32 size, dataSize;
1219 sal_uInt32 next;
1221 rMF >> type >> flags >> size >> dataSize;
1223 next = rMF.Tell() + ( size - 12 );
1225 EMFP_DEBUG (printf ("EMF+ record size: %u type: %04hx flags: %04hx data size: %u\n", (unsigned int)size, type, flags, (unsigned int)dataSize));
1227 if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000))) {
1228 if (!mbMultipart) {
1229 mbMultipart = true;
1230 mMFlags = flags;
1231 mMStream.Seek(0);
1234 // 1st 4 bytes are unknown
1235 mMStream.Write (((const char *)rMF.GetData()) + rMF.Tell() + 4, dataSize - 4);
1236 EMFP_DEBUG (printf ("EMF+ read next object part size: %u type: %04hx flags: %04hx data size: %u\n", (unsigned int)size, type, flags, (unsigned int)dataSize));
1237 } else {
1238 if (mbMultipart) {
1239 EMFP_DEBUG (printf ("EMF+ multipart record flags: %04hx\n", mMFlags));
1240 mMStream.Seek (0);
1241 processObjectRecord (mMStream, mMFlags, sal_True);
1243 mbMultipart = false;
1246 if (type != EmfPlusRecordTypeObject || !(flags & 0x8000))
1247 switch (type) {
1248 case EmfPlusRecordTypeHeader:
1249 sal_uInt32 header, version;
1251 rMF >> header >> version >> nHDPI >> nVDPI;
1253 EMFP_DEBUG (printf ("EMF+ Header\n"));
1254 EMFP_DEBUG (printf ("EMF+\theader: 0x%08x version: %u horizontal DPI: %d vertical DPI: %d dual: %d\n", (int)header, (unsigned int)version, (int)nHDPI, (int)nVDPI,(int)( flags & 1)));
1256 break;
1257 case EmfPlusRecordTypeEndOfFile:
1258 EMFP_DEBUG (printf ("EMF+ EndOfFile\n"));
1259 break;
1260 case EmfPlusRecordTypeGetDC:
1261 EMFP_DEBUG (printf ("EMF+ GetDC\n"));
1262 EMFP_DEBUG (printf ("EMF+\talready used in svtools wmf/emf filter parser\n"));
1263 break;
1264 case EmfPlusRecordTypeObject:
1265 processObjectRecord (rMF, flags);
1266 break;
1267 case EmfPlusRecordTypeFillPie:
1269 sal_uInt32 brushIndexOrColor;
1270 float startAngle, sweepAngle;
1272 rMF >> brushIndexOrColor >> startAngle >> sweepAngle;
1274 EMFP_DEBUG (printf ("EMF+ FillPie colorOrIndex: %x startAngle: %f sweepAngle: %f\n", (unsigned int)brushIndexOrColor, startAngle, sweepAngle));
1276 float dx, dy, dw, dh;
1278 ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1280 EMFP_DEBUG (printf ("EMF+ RectData: %f,%f %fx%f\n", dx, dy, dw, dh));
1282 startAngle = 2*M_PI*startAngle/360;
1283 sweepAngle = 2*M_PI*sweepAngle/360;
1285 B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
1286 B2DSize mappedSize( MapSize (dw/2, dh/2));
1288 double endAngle = startAngle + sweepAngle;
1289 if (endAngle < 0)
1290 endAngle += M_PI*2;
1291 endAngle = fmod (endAngle, M_PI*2);
1293 if (sweepAngle < 0) {
1294 double tmp = startAngle;
1295 startAngle = endAngle;
1296 endAngle = tmp;
1299 EMFP_DEBUG (printf ("EMF+ angles: %f,%f ---> %f,%f\n", startAngle, sweepAngle, startAngle, endAngle));
1301 B2DPolygon polygon = tools::createPolygonFromEllipseSegment (mappedCenter, mappedSize.getX (), mappedSize.getY (), startAngle, endAngle);
1302 polygon.append (mappedCenter);
1303 polygon.setClosed (true);
1305 B2DPolyPolygon polyPolygon (polygon);
1306 EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1308 break;
1309 case EmfPlusRecordTypeFillPath:
1311 sal_uInt32 index = flags & 0xff;
1312 sal_uInt32 brushIndexOrColor;
1314 rMF >> brushIndexOrColor;
1316 EMFP_DEBUG (printf ("EMF+ FillPath slot: %u\n", (unsigned int)index));
1318 EMFPPlusFillPolygon (((EMFPPath*) aObjects [index])->GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1320 break;
1321 case EmfPlusRecordTypeFillRects:
1323 EMFP_DEBUG (printf ("EMF+ FillRects\n"));
1325 sal_uInt32 brushIndexOrColor;
1326 sal_Int32 rectangles;
1327 ::basegfx::B2DPolygon polygon;
1329 rMF >> brushIndexOrColor >> rectangles;
1331 EMFP_DEBUG (printf ("EMF+\t%s: 0x%08x\n", (flags & 0x8000) ? "color" : "brush index", (unsigned int)brushIndexOrColor));
1333 for (int i=0; i < rectangles; i++) {
1334 if (flags & 0x4000) {
1335 /* 16bit integers */
1336 sal_Int16 x, y, width, height;
1338 rMF >> x >> y >> width >> height;
1340 polygon.append (Map (x, y));
1341 polygon.append (Map (x + width, y));
1342 polygon.append (Map (x + width, y + height));
1343 polygon.append (Map (x, y + height));
1345 EMFP_DEBUG (printf ("EMF+\trectangle: %d,%d %dx%d\n", x, y, width, height));
1346 } else {
1347 /* Single's */
1348 float x, y, width, height;
1350 rMF >> x >> y >> width >> height;
1352 polygon.append (Map (x, y));
1353 polygon.append (Map (x + width, y));
1354 polygon.append (Map (x + width, y + height));
1355 polygon.append (Map (x, y + height));
1357 EMFP_DEBUG (printf ("EMF+\trectangle: %f,%f %fx%f\n", x, y, width, height));
1360 ::basegfx::B2DPolyPolygon polyPolygon (polygon);
1362 EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1364 break;
1366 case EmfPlusRecordTypeFillPolygon:
1368 EMFP_DEBUG (sal_uInt8 index = flags & 0xff);
1369 sal_uInt32 brushIndexOrColor;
1370 sal_Int32 points;
1372 rMF >> brushIndexOrColor;
1373 rMF >> points;
1375 EMFP_DEBUG (printf ("EMF+ FillPolygon in slot: %d points: %d\n", index, points));
1376 EMFP_DEBUG (printf ("EMF+\t%s: 0x%08x\n", (flags & 0x8000) ? "color" : "brush index", brushIndexOrColor));
1378 EMFPPath path (points, true);
1379 path.Read (rMF, flags, *this);
1382 EMFPPlusFillPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1384 break;
1386 case EmfPlusRecordTypeDrawLines:
1388 sal_uInt32 index = flags & 0xff;
1389 sal_uInt32 points;
1391 rMF >> points;
1393 EMFP_DEBUG (printf ("EMF+ DrawLines in slot: %u points: %u\n", (unsigned int)index, (unsigned int)points));
1395 EMFPPath path (points, true);
1396 path.Read (rMF, flags, *this);
1398 EMFPPen* pen = (EMFPPen*) aObjects [index];
1400 rState.isFillColorSet = false;
1401 rState.isLineColorSet = true;
1402 rState.lineColor = ::vcl::unotools::colorToDoubleSequence (pen->GetColor (),
1403 rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace() );
1404 ::basegfx::B2DPolyPolygon& polygon (path.GetPolygon (*this));
1406 polygon.transform( rState.mapModeTransform );
1408 rendering::StrokeAttributes aStrokeAttributes;
1410 pen->SetStrokeAttributes (aStrokeAttributes, *this, rState);
1412 ActionSharedPtr pPolyAction(
1413 internal::PolyPolyActionFactory::createPolyPolyAction(
1414 polygon, rFactoryParms.mrCanvas, rState, aStrokeAttributes ) );
1416 if( pPolyAction )
1418 maActions.push_back(
1419 MtfAction(
1420 pPolyAction,
1421 rFactoryParms.mrCurrActionIndex ) );
1423 rFactoryParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1426 break;
1428 case EmfPlusRecordTypeDrawPath:
1430 sal_uInt32 penIndex;
1432 rMF >> penIndex;
1434 EMFP_DEBUG (printf ("EMF+ DrawPath\n"));
1435 EMFP_DEBUG (printf ("EMF+\tpen: %u\n", (unsigned int)penIndex));
1437 EMFPPath* path = (EMFPPath*) aObjects [flags & 0xff];
1438 EMFPPen* pen = (EMFPPen*) aObjects [penIndex & 0xff];
1440 SAL_WARN_IF( !pen, "cppcanvas", "EmfPlusRecordTypeDrawPath missing pen" );
1441 SAL_WARN_IF( !path, "cppcanvas", "EmfPlusRecordTypeDrawPath missing path" );
1443 if (pen && path)
1445 rState.isFillColorSet = false;
1446 rState.isLineColorSet = true;
1447 rState.lineColor = ::vcl::unotools::colorToDoubleSequence (pen->GetColor (),
1448 rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace());
1449 ::basegfx::B2DPolyPolygon& polygon (path->GetPolygon (*this));
1451 polygon.transform( rState.mapModeTransform );
1452 rendering::StrokeAttributes aStrokeAttributes;
1454 pen->SetStrokeAttributes (aStrokeAttributes, *this, rState);
1456 ActionSharedPtr pPolyAction(
1457 internal::PolyPolyActionFactory::createPolyPolyAction(
1458 polygon, rFactoryParms.mrCanvas, rState, aStrokeAttributes ) );
1460 if( pPolyAction )
1462 maActions.push_back(
1463 MtfAction(
1464 pPolyAction,
1465 rFactoryParms.mrCurrActionIndex ) );
1467 rFactoryParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1470 break;
1472 case EmfPlusRecordTypeDrawImagePoints:
1474 sal_uInt32 attrIndex;
1475 sal_Int32 sourceUnit;
1477 rMF >> attrIndex >> sourceUnit;
1479 EMFP_DEBUG (printf ("EMF+ DrawImagePoints attributes index: %d source unit: %d\n", (int)attrIndex, (int)sourceUnit));
1480 EMFP_DEBUG (printf ("EMF+\tTODO: use image attributes\n"));
1482 if (sourceUnit == 2 && aObjects [flags & 0xff]) { // we handle only GraphicsUnit.Pixel now
1483 EMFPImage& image = *(EMFPImage *) aObjects [flags & 0xff];
1484 float sx, sy, sw, sh;
1485 sal_Int32 unknown;
1487 ReadRectangle (rMF, sx, sy, sw, sh);
1489 rMF >> unknown;
1491 EMFP_DEBUG (printf ("EMF+ DrawImagePoints source rectangle: %f,%f %fx%f unknown: 0x%08x\n", sx, sy, sw, sh, (unsigned int)unknown));
1493 if (unknown == 3) { // it probably means number of points defining destination rectangle
1494 float x1, y1, x2, y2, x3, y3;
1496 ReadPoint (rMF, x1, y1, flags);
1497 ReadPoint (rMF, x2, y2, flags);
1498 ReadPoint (rMF, x3, y3, flags);
1500 BitmapEx aBmp( image.graphic.GetBitmapEx () );
1501 const Rectangle aCropRect (::vcl::unotools::pointFromB2DPoint (basegfx::B2DPoint (sx, sy)),
1502 ::vcl::unotools::sizeFromB2DSize (basegfx::B2DSize(sw, sh)));
1503 aBmp.Crop( aCropRect );
1506 Size aSize( aBmp.GetSizePixel() );
1507 if( aSize.Width() > 0 && aSize.Height() > 0 ) {
1508 ActionSharedPtr pBmpAction (
1509 internal::BitmapActionFactory::createBitmapAction (
1510 aBmp,
1511 rState.mapModeTransform * Map (x1, y1),
1512 rState.mapModeTransform * MapSize(x2 - x1, y3 - y1),
1513 rCanvas,
1514 rState));
1516 if( pBmpAction ) {
1517 maActions.push_back( MtfAction( pBmpAction,
1518 rFactoryParms.mrCurrActionIndex ) );
1520 rFactoryParms.mrCurrActionIndex += pBmpAction->getActionCount()-1;
1522 } else {
1523 EMFP_DEBUG (printf ("EMF+ warning: empty bitmap\n"));
1525 } else {
1526 EMFP_DEBUG (printf ("EMF+ DrawImagePoints TODO (fixme)\n"));
1528 } else {
1529 EMFP_DEBUG (printf ("EMF+ DrawImagePoints TODO (fixme) - possibly unsupported source units for crop rectangle\n"));
1531 break;
1533 case EmfPlusRecordTypeDrawString:
1535 EMFP_DEBUG (printf ("EMF+ DrawString\n"));
1537 sal_uInt32 brushId;
1538 sal_uInt32 formatId;
1539 sal_uInt32 stringLength;
1541 rMF >> brushId >> formatId >> stringLength;
1542 EMFP_DEBUG (printf ("EMF+ DrawString brushId: %x formatId: %x length: %x\n", brushId, formatId, stringLength));
1544 if (flags & 0x8000) {
1545 float lx, ly, lw, lh;
1547 rMF >> lx >> ly >> lw >> lh;
1549 EMFP_DEBUG (printf ("EMF+ DrawString layoutRect: %f,%f - %fx%f\n", lx, ly, lw, lh));
1551 XubString text = readString ( rMF, stringLength );
1553 double cellSize = setFont (flags & 0xff, rFactoryParms, rState);
1554 SET_TEXT_COLOR( brushId );
1556 ActionSharedPtr pTextAction(
1557 TextActionFactory::createTextAction(
1558 // position is just rough guess for now
1559 // we should calculate it exactly from layoutRect or font
1560 ::vcl::unotools::pointFromB2DPoint ( Map( lx + 0.15*cellSize, ly + cellSize ) ),
1561 ::Size(),
1562 ::Color(),
1563 ::Size(),
1564 ::Color(),
1565 text,
1567 stringLength,
1568 NULL,
1569 rFactoryParms.mrVDev,
1570 rFactoryParms.mrCanvas,
1571 rState,
1572 rFactoryParms.mrParms,
1573 false ) );
1574 if( pTextAction )
1576 EMFP_DEBUG (printf ("EMF+\t\tadd text action\n"));
1578 maActions.push_back(
1579 MtfAction(
1580 pTextAction,
1581 rFactoryParms.mrCurrActionIndex ) );
1583 rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
1585 } else {
1586 EMFP_DEBUG (printf ("EMF+ DrawString TODO - drawing with brush not yet supported\n"));
1589 break;
1590 case EmfPlusRecordTypeSetPageTransform:
1591 rMF >> fPageScale;
1593 EMFP_DEBUG (printf ("EMF+ SetPageTransform\n"));
1594 EMFP_DEBUG (printf ("EMF+\tscale: %f unit: %d\n", fPageScale, flags));
1595 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1596 break;
1597 case EmfPlusRecordTypeSetRenderingOrigin:
1598 rMF >> nOriginX >> nOriginY;
1599 EMFP_DEBUG (printf ("EMF+ SetRenderingOrigin\n"));
1600 EMFP_DEBUG (printf ("EMF+\torigin [x,y]: %d,%d\n", (int)nOriginX, (int)nOriginY));
1601 break;
1602 case EmfPlusRecordTypeSetTextRenderingHint:
1603 EMFP_DEBUG (printf ("EMF+ SetTextRenderingHint\n"));
1604 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1605 break;
1606 case EmfPlusRecordTypeSetAntiAliasMode:
1607 EMFP_DEBUG (printf ("EMF+ SetAntiAliasMode\n"));
1608 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1609 break;
1610 case EmfPlusRecordTypeSetInterpolationMode:
1611 EMFP_DEBUG (printf ("EMF+ InterpolationMode\n"));
1612 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1613 break;
1614 case EmfPlusRecordTypeSetPixelOffsetMode:
1615 EMFP_DEBUG (printf ("EMF+ SetPixelOffsetMode\n"));
1616 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1617 break;
1618 case EmfPlusRecordTypeSetCompositingQuality:
1619 EMFP_DEBUG (printf ("EMF+ SetCompositingQuality\n"));
1620 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1621 break;
1622 case EmfPlusRecordTypeSave:
1623 EMFP_DEBUG (printf ("EMF+ Save\n"));
1624 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1625 break;
1626 case EmfPlusRecordTypeSetWorldTransform: {
1627 EMFP_DEBUG (printf ("EMF+ SetWorldTransform\n"));
1628 XForm transform;
1629 rMF >> transform;
1630 aWorldTransform.Set (transform);
1631 EMFP_DEBUG (printf ("EMF+\tm11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n",
1632 aWorldTransform.eM11, aWorldTransform.eM12,
1633 aWorldTransform.eM21, aWorldTransform.eM22,
1634 aWorldTransform.eDx, aWorldTransform.eDy));
1635 break;
1637 case EmfPlusRecordTypeResetWorldTransform:
1638 EMFP_DEBUG (printf ("EMF+ ResetWorldTransform\n"));
1639 aWorldTransform.SetIdentity ();
1640 break;
1641 case EmfPlusRecordTypeMultiplyWorldTransform: {
1642 EMFP_DEBUG (printf ("EMF+ MultiplyWorldTransform\n"));
1643 XForm transform;
1644 rMF >> transform;
1646 EMFP_DEBUG (printf ("EMF+\tmatrix m11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n",
1647 transform.eM11, transform.eM12,
1648 transform.eM21, transform.eM22,
1649 transform.eDx, transform.eDy));
1651 if (flags & 0x2000) // post multiply
1652 aWorldTransform.Multiply (transform);
1653 else { // pre multiply
1654 transform.Multiply (aWorldTransform);
1655 aWorldTransform.Set (transform);
1657 EMFP_DEBUG (printf ("EMF+\tresult world matrix m11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n",
1658 aWorldTransform.eM11, aWorldTransform.eM12,
1659 aWorldTransform.eM21, aWorldTransform.eM22,
1660 aWorldTransform.eDx, aWorldTransform.eDy));
1661 break;
1663 case EmfPlusRecordTypeSetClipPath:
1665 EMFP_DEBUG (printf ("EMF+ SetClipPath\n"));
1666 EMFP_DEBUG (printf ("EMF+\tpath in slot: %d\n", flags & 0xff));
1668 EMFPPath& path = *(EMFPPath*) aObjects [flags & 0xff];
1669 ::basegfx::B2DPolyPolygon& clipPoly (path.GetPolygon (*this));
1671 clipPoly.transform (rState.mapModeTransform);
1672 updateClipping (clipPoly, rFactoryParms, false);
1674 break;
1676 case EmfPlusRecordTypeSetClipRegion: {
1677 EMFP_DEBUG (printf ("EMF+ SetClipRegion\n"));
1678 EMFP_DEBUG (printf ("EMF+\tregion in slot: %d combine mode: %d\n", flags & 0xff, (flags & 0xff00) >> 8));
1679 EMFPRegion *region = (EMFPRegion*)aObjects [flags & 0xff];
1681 // reset clip
1682 if (region && region->parts == 0 && region->initialState == EmfPlusRegionInitialStateInfinite) {
1683 updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms, false);
1684 } else {
1685 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1687 break;
1689 case EmfPlusRecordTypeDrawDriverString: {
1690 EMFP_DEBUG (printf ("EMF+ DrawDriverString, flags: 0x%04x\n", flags));
1691 sal_uInt32 brushIndexOrColor;
1692 sal_uInt32 optionFlags;
1693 sal_uInt32 hasMatrix;
1694 sal_uInt32 glyphsCount;
1696 rMF >> brushIndexOrColor >> optionFlags >> hasMatrix >> glyphsCount;
1698 EMFP_DEBUG (printf ("EMF+\t%s: 0x%08x\n", (flags & 0x8000) ? "color" : "brush index", (unsigned int)brushIndexOrColor));
1699 EMFP_DEBUG (printf ("EMF+\toption flags: 0x%08x\n", (unsigned int)optionFlags));
1700 EMFP_DEBUG (printf ("EMF+\thas matrix: %u\n", (unsigned int)hasMatrix));
1701 EMFP_DEBUG (printf ("EMF+\tglyphs: %u\n", (unsigned int)glyphsCount));
1703 if( ( optionFlags & 1 ) && glyphsCount > 0 ) {
1704 float *charsPosX = new float[glyphsCount];
1705 float *charsPosY = new float[glyphsCount];
1707 XubString text = readString (rMF, glyphsCount);
1709 for( sal_uInt32 i=0; i<glyphsCount; i++) {
1710 rMF >> charsPosX[i] >> charsPosY[i];
1711 EMFP_DEBUG (printf ("EMF+\tglyphPosition[%u]: %f, %f\n", (unsigned int)i, charsPosX[i], charsPosY[i]));
1714 XForm transform;
1715 if( hasMatrix ) {
1716 rMF >> transform;
1717 EMFP_DEBUG (printf ("EMF+\tmatrix:: %f, %f, %f, %f, %f, %f\n", transform.eM11, transform.eM12, transform.eM21, transform.eM22, transform.eDx, transform.eDy));
1720 // add the text action
1721 setFont (flags & 0xff, rFactoryParms, rState);
1723 if( flags & 0x8000 )
1724 SET_TEXT_COLOR(brushIndexOrColor);
1726 ActionSharedPtr pTextAction(
1727 TextActionFactory::createTextAction(
1728 ::vcl::unotools::pointFromB2DPoint ( Map( charsPosX[0], charsPosY[0] ) ),
1729 ::Size(),
1730 ::Color(),
1731 ::Size(),
1732 ::Color(),
1733 text,
1735 glyphsCount,
1736 NULL,
1737 rFactoryParms.mrVDev,
1738 rFactoryParms.mrCanvas,
1739 rState,
1740 rFactoryParms.mrParms,
1741 false ) );
1743 if( pTextAction )
1745 EMFP_DEBUG (printf ("EMF+\t\tadd text action\n"));
1747 maActions.push_back(
1748 MtfAction(
1749 pTextAction,
1750 rFactoryParms.mrCurrActionIndex ) );
1752 rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
1755 delete[] charsPosX;
1756 delete[] charsPosY;
1757 } else {
1758 EMFP_DEBUG (printf ("EMF+\tTODO: fonts (non-unicode glyphs chars)\n"));
1761 break;
1763 default:
1764 EMFP_DEBUG (printf ("EMF+ unhandled record type: %d\n", type));
1765 EMFP_DEBUG (printf ("EMF+\tTODO\n"));
1768 rMF.Seek (next);
1770 length -= size;
1776 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */