Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <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>
39 :
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>
44 :
45 : #include <bitmapaction.hxx>
46 : #include <implrenderer.hxx>
47 : #include <outdevstate.hxx>
48 : #include <polypolyaction.hxx>
49 : #include <textaction.hxx>
50 : #include <stdio.h>
51 :
52 : namespace
53 : {
54 :
55 : #define EmfPlusRecordTypeHeader 16385
56 : #define EmfPlusRecordTypeEndOfFile 16386
57 : #define EmfPlusRecordTypeGetDC 16388
58 : #define EmfPlusRecordTypeObject 16392
59 : #define EmfPlusRecordTypeFillRects 16394
60 : #define EmfPlusRecordTypeFillPolygon 16396
61 : #define EmfPlusRecordTypeDrawLines 16397
62 : #define EmfPlusRecordTypeFillEllipse 16398
63 : #define EmfPlusRecordTypeDrawEllipse 16399
64 : #define EmfPlusRecordTypeFillPie 16400
65 : #define EmfPlusRecordTypeFillPath 16404
66 : #define EmfPlusRecordTypeDrawPath 16405
67 : #define EmfPlusRecordTypeDrawImage 16410
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 EmfPlusRecordTypeRestore 16422
78 : #define EmfPlusRecordTypeBeginContainerNoParams 16424
79 : #define EmfPlusRecordTypeEndContainer 16425
80 : #define EmfPlusRecordTypeSetWorldTransform 16426
81 : #define EmfPlusRecordTypeResetWorldTransform 16427
82 : #define EmfPlusRecordTypeMultiplyWorldTransform 16428
83 : #define EmfPlusRecordTypeSetPageTransform 16432
84 : #define EmfPlusRecordTypeSetClipRect 16434
85 : #define EmfPlusRecordTypeSetClipPath 16435
86 : #define EmfPlusRecordTypeSetClipRegion 16436
87 : #define EmfPlusRecordTypeDrawDriverString 16438
88 :
89 : #define EmfPlusObjectTypeBrush 0x100
90 : #define EmfPlusObjectTypePen 0x200
91 : #define EmfPlusObjectTypePath 0x300
92 : #define EmfPlusObjectTypeRegion 0x400
93 : #define EmfPlusObjectTypeImage 0x500
94 : #define EmfPlusObjectTypeFont 0x600
95 : #define EmfPlusObjectTypeStringFormat 0x700
96 : #define EmfPlusObjectTypeImageAttributes 0x800
97 : #define EmfPlusObjectTypeCustomLineCap 0x900
98 :
99 : #define EmfPlusRegionInitialStateInfinite 0x10000003
100 :
101 : const sal_Int32 EmfPlusLineStyleSolid = 0x00000000;
102 : const sal_Int32 EmfPlusLineStyleDash = 0x00000001;
103 : const sal_Int32 EmfPlusLineStyleDot = 0x00000002;
104 : const sal_Int32 EmfPlusLineStyleDashDot = 0x00000003;
105 : const sal_Int32 EmfPlusLineStyleDashDotDot = 0x00000004;
106 : const sal_Int32 EmfPlusLineStyleCustom = 0x00000005;
107 :
108 : const sal_uInt32 EmfPlusCustomLineCapDataTypeDefault = 0x00000000;
109 : const sal_uInt32 EmfPlusCustomLineCapDataTypeAdjustableArrow = 0x00000001;
110 :
111 : const sal_uInt32 EmfPlusCustomLineCapDataFillPath = 0x00000001;
112 : const sal_uInt32 EmfPlusCustomLineCapDataLinePath = 0x00000002;
113 :
114 : const sal_uInt32 EmfPlusLineCapTypeSquare = 0x00000001;
115 : const sal_uInt32 EmfPlusLineCapTypeRound = 0x00000002;
116 :
117 : const sal_uInt32 EmfPlusLineJoinTypeMiter = 0x00000000;
118 : const sal_uInt32 EmfPlusLineJoinTypeBevel = 0x00000001;
119 : const sal_uInt32 EmfPlusLineJoinTypeRound = 0x00000002;
120 : const sal_uInt32 EmfPlusLineJoinTypeMiterClipped = 0x00000003;
121 :
122 : enum EmfPlusCombineMode
123 : {
124 : EmfPlusCombineModeReplace = 0x00000000,
125 : EmfPlusCombineModeIntersect = 0x00000001,
126 : EmfPlusCombineModeUnion = 0x00000002,
127 : EmfPlusCombineModeXOR = 0x00000003,
128 : EmfPlusCombineModeExclude = 0x00000004,
129 : EmfPlusCombineModeComplement = 0x00000005
130 : };
131 :
132 : enum EmfPlusHatchStyle
133 : {
134 : HatchStyleHorizontal = 0x00000000,
135 : HatchStyleVertical = 0x00000001,
136 : HatchStyleForwardDiagonal = 0x00000002,
137 : HatchStyleBackwardDiagonal = 0x00000003,
138 : HatchStyleLargeGrid = 0x00000004,
139 : HatchStyleDiagonalCross = 0x00000005,
140 : HatchStyle05Percent = 0x00000006,
141 : HatchStyle10Percent = 0x00000007,
142 : HatchStyle20Percent = 0x00000008,
143 : HatchStyle25Percent = 0x00000009,
144 : HatchStyle30Percent = 0x0000000A,
145 : HatchStyle40Percent = 0x0000000B,
146 : HatchStyle50Percent = 0x0000000C,
147 : HatchStyle60Percent = 0x0000000D,
148 : HatchStyle70Percent = 0x0000000E,
149 : HatchStyle75Percent = 0x0000000F,
150 : HatchStyle80Percent = 0x00000010,
151 : HatchStyle90Percent = 0x00000011,
152 : HatchStyleLightDownwardDiagonal = 0x00000012,
153 : HatchStyleLightUpwardDiagonal = 0x00000013,
154 : HatchStyleDarkDownwardDiagonal = 0x00000014,
155 : HatchStyleDarkUpwardDiagonal = 0x00000015,
156 : HatchStyleWideDownwardDiagonal = 0x00000016,
157 : HatchStyleWideUpwardDiagonal = 0x00000017,
158 : HatchStyleLightVertical = 0x00000018,
159 : HatchStyleLightHorizontal = 0x00000019,
160 : HatchStyleNarrowVertical = 0x0000001A,
161 : HatchStyleNarrowHorizontal = 0x0000001B,
162 : HatchStyleDarkVertical = 0x0000001C,
163 : HatchStyleDarkHorizontal = 0x0000001D,
164 : HatchStyleDashedDownwardDiagonal = 0x0000001E,
165 : HatchStyleDashedUpwardDiagonal = 0x0000001F,
166 : HatchStyleDashedHorizontal = 0x00000020,
167 : HatchStyleDashedVertical = 0x00000021,
168 : HatchStyleSmallConfetti = 0x00000022,
169 : HatchStyleLargeConfetti = 0x00000023,
170 : HatchStyleZigZag = 0x00000024,
171 : HatchStyleWave = 0x00000025,
172 : HatchStyleDiagonalBrick = 0x00000026,
173 : HatchStyleHorizontalBrick = 0x00000027,
174 : HatchStyleWeave = 0x00000028,
175 : HatchStylePlaid = 0x00000029,
176 : HatchStyleDivot = 0x0000002A,
177 : HatchStyleDottedGrid = 0x0000002B,
178 : HatchStyleDottedDiamond = 0x0000002C,
179 : HatchStyleShingle = 0x0000002D,
180 : HatchStyleTrellis = 0x0000002E,
181 : HatchStyleSphere = 0x0000002F,
182 : HatchStyleSmallGrid = 0x00000030,
183 : HatchStyleSmallCheckerBoard = 0x00000031,
184 : HatchStyleLargeCheckerBoard = 0x00000032,
185 : HatchStyleOutlinedDiamond = 0x00000033,
186 : HatchStyleSolidDiamond = 0x00000034
187 : };
188 :
189 0 : const char* emfTypeToName(sal_uInt16 type)
190 : {
191 0 : switch(type)
192 : {
193 0 : case EmfPlusRecordTypeHeader: return "EmfPlusRecordTypeHeader";
194 0 : case EmfPlusRecordTypeEndOfFile: return "EmfPlusRecordTypeEndOfFile";
195 0 : case EmfPlusRecordTypeGetDC: return "EmfPlusRecordTypeGetDC";
196 0 : case EmfPlusRecordTypeObject: return "EmfPlusRecordTypeObject";
197 0 : case EmfPlusRecordTypeFillRects: return "EmfPlusRecordTypeFillRects";
198 0 : case EmfPlusRecordTypeFillPolygon: return "EmfPlusRecordTypeFillPolygon";
199 0 : case EmfPlusRecordTypeDrawLines: return "EmfPlusRecordTypeDrawLines";
200 0 : case EmfPlusRecordTypeFillEllipse: return "EmfPlusRecordTypeFillEllipse";
201 0 : case EmfPlusRecordTypeDrawEllipse: return "EmfPlusRecordTypeDrawEllipse";
202 0 : case EmfPlusRecordTypeFillPie: return "EmfPlusRecordTypeFillPie";
203 0 : case EmfPlusRecordTypeFillPath: return "EmfPlusRecordTypeFillPath";
204 0 : case EmfPlusRecordTypeDrawPath: return "EmfPlusRecordTypeDrawPath";
205 0 : case EmfPlusRecordTypeDrawImage: return "EmfPlusRecordTypeDrawImage";
206 0 : case EmfPlusRecordTypeDrawImagePoints: return "EmfPlusRecordTypeDrawImagePoints";
207 0 : case EmfPlusRecordTypeDrawString: return "EmfPlusRecordTypeDrawString";
208 0 : case EmfPlusRecordTypeSetRenderingOrigin: return "EmfPlusRecordTypeSetRenderingOrigin";
209 0 : case EmfPlusRecordTypeSetAntiAliasMode: return "EmfPlusRecordTypeSetAntiAliasMode";
210 0 : case EmfPlusRecordTypeSetTextRenderingHint: return "EmfPlusRecordTypeSetTextRenderingHint";
211 0 : case EmfPlusRecordTypeSetInterpolationMode: return "EmfPlusRecordTypeSetInterpolationMode";
212 0 : case EmfPlusRecordTypeSetPixelOffsetMode: return "EmfPlusRecordTypeSetPixelOffsetMode";
213 0 : case EmfPlusRecordTypeSetCompositingQuality: return "EmfPlusRecordTypeSetCompositingQuality";
214 0 : case EmfPlusRecordTypeSave: return "EmfPlusRecordTypeSave";
215 0 : case EmfPlusRecordTypeRestore: return "EmfPlusRecordTypeRestore";
216 0 : case EmfPlusRecordTypeBeginContainerNoParams: return "EmfPlusRecordTypeBeginContainerNoParams";
217 0 : case EmfPlusRecordTypeEndContainer: return "EmfPlusRecordTypeEndContainer";
218 0 : case EmfPlusRecordTypeSetWorldTransform: return "EmfPlusRecordTypeSetWorldTransform";
219 0 : case EmfPlusRecordTypeResetWorldTransform: return "EmfPlusRecordTypeResetWorldTransform";
220 0 : case EmfPlusRecordTypeMultiplyWorldTransform: return "EmfPlusRecordTypeMultiplyWorldTransform";
221 0 : case EmfPlusRecordTypeSetPageTransform: return "EmfPlusRecordTypeSetPageTransform";
222 0 : case EmfPlusRecordTypeSetClipRect: return "EmfPlusRecordTypeSetClipRect";
223 0 : case EmfPlusRecordTypeSetClipPath: return "EmfPlusRecordTypeSetClipPath";
224 0 : case EmfPlusRecordTypeSetClipRegion: return "EmfPlusRecordTypeSetClipRegion";
225 0 : case EmfPlusRecordTypeDrawDriverString: return "EmfPlusRecordTypeDrawDriverString";
226 : }
227 0 : return "";
228 : }
229 :
230 : } // anonymous namespace
231 :
232 : using namespace ::com::sun::star;
233 : using namespace ::basegfx;
234 :
235 : namespace cppcanvas
236 : {
237 : namespace internal
238 : {
239 : struct EMFPPath : public EMFPObject
240 : {
241 : ::basegfx::B2DPolyPolygon aPolygon;
242 : sal_Int32 nPoints;
243 : float* pPoints;
244 : sal_uInt8* pPointTypes;
245 :
246 : public:
247 0 : EMFPPath (sal_Int32 _nPoints, bool bLines = false)
248 0 : {
249 0 : if( _nPoints<0 || sal_uInt32(_nPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
250 0 : _nPoints = SAL_MAX_INT32/(2*sizeof(float));
251 0 : nPoints = _nPoints;
252 0 : pPoints = new float [nPoints*2];
253 0 : if (!bLines)
254 0 : pPointTypes = new sal_uInt8 [_nPoints];
255 : else
256 0 : pPointTypes = NULL;
257 0 : }
258 :
259 0 : virtual ~EMFPPath ()
260 0 : {
261 0 : delete [] pPoints;
262 0 : delete [] pPointTypes;
263 0 : }
264 :
265 : // TODO: remove rR argument when debug code is not longer needed
266 0 : void Read (SvStream& s, sal_uInt32 pathFlags, ImplRenderer& rR)
267 : {
268 0 : for (int i = 0; i < nPoints; i ++) {
269 0 : if (pathFlags & 0x4000) {
270 : // EMFPlusPoint: stored in signed short 16bit integer format
271 : sal_Int16 x, y;
272 :
273 0 : s.ReadInt16( x ).ReadInt16( y );
274 : SAL_INFO ("cppcanvas.emf", "EMF+\tEMFPlusPoint [x,y]: " << x << "," << y);
275 0 : pPoints [i*2] = x;
276 0 : pPoints [i*2 + 1] = y;
277 0 : } else if (!(pathFlags & 0xC000)) {
278 : // EMFPlusPointF: stored in Single (float) format
279 0 : s.ReadFloat( pPoints [i*2] ).ReadFloat( pPoints [i*2 + 1] );
280 : SAL_INFO ("cppcanvas.emf", "EMF+\tEMFPlusPointF [x,y]: " << pPoints [i*2] << "," << pPoints [i*2 + 1]);
281 : } else { //if (pathFlags & 0x8000)
282 : // EMFPlusPointR: points are stored in EMFPlusInteger7 or
283 : // EMFPlusInteger15 objects, see section 2.2.2.21/22
284 : SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - parse EMFPlusPointR object (section 2.2.1.6)");
285 : }
286 :
287 : }
288 :
289 0 : if (pPointTypes)
290 0 : for (int i = 0; i < nPoints; i ++) {
291 0 : s.ReadUChar( pPointTypes [i] );
292 : SAL_INFO ("cppcanvas.emf", "EMF+\tpoint type: " << (int)pPointTypes [i]);
293 : }
294 :
295 0 : aPolygon.clear ();
296 :
297 : #if OSL_DEBUG_LEVEL > 1
298 : const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (GetPolygon (rR)));
299 :
300 : SAL_INFO ("cppcanvas.emf",
301 : "EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << aBounds.getWidth () << "x" << aBounds.getHeight () << " (mapped)");
302 : #else
303 : (void) rR; // avoid warnings
304 : #endif
305 0 : }
306 :
307 0 : ::basegfx::B2DPolyPolygon& GetPolygon (ImplRenderer& rR, bool bMapIt = true)
308 : {
309 0 : ::basegfx::B2DPolygon polygon;
310 :
311 0 : aPolygon.clear ();
312 :
313 0 : int last_normal = 0, p = 0;
314 0 : ::basegfx::B2DPoint prev, mapped;
315 0 : bool hasPrev = false;
316 0 : for (int i = 0; i < nPoints; i ++) {
317 0 : if (p && pPointTypes && (pPointTypes [i] == 0)) {
318 0 : aPolygon.append (polygon);
319 0 : last_normal = i;
320 0 : p = 0;
321 0 : polygon.clear ();
322 : }
323 :
324 0 : if (bMapIt)
325 0 : mapped = rR.Map (pPoints [i*2], pPoints [i*2 + 1]);
326 : else
327 0 : mapped = ::basegfx::B2DPoint (pPoints [i*2], pPoints [i*2 + 1]);
328 0 : if (pPointTypes) {
329 0 : if ((pPointTypes [i] & 0x07) == 3) {
330 0 : if (((i - last_normal )% 3) == 1) {
331 0 : polygon.setNextControlPoint (p - 1, mapped);
332 : SAL_INFO ("cppcanvas.emf", "polygon append next: " << p - 1 << " mapped: " << mapped.getX () << "," << mapped.getY ());
333 0 : continue;
334 0 : } else if (((i - last_normal) % 3) == 2) {
335 0 : prev = mapped;
336 0 : hasPrev = true;
337 0 : continue;
338 : }
339 : } else
340 0 : last_normal = i;
341 : }
342 0 : polygon.append (mapped);
343 : SAL_INFO ("cppcanvas.emf", "polygon append point: " << pPoints [i*2] << "," << pPoints [i*2 + 1] << " mapped: " << mapped.getX () << ":" << mapped.getY ());
344 0 : if (hasPrev) {
345 0 : polygon.setPrevControlPoint (p, prev);
346 : SAL_INFO ("cppcanvas.emf", "polygon append prev: " << p << " mapped: " << prev.getX () << "," << prev.getY ());
347 0 : hasPrev = false;
348 : }
349 0 : p ++;
350 0 : if (pPointTypes && (pPointTypes [i] & 0x80)) { // closed polygon
351 0 : polygon.setClosed (true);
352 0 : aPolygon.append (polygon);
353 : SAL_INFO ("cppcanvas.emf", "close polygon");
354 0 : last_normal = i + 1;
355 0 : p = 0;
356 0 : polygon.clear ();
357 : }
358 : }
359 :
360 0 : if (polygon.count ()) {
361 0 : aPolygon.append (polygon);
362 :
363 : #if OSL_DEBUG_LEVEL > 1
364 : for (unsigned int i=0; i<aPolygon.count(); i++) {
365 : polygon = aPolygon.getB2DPolygon(i);
366 : SAL_INFO ("cppcanvas.emf", "polygon: " << i);
367 : for (unsigned int j=0; j<polygon.count(); j++) {
368 : ::basegfx::B2DPoint point = polygon.getB2DPoint(j);
369 : SAL_INFO ("cppcanvas.emf", "point: " << point.getX() << "," << point.getY());
370 : if (polygon.isPrevControlPointUsed(j)) {
371 : point = polygon.getPrevControlPoint(j);
372 : SAL_INFO ("cppcanvas.emf", "prev: " << point.getX() << "," << point.getY());
373 : }
374 : if (polygon.isNextControlPointUsed(j)) {
375 : point = polygon.getNextControlPoint(j);
376 : SAL_INFO ("cppcanvas.emf", "next: " << point.getX() << "," << point.getY());
377 : }
378 : }
379 : }
380 : #endif
381 : }
382 :
383 0 : return aPolygon;
384 : }
385 : };
386 :
387 : struct EMFPRegion : public EMFPObject
388 : {
389 : sal_Int32 parts;
390 : sal_Int32 *combineMode;
391 : sal_Int32 initialState;
392 : EMFPPath *initialPath;
393 : float ix, iy, iw, ih;
394 :
395 0 : EMFPRegion ()
396 : : parts(0)
397 : , combineMode(NULL)
398 : , initialState(0)
399 : , initialPath(NULL)
400 : , ix(0.0)
401 : , iy(0.0)
402 : , iw(0.0)
403 0 : , ih(0.0)
404 : {
405 0 : }
406 :
407 0 : virtual ~EMFPRegion ()
408 0 : {
409 0 : if (combineMode) {
410 0 : delete [] combineMode;
411 0 : combineMode = NULL;
412 : }
413 0 : if (initialPath) {
414 0 : delete initialPath;
415 0 : initialPath = NULL;
416 : }
417 0 : }
418 :
419 0 : void Read (SvStream& s)
420 : {
421 : sal_uInt32 header;
422 :
423 0 : s.ReadUInt32( header ).ReadInt32( parts );
424 :
425 : SAL_INFO ("cppcanvas.emf", "EMF+\tregion");
426 : SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " parts: " << parts << std::dec );
427 :
428 0 : if (parts) {
429 0 : if( parts<0 || sal_uInt32(parts)>SAL_MAX_INT32/sizeof(sal_Int32) )
430 0 : parts = SAL_MAX_INT32/sizeof(sal_Int32);
431 :
432 0 : combineMode = new sal_Int32 [parts];
433 :
434 0 : for (int i = 0; i < parts; i ++) {
435 0 : s.ReadInt32( combineMode [i] );
436 : SAL_INFO ("cppcanvas.emf", "EMF+\tcombine mode [" << i << "]: 0x" << std::hex << combineMode [i] << std::dec);
437 : }
438 : }
439 :
440 0 : s.ReadInt32( initialState );
441 : SAL_INFO ("cppcanvas.emf", "EMF+\tinitial state: 0x" << std::hex << initialState << std::dec);
442 0 : }
443 : };
444 :
445 : struct EMFPBrush : public EMFPObject
446 : {
447 : ::Color solidColor;
448 : sal_uInt32 type;
449 : sal_uInt32 additionalFlags;
450 :
451 : /* linear gradient */
452 : sal_Int32 wrapMode;
453 : float areaX, areaY, areaWidth, areaHeight;
454 : ::Color secondColor; // first color is stored in solidColor;
455 : XForm transformation;
456 : bool hasTransformation;
457 : sal_Int32 blendPoints;
458 : float* blendPositions;
459 : float* blendFactors;
460 : sal_Int32 colorblendPoints;
461 : float* colorblendPositions;
462 : ::Color* colorblendColors;
463 : sal_Int32 surroundColorsNumber;
464 : ::Color* surroundColors;
465 : EMFPPath *path;
466 : EmfPlusHatchStyle hatchStyle;
467 :
468 : public:
469 0 : EMFPBrush ()
470 : : type(0)
471 : , additionalFlags(0)
472 : , wrapMode(0)
473 : , areaX(0.0)
474 : , areaY(0.0)
475 : , areaWidth(0.0)
476 : , areaHeight(0.0)
477 : , hasTransformation(false)
478 : , blendPoints(0)
479 : , blendPositions(NULL)
480 : , blendFactors(NULL)
481 : , colorblendPoints(0)
482 : , colorblendPositions(NULL)
483 : , colorblendColors(NULL)
484 : , surroundColorsNumber(0)
485 : , surroundColors(NULL)
486 : , path(NULL)
487 0 : , hatchStyle(HatchStyleHorizontal)
488 : {
489 0 : }
490 :
491 0 : virtual ~EMFPBrush ()
492 0 : {
493 0 : if (blendPositions != NULL) {
494 0 : delete[] blendPositions;
495 0 : blendPositions = NULL;
496 : }
497 0 : if (colorblendPositions != NULL) {
498 0 : delete[] colorblendPositions;
499 0 : colorblendPositions = NULL;
500 : }
501 0 : if (colorblendColors != NULL) {
502 0 : delete[] colorblendColors;
503 0 : colorblendColors = NULL;
504 : }
505 0 : if (surroundColors != NULL) {
506 0 : delete[] surroundColors;
507 0 : surroundColors = NULL;
508 : }
509 0 : if (path) {
510 0 : delete path;
511 0 : path = NULL;
512 : }
513 0 : }
514 :
515 : sal_uInt32 GetType() const { return type; }
516 0 : const ::Color& GetColor() const { return solidColor; }
517 :
518 0 : void Read (SvStream& s, ImplRenderer& rR)
519 : {
520 : sal_uInt32 header;
521 :
522 0 : s.ReadUInt32( header ).ReadUInt32( type );
523 :
524 : SAL_INFO ("cppcanvas.emf", "EMF+\tbrush");
525 : SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec);
526 :
527 0 : switch (type) {
528 : case 0:
529 : {
530 : sal_uInt32 color;
531 :
532 0 : s.ReadUInt32( color );
533 0 : solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
534 : SAL_INFO ("cppcanvas.emf", "EMF+\tsolid color: 0x" << std::hex << color << std::dec);
535 0 : break;
536 : }
537 : case 1:
538 : {
539 : sal_uInt32 style;
540 : sal_uInt32 foregroundColor;
541 : sal_uInt32 backgroundColor;
542 0 : s.ReadUInt32( style );
543 0 : s.ReadUInt32( foregroundColor );
544 0 : s.ReadUInt32( backgroundColor );
545 :
546 0 : hatchStyle = static_cast<EmfPlusHatchStyle>(style);
547 0 : solidColor = ::Color(0xff - (foregroundColor >> 24), (foregroundColor >> 16) & 0xff, (foregroundColor >> 8) & 0xff, foregroundColor & 0xff);
548 0 : secondColor = ::Color(0xff - (backgroundColor >> 24), (backgroundColor >> 16) & 0xff, (backgroundColor >> 8) & 0xff, backgroundColor & 0xff);
549 : SAL_INFO ("cppcanvas.emf", "EMF+\thatch style " << style << " foregroundcolor: 0x" << solidColor.AsRGBHexString() << " background 0x" << secondColor.AsRGBHexString());
550 0 : break;
551 : }
552 : // path gradient
553 : case 3:
554 : {
555 0 : s.ReadUInt32( additionalFlags ).ReadInt32( wrapMode );
556 :
557 : SAL_INFO ("cppcanvas.emf", "EMF+\tpath gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec);
558 :
559 : sal_uInt32 color;
560 :
561 0 : s.ReadUInt32( color );
562 0 : solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
563 : SAL_INFO("cppcanvas.emf", "EMF+\tcenter color: 0x" << std::hex << color << std::dec);
564 :
565 0 : s.ReadFloat( areaX ).ReadFloat( areaY );
566 : SAL_INFO("cppcanvas.emf", "EMF+\tcenter point: " << areaX << "," << areaY);
567 :
568 0 : s.ReadInt32( surroundColorsNumber );
569 : SAL_INFO("cppcanvas.emf", "EMF+\tsurround colors: " << surroundColorsNumber);
570 :
571 0 : if( surroundColorsNumber<0 || sal_uInt32(surroundColorsNumber)>SAL_MAX_INT32/sizeof(::Color) )
572 0 : surroundColorsNumber = SAL_MAX_INT32/sizeof(::Color);
573 :
574 0 : surroundColors = new ::Color [surroundColorsNumber];
575 0 : for (int i = 0; i < surroundColorsNumber; i++) {
576 0 : s.ReadUInt32( color );
577 0 : surroundColors[i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
578 0 : if (i == 0)
579 0 : secondColor = surroundColors [0];
580 : SAL_INFO("cppcanvas.emf", "EMF+\tsurround color[" << i << "]: 0x" << std::hex << color << std::dec);
581 : }
582 :
583 0 : if (additionalFlags & 0x01) {
584 : sal_Int32 pathLength;
585 :
586 0 : s.ReadInt32( pathLength );
587 : SAL_INFO("cppcanvas.emf", "EMF+\tpath length: " << pathLength);
588 :
589 0 : sal_Size pos = s.Tell ();
590 :
591 : sal_uInt32 pathHeader;
592 : sal_Int32 pathPoints, pathFlags;
593 0 : s.ReadUInt32( pathHeader ).ReadInt32( pathPoints ).ReadInt32( pathFlags );
594 :
595 : SAL_INFO("cppcanvas.emf", "EMF+\tpath (brush path gradient)");
596 : SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec );
597 :
598 0 : path = new EMFPPath (pathPoints);
599 0 : path->Read (s, pathFlags, rR);
600 :
601 0 : s.Seek (pos + pathLength);
602 :
603 0 : const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (path->GetPolygon (rR, false)));
604 0 : areaWidth = aBounds.getWidth ();
605 0 : areaHeight = aBounds.getHeight ();
606 :
607 : SAL_INFO("cppcanvas.emf", "EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << " " << aBounds.getWidth () << "x" << aBounds.getHeight ());
608 :
609 :
610 0 : if (additionalFlags & 0x02) {
611 : SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
612 0 : ReadXForm( s, transformation );
613 0 : hasTransformation = true;
614 : SAL_INFO("cppcanvas.emf",
615 : "EMF+\tm11: " << transformation.eM11 << " m12: " << transformation.eM12 <<
616 : "\nEMF+\tm21: " << transformation.eM21 << " m22: " << transformation.eM22 <<
617 : "\nEMF+\tdx: " << transformation.eDx << " dy: " << transformation.eDy);
618 :
619 : }
620 0 : if (additionalFlags & 0x08) {
621 0 : s.ReadInt32( blendPoints );
622 : SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
623 0 : if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
624 0 : blendPoints = SAL_MAX_INT32/(2*sizeof(float));
625 0 : blendPositions = new float [2*blendPoints];
626 0 : blendFactors = blendPositions + blendPoints;
627 0 : for (int i=0; i < blendPoints; i ++) {
628 0 : s.ReadFloat( blendPositions [i] );
629 : SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions [i]);
630 : }
631 0 : for (int i=0; i < blendPoints; i ++) {
632 0 : s.ReadFloat( blendFactors [i] );
633 : SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors [i]);
634 : }
635 : }
636 :
637 0 : if (additionalFlags & 0x04) {
638 0 : s.ReadInt32( colorblendPoints );
639 : SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
640 0 : if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
641 0 : colorblendPoints = SAL_MAX_INT32/sizeof(float);
642 0 : if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
643 0 : colorblendPoints = SAL_MAX_INT32/sizeof(::Color);
644 0 : colorblendPositions = new float [colorblendPoints];
645 0 : colorblendColors = new ::Color [colorblendPoints];
646 0 : for (int i=0; i < colorblendPoints; i ++) {
647 0 : s.ReadFloat( colorblendPositions [i] );
648 : SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions [i]);
649 : }
650 0 : for (int i=0; i < colorblendPoints; i ++) {
651 0 : s.ReadUInt32( color );
652 0 : colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
653 : SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
654 : }
655 : }
656 : }
657 0 : break;
658 : }
659 : // linear gradient
660 : case 4:
661 : {
662 0 : s.ReadUInt32( additionalFlags ).ReadInt32( wrapMode );
663 :
664 : SAL_INFO("cppcanvas.emf", "EMF+\tlinear gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec);
665 :
666 0 : s.ReadFloat( areaX ).ReadFloat( areaY ).ReadFloat( areaWidth ).ReadFloat( areaHeight );
667 :
668 : SAL_INFO("cppcanvas.emf", "EMF+\tarea: " << areaX << "," << areaY << " - " << areaWidth << "x" << areaHeight);
669 :
670 : sal_uInt32 color;
671 :
672 0 : s.ReadUInt32( color );
673 0 : solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
674 : SAL_INFO("cppcanvas.emf", "EMF+\tfirst color: 0x" << std::hex << color << std::dec);
675 :
676 0 : s.ReadUInt32( color );
677 0 : secondColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
678 : SAL_INFO("cppcanvas.emf", "EMF+\tsecond color: 0x" << std::hex << color << std::dec);
679 :
680 : // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
681 0 : s.ReadUInt32( color );
682 0 : s.ReadUInt32( color );
683 :
684 0 : if (additionalFlags & 0x02) {
685 : SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
686 0 : ReadXForm( s, transformation );
687 0 : hasTransformation = true;
688 : SAL_INFO("cppcanvas.emf",
689 : "EMF+\tm11: " << transformation.eM11 << " m12: " << transformation.eM12 <<
690 : "\nEMF+\tm21: " << transformation.eM21 << " m22: " << transformation.eM22 <<
691 : "\nEMF+\tdx: " << transformation.eDx << " dy: " << transformation.eDy);
692 : }
693 0 : if (additionalFlags & 0x08) {
694 0 : s.ReadInt32( blendPoints );
695 : SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
696 0 : if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
697 0 : blendPoints = SAL_MAX_INT32/(2*sizeof(float));
698 0 : blendPositions = new float [2*blendPoints];
699 0 : blendFactors = blendPositions + blendPoints;
700 0 : for (int i=0; i < blendPoints; i ++) {
701 0 : s.ReadFloat( blendPositions [i] );
702 : SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions [i]);
703 : }
704 0 : for (int i=0; i < blendPoints; i ++) {
705 0 : s.ReadFloat( blendFactors [i] );
706 : SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors [i]);
707 : }
708 : }
709 :
710 0 : if (additionalFlags & 0x04) {
711 0 : s.ReadInt32( colorblendPoints );
712 : SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
713 0 : if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
714 0 : colorblendPoints = SAL_MAX_INT32/sizeof(float);
715 0 : if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
716 0 : colorblendPoints = sal_uInt32(SAL_MAX_INT32)/sizeof(::Color);
717 0 : colorblendPositions = new float [colorblendPoints];
718 0 : colorblendColors = new ::Color [colorblendPoints];
719 0 : for (int i=0; i < colorblendPoints; i ++) {
720 0 : s.ReadFloat( colorblendPositions [i] );
721 : SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions [i]);
722 : }
723 0 : for (int i=0; i < colorblendPoints; i ++) {
724 0 : s.ReadUInt32( color );
725 0 : colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
726 : SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
727 : }
728 : }
729 :
730 0 : break;
731 : }
732 : default:
733 : SAL_INFO("cppcanvas.emf", "EMF+\tunhandled brush type: " << std::hex << type << std::dec);
734 : }
735 0 : }
736 : };
737 :
738 : /// Convert stroke caps between EMF+ and rendering API
739 0 : sal_Int8 lcl_convertStrokeCap(sal_uInt32 nEmfStroke)
740 : {
741 0 : switch (nEmfStroke)
742 : {
743 0 : case EmfPlusLineCapTypeSquare: return rendering::PathCapType::SQUARE;
744 0 : case EmfPlusLineCapTypeRound: return rendering::PathCapType::ROUND;
745 : }
746 :
747 : // we have no mapping for EmfPlusLineCapTypeTriangle = 0x00000003,
748 : // so return BUTT always
749 0 : return rendering::PathCapType::BUTT;
750 : }
751 :
752 0 : sal_Int8 lcl_convertLineJoinType(sal_uInt32 nEmfLineJoin)
753 : {
754 0 : switch (nEmfLineJoin)
755 : {
756 : case EmfPlusLineJoinTypeMiter: // fall-through
757 0 : case EmfPlusLineJoinTypeMiterClipped: return rendering::PathJoinType::MITER;
758 0 : case EmfPlusLineJoinTypeBevel: return rendering::PathJoinType::BEVEL;
759 0 : case EmfPlusLineJoinTypeRound: return rendering::PathJoinType::ROUND;
760 : }
761 : assert(false); // Line Join type isn't in specification.
762 0 : return 0;
763 : }
764 :
765 : struct EMFPCustomLineCap : public EMFPObject
766 : {
767 : sal_uInt32 type;
768 : sal_uInt32 strokeStartCap, strokeEndCap, strokeJoin;
769 : float miterLimit;
770 : basegfx::B2DPolyPolygon polygon;
771 : bool mbIsFilled;
772 :
773 : public:
774 0 : EMFPCustomLineCap()
775 : : EMFPObject()
776 : , type(0)
777 : , strokeStartCap(0)
778 : , strokeEndCap(0)
779 : , strokeJoin(0)
780 : , miterLimit(0.0)
781 0 : , mbIsFilled(false)
782 : {
783 0 : }
784 :
785 0 : virtual ~EMFPCustomLineCap()
786 0 : {
787 0 : }
788 :
789 0 : void SetAttributes(rendering::StrokeAttributes& aAttributes)
790 : {
791 0 : aAttributes.StartCapType = lcl_convertStrokeCap(strokeStartCap);
792 0 : aAttributes.EndCapType = lcl_convertStrokeCap(strokeEndCap);
793 0 : aAttributes.JoinType = lcl_convertLineJoinType(strokeJoin);
794 :
795 0 : aAttributes.MiterLimit = miterLimit;
796 0 : }
797 :
798 0 : void ReadPath(SvStream& s, ImplRenderer& rR, bool bFill)
799 : {
800 : sal_Int32 pathLength;
801 0 : s.ReadInt32( pathLength );
802 : SAL_INFO("cppcanvas.emf", "EMF+\t\tpath length: " << pathLength);
803 :
804 : sal_uInt32 pathHeader;
805 : sal_Int32 pathPoints, pathFlags;
806 0 : s.ReadUInt32( pathHeader ).ReadInt32( pathPoints ).ReadInt32( pathFlags );
807 :
808 : SAL_INFO("cppcanvas.emf", "EMF+\t\tpath (custom cap line path)");
809 : SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec );
810 :
811 0 : EMFPPath path(pathPoints);
812 0 : path.Read(s, pathFlags, rR);
813 :
814 0 : polygon = path.GetPolygon(rR, false);
815 0 : mbIsFilled = bFill;
816 :
817 : // transformation to convert the path to what LibreOffice
818 : // expects
819 0 : B2DHomMatrix aMatrix;
820 0 : aMatrix.scale(1.0, -1.0);
821 :
822 0 : polygon.transform(aMatrix);
823 0 : };
824 :
825 0 : void Read (SvStream& s, ImplRenderer& rR)
826 : {
827 : sal_uInt32 header;
828 :
829 0 : s.ReadUInt32( header ).ReadUInt32( type );
830 :
831 : SAL_INFO("cppcanvas.emf", "EMF+\t\tcustom cap");
832 : SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << header << " type: " << type << std::dec);
833 :
834 0 : if (type == EmfPlusCustomLineCapDataTypeDefault)
835 : {
836 : sal_uInt32 customLineCapDataFlags, baseCap;
837 : float baseInset;
838 : float widthScale;
839 : float fillHotSpotX, fillHotSpotY, strokeHotSpotX, strokeHotSpotY;
840 :
841 0 : s.ReadUInt32( customLineCapDataFlags ).ReadUInt32( baseCap ).ReadFloat( baseInset )
842 0 : .ReadUInt32( strokeStartCap ).ReadUInt32( strokeEndCap ).ReadUInt32( strokeJoin )
843 0 : .ReadFloat( miterLimit ).ReadFloat( widthScale )
844 0 : .ReadFloat( fillHotSpotX ).ReadFloat( fillHotSpotY ).ReadFloat( strokeHotSpotX ).ReadFloat( strokeHotSpotY );
845 :
846 : SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomLineCapDataFlags: 0x" << std::hex << customLineCapDataFlags);
847 : SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseCap: 0x" << std::hex << baseCap);
848 : SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseInset: " << baseInset);
849 : SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeStartCap: 0x" << std::hex << strokeStartCap);
850 : SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeEndCap: 0x" << std::hex << strokeEndCap);
851 : SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeJoin: 0x" << std::hex << strokeJoin);
852 : SAL_INFO("cppcanvas.emf", "EMF+\t\tmiterLimit: " << miterLimit);
853 : SAL_INFO("cppcanvas.emf", "EMF+\t\twidthScale: " << widthScale);
854 :
855 0 : if (customLineCapDataFlags & EmfPlusCustomLineCapDataFillPath)
856 : {
857 0 : ReadPath(s, rR, true);
858 : }
859 :
860 0 : if (customLineCapDataFlags & EmfPlusCustomLineCapDataLinePath)
861 : {
862 0 : ReadPath(s, rR, false);
863 : }
864 : }
865 0 : else if (type == EmfPlusCustomLineCapDataTypeAdjustableArrow)
866 : {
867 : // TODO only reads the data, does not use them [I've had
868 : // no test document to be able to implement it]
869 :
870 : sal_Int32 width, height, middleInset, fillState, lineStartCap;
871 : sal_Int32 lineEndCap, lineJoin, widthScale;
872 : float fillHotSpotX, fillHotSpotY, lineHotSpotX, lineHotSpotY;
873 :
874 0 : s.ReadInt32( width ).ReadInt32( height ).ReadInt32( middleInset ).ReadInt32( fillState ).ReadInt32( lineStartCap )
875 0 : .ReadInt32( lineEndCap ).ReadInt32( lineJoin ).ReadFloat( miterLimit ).ReadInt32( widthScale )
876 0 : .ReadFloat( fillHotSpotX ).ReadFloat( fillHotSpotY ).ReadFloat( lineHotSpotX ).ReadFloat( lineHotSpotY );
877 :
878 : SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - actually read EmfPlusCustomLineCapArrowData object (section 2.2.2.12)");
879 : }
880 0 : }
881 : };
882 :
883 : struct EMFPPen : public EMFPBrush
884 : {
885 : XForm transformation;
886 : float width;
887 : sal_Int32 startCap;
888 : sal_Int32 endCap;
889 : sal_Int32 lineJoin;
890 : float mitterLimit;
891 : sal_Int32 dashStyle;
892 : sal_Int32 dashCap;
893 : float dashOffset;
894 : sal_Int32 dashPatternLen;
895 : float *dashPattern;
896 : sal_Int32 alignment;
897 : sal_Int32 compoundArrayLen;
898 : float *compoundArray;
899 : sal_Int32 customStartCapLen;
900 : EMFPCustomLineCap *customStartCap;
901 : sal_Int32 customEndCapLen;
902 : EMFPCustomLineCap *customEndCap;
903 :
904 : public:
905 0 : EMFPPen ()
906 : : EMFPBrush()
907 : , width(0.0)
908 : , startCap(0)
909 : , endCap(0)
910 : , lineJoin(0)
911 : , mitterLimit(0.0)
912 : , dashStyle(0)
913 : , dashCap(0)
914 : , dashOffset(0.0)
915 : , dashPatternLen(0)
916 : , dashPattern(NULL)
917 : , alignment(0)
918 : , compoundArrayLen(0)
919 : , compoundArray(NULL)
920 : , customStartCapLen(0)
921 : , customStartCap(NULL)
922 : , customEndCapLen(0)
923 0 : , customEndCap(NULL)
924 : {
925 0 : }
926 :
927 0 : virtual ~EMFPPen()
928 0 : {
929 0 : delete[] dashPattern;
930 0 : delete[] compoundArray;
931 0 : delete customStartCap;
932 0 : delete customEndCap;
933 0 : }
934 :
935 0 : void SetStrokeWidth(rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
936 : {
937 : #if OSL_DEBUG_LEVEL > 1
938 : if (width == 0.0) {
939 : SAL_INFO ("cppcanvas.emf", "TODO: pen with zero width - using minimal which might not be correct\n");
940 : }
941 : #endif
942 0 : rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getLength());
943 0 : }
944 :
945 0 : void SetStrokeAttributes(rendering::StrokeAttributes& rStrokeAttributes)
946 : {
947 0 : rStrokeAttributes.JoinType = lcl_convertLineJoinType(lineJoin);
948 :
949 0 : if (dashStyle != EmfPlusLineStyleSolid)
950 : {
951 0 : const float dash[] = {3, 3};
952 0 : const float dot[] = {1, 3};
953 0 : const float dashdot[] = {3, 3, 1, 3};
954 0 : const float dashdotdot[] = {3, 3, 1, 3, 1, 3};
955 :
956 0 : sal_Int32 nLen = 0;
957 0 : const float *pPattern = NULL;
958 0 : switch (dashStyle)
959 : {
960 0 : case EmfPlusLineStyleDash: nLen = SAL_N_ELEMENTS(dash); pPattern = dash; break;
961 0 : case EmfPlusLineStyleDot: nLen = SAL_N_ELEMENTS(dot); pPattern = dot; break;
962 0 : case EmfPlusLineStyleDashDot: nLen = SAL_N_ELEMENTS(dashdot); pPattern = dashdot; break;
963 0 : case EmfPlusLineStyleDashDotDot: nLen = SAL_N_ELEMENTS(dashdotdot); pPattern = dashdotdot; break;
964 0 : case EmfPlusLineStyleCustom: nLen = dashPatternLen; pPattern = dashPattern; break;
965 : }
966 0 : if (nLen > 0)
967 : {
968 0 : uno::Sequence<double> aDashArray(nLen);
969 0 : for (int i = 0; i < nLen; ++i)
970 0 : aDashArray[i] = pPattern[i];
971 :
972 0 : rStrokeAttributes.DashArray = aDashArray;
973 : }
974 : }
975 0 : }
976 :
977 0 : void Read (SvStream& s, ImplRenderer& rR, sal_Int32, sal_Int32 )
978 : {
979 : sal_uInt32 header, unknown, penFlags, unknown2;
980 : int i;
981 :
982 0 : s.ReadUInt32( header ).ReadUInt32( unknown ).ReadUInt32( penFlags ).ReadUInt32( unknown2 ).ReadFloat( width );
983 :
984 : SAL_INFO("cppcanvas.emf", "EMF+\tpen");
985 : SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " unknown: 0x" << unknown <<
986 : " additional flags: 0x" << penFlags << " unknown: 0x" << unknown2 << " width: " << std::dec << width );
987 :
988 0 : if (penFlags & 1)
989 0 : ReadXForm( s, transformation );
990 :
991 0 : if (penFlags & 2)
992 : {
993 0 : s.ReadInt32( startCap );
994 : SAL_INFO("cppcanvas.emf", "EMF+\t\tstartCap: 0x" << std::hex << startCap);
995 : }
996 : else
997 0 : startCap = 0;
998 :
999 0 : if (penFlags & 4)
1000 : {
1001 0 : s.ReadInt32( endCap );
1002 : SAL_INFO("cppcanvas.emf", "EMF+\t\tendCap: 0x" << std::hex << endCap);
1003 : }
1004 : else
1005 0 : endCap = 0;
1006 :
1007 0 : if (penFlags & 8)
1008 0 : s.ReadInt32( lineJoin );
1009 : else
1010 0 : lineJoin = 0;
1011 :
1012 0 : if (penFlags & 16)
1013 0 : s.ReadFloat( mitterLimit );
1014 : else
1015 0 : mitterLimit = 0;
1016 :
1017 0 : if (penFlags & 32)
1018 : {
1019 0 : s.ReadInt32( dashStyle );
1020 : SAL_INFO("cppcanvas.emf", "EMF+\t\tdashStyle: 0x" << std::hex << dashStyle);
1021 : }
1022 : else
1023 0 : dashStyle = 0;
1024 :
1025 0 : if (penFlags & 64)
1026 0 : s.ReadInt32( dashCap );
1027 : else
1028 0 : dashCap = 0;
1029 :
1030 0 : if (penFlags & 128)
1031 0 : s.ReadFloat( dashOffset );
1032 : else
1033 0 : dashOffset = 0;
1034 :
1035 0 : if (penFlags & 256)
1036 : {
1037 0 : dashStyle = EmfPlusLineStyleCustom;
1038 :
1039 0 : s.ReadInt32( dashPatternLen );
1040 : SAL_INFO("cppcanvas.emf", "EMF+\t\tdashPatternLen: " << dashPatternLen);
1041 :
1042 0 : if( dashPatternLen<0 || sal_uInt32(dashPatternLen)>SAL_MAX_INT32/sizeof(float) )
1043 0 : dashPatternLen = SAL_MAX_INT32/sizeof(float);
1044 0 : dashPattern = new float [dashPatternLen];
1045 0 : for (i = 0; i < dashPatternLen; i++)
1046 : {
1047 0 : s.ReadFloat( dashPattern [i] );
1048 : SAL_INFO("cppcanvas.emf", "EMF+\t\t\tdashPattern[" << i << "]: " << dashPattern[i]);
1049 : }
1050 : }
1051 : else
1052 0 : dashPatternLen = 0;
1053 :
1054 0 : if (penFlags & 512)
1055 0 : s.ReadInt32( alignment );
1056 : else
1057 0 : alignment = 0;
1058 :
1059 0 : if (penFlags & 1024) {
1060 0 : s.ReadInt32( compoundArrayLen );
1061 0 : if( compoundArrayLen<0 || sal_uInt32(compoundArrayLen)>SAL_MAX_INT32/sizeof(float) )
1062 0 : compoundArrayLen = SAL_MAX_INT32/sizeof(float);
1063 0 : compoundArray = new float [compoundArrayLen];
1064 0 : for (i = 0; i < compoundArrayLen; i++)
1065 0 : s.ReadFloat( compoundArray [i] );
1066 : } else
1067 0 : compoundArrayLen = 0;
1068 :
1069 0 : if (penFlags & 2048)
1070 : {
1071 0 : s.ReadInt32( customStartCapLen );
1072 : SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomStartCapLen: " << customStartCapLen);
1073 0 : sal_Size pos = s.Tell();
1074 :
1075 0 : customStartCap = new EMFPCustomLineCap();
1076 0 : customStartCap->Read(s, rR);
1077 :
1078 : // maybe we don't read everything yet, play it safe ;-)
1079 0 : s.Seek(pos + customStartCapLen);
1080 : }
1081 : else
1082 0 : customStartCapLen = 0;
1083 :
1084 0 : if (penFlags & 4096)
1085 : {
1086 0 : s.ReadInt32( customEndCapLen );
1087 : SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomEndCapLen: " << customEndCapLen);
1088 0 : sal_Size pos = s.Tell();
1089 :
1090 0 : customEndCap = new EMFPCustomLineCap();
1091 0 : customEndCap->Read(s, rR);
1092 :
1093 : // maybe we don't read everything yet, play it safe ;-)
1094 0 : s.Seek(pos + customEndCapLen);
1095 : }
1096 : else
1097 0 : customEndCapLen = 0;
1098 :
1099 0 : EMFPBrush::Read (s, rR);
1100 0 : }
1101 : };
1102 :
1103 0 : struct EMFPImage : public EMFPObject
1104 : {
1105 : sal_uInt32 type;
1106 : sal_Int32 width;
1107 : sal_Int32 height;
1108 : sal_Int32 stride;
1109 : sal_Int32 pixelFormat;
1110 : Graphic graphic;
1111 :
1112 :
1113 0 : void Read (SvMemoryStream &s, sal_uInt32 dataSize, bool bUseWholeStream)
1114 : {
1115 : sal_uInt32 header, unknown;
1116 :
1117 0 : s.ReadUInt32( header ).ReadUInt32( type );
1118 :
1119 : SAL_INFO("cppcanvas.emf", "EMF+\timage\nEMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec );
1120 :
1121 0 : if (type == 1) { // bitmap
1122 0 : s.ReadInt32( width ).ReadInt32( height ).ReadInt32( stride ).ReadInt32( pixelFormat ).ReadUInt32( unknown );
1123 : SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << width << " height: " << height << " stride: " << stride << " pixelFormat: 0x" << std::hex << pixelFormat << std::dec);
1124 0 : if (width == 0) { // non native formats
1125 0 : GraphicFilter filter;
1126 :
1127 0 : filter.ImportGraphic (graphic, OUString(), s);
1128 0 : SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << graphic.GetBitmap().GetSizePixel().Width() << " height: " << graphic.GetBitmap().GetSizePixel().Height());
1129 : }
1130 :
1131 0 : } else if (type == 2) {
1132 : sal_Int32 mfType, mfSize;
1133 :
1134 0 : s.ReadInt32( mfType ).ReadInt32( mfSize );
1135 : SAL_INFO("cppcanvas.emf", "EMF+\tmetafile type: " << mfType << " dataSize: " << mfSize << " real size calculated from record dataSize: " << dataSize - 16);
1136 :
1137 0 : GraphicFilter filter;
1138 : // workaround buggy metafiles, which have wrong mfSize set (n#705956 for example)
1139 0 : SvMemoryStream mfStream (((char *)s.GetData()) + s.Tell(), bUseWholeStream ? s.remainingSize() : dataSize - 16, STREAM_READ);
1140 :
1141 0 : filter.ImportGraphic (graphic, OUString(), mfStream);
1142 :
1143 : // debug code - write the stream to debug file /tmp/emf-stream.emf
1144 : #if OSL_DEBUG_LEVEL > 1
1145 : mfStream.Seek(0);
1146 : static sal_Int32 emfp_debug_stream_number = 0;
1147 : OUString emfp_debug_filename = "/tmp/emf-embedded-stream" +
1148 : OUString::number(emfp_debug_stream_number++) + ".emf";
1149 :
1150 : SvFileStream file( emfp_debug_filename, STREAM_WRITE | STREAM_TRUNC );
1151 :
1152 : mfStream.WriteStream(file);
1153 : file.Flush();
1154 : file.Close();
1155 : #endif
1156 : }
1157 0 : }
1158 : };
1159 :
1160 0 : struct EMFPFont : public EMFPObject
1161 : {
1162 : sal_uInt32 version;
1163 : float emSize;
1164 : sal_uInt32 sizeUnit;
1165 : sal_Int32 fontFlags;
1166 : OUString family;
1167 :
1168 0 : void Read (SvMemoryStream &s)
1169 : {
1170 : sal_uInt32 header;
1171 : sal_uInt32 reserved;
1172 : sal_uInt32 length;
1173 :
1174 0 : s.ReadUInt32( header ).ReadFloat( emSize ).ReadUInt32( sizeUnit ).ReadInt32( fontFlags ).ReadUInt32( reserved ).ReadUInt32( length );
1175 :
1176 : OSL_ASSERT( ( header >> 12 ) == 0xdbc01 );
1177 :
1178 : SAL_INFO("cppcanvas.emf", "EMF+\tfont\nEMF+\theader: 0x" << std::hex << (header >> 12) << " version: 0x" << (header & 0x1fff) << " size: " << std::dec << emSize << " unit: 0x" << std::hex << sizeUnit << std::dec);
1179 : SAL_INFO("cppcanvas.emf", "EMF+\tflags: 0x" << std::hex << fontFlags << " reserved: 0x" << reserved << " length: 0x" << std::hex << length << std::dec);
1180 :
1181 0 : if( length > 0 && length < 0x4000 ) {
1182 0 : sal_Unicode *chars = (sal_Unicode *) alloca( sizeof( sal_Unicode ) * length );
1183 :
1184 0 : for( sal_uInt32 i = 0; i < length; i++ )
1185 0 : s.ReadUInt16( chars[ i ] );
1186 :
1187 0 : family = OUString( chars, length );
1188 : SAL_INFO("cppcanvas.emf", "EMF+\tfamily: " << OUStringToOString( family, RTL_TEXTENCODING_UTF8).getStr()); // TODO: can we just use family?
1189 : }
1190 0 : }
1191 : };
1192 :
1193 0 : void ImplRenderer::ReadRectangle (SvStream& s, float& x, float& y, float &width, float& height, bool bCompressed)
1194 : {
1195 0 : if (bCompressed) {
1196 : sal_Int16 ix, iy, iw, ih;
1197 :
1198 0 : s.ReadInt16( ix ).ReadInt16( iy ).ReadInt16( iw ).ReadInt16( ih );
1199 :
1200 0 : x = ix;
1201 0 : y = iy;
1202 0 : width = iw;
1203 0 : height = ih;
1204 : } else
1205 0 : s.ReadFloat( x ).ReadFloat( y ).ReadFloat( width ).ReadFloat( height );
1206 0 : }
1207 :
1208 0 : void ImplRenderer::ReadPoint (SvStream& s, float& x, float& y, sal_uInt32 flags)
1209 : {
1210 0 : if (flags & 0x4000) {
1211 : sal_Int16 ix, iy;
1212 :
1213 0 : s.ReadInt16( ix ).ReadInt16( iy );
1214 :
1215 0 : x = ix;
1216 0 : y = iy;
1217 : } else
1218 0 : s.ReadFloat( x ).ReadFloat( y );
1219 0 : }
1220 :
1221 0 : void ImplRenderer::MapToDevice (double& x, double& y)
1222 : {
1223 : // TODO: other units
1224 0 : x = 100*nMmX*x/nPixX;
1225 0 : y = 100*nMmY*y/nPixY;
1226 0 : }
1227 :
1228 0 : ::basegfx::B2DPoint ImplRenderer::Map (double ix, double iy)
1229 : {
1230 : double x, y;
1231 :
1232 0 : x = ix*aWorldTransform.eM11 + iy*aWorldTransform.eM21 + aWorldTransform.eDx;
1233 0 : y = ix*aWorldTransform.eM12 + iy*aWorldTransform.eM22 + aWorldTransform.eDy;
1234 :
1235 0 : MapToDevice (x, y);
1236 :
1237 0 : x -= nFrameLeft;
1238 0 : y -= nFrameTop;
1239 :
1240 0 : x *= aBaseTransform.eM11;
1241 0 : y *= aBaseTransform.eM22;
1242 :
1243 0 : return ::basegfx::B2DPoint (x, y);
1244 : }
1245 :
1246 0 : ::basegfx::B2DSize ImplRenderer::MapSize (double iwidth, double iheight)
1247 : {
1248 : double w, h;
1249 :
1250 0 : w = iwidth*aWorldTransform.eM11 + iheight*aWorldTransform.eM21;
1251 0 : h = iwidth*aWorldTransform.eM12 + iheight*aWorldTransform.eM22;
1252 :
1253 0 : MapToDevice (w, h);
1254 :
1255 0 : w *= aBaseTransform.eM11;
1256 0 : h *= aBaseTransform.eM22;
1257 :
1258 0 : return ::basegfx::B2DSize (w, h);
1259 : }
1260 :
1261 : #define COLOR(x) \
1262 : ::vcl::unotools::colorToDoubleSequence( ::Color (0xff - (x >> 24), \
1263 : (x >> 16) & 0xff, \
1264 : (x >> 8) & 0xff, \
1265 : x & 0xff), \
1266 : rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
1267 :
1268 0 : void ImplRenderer::EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
1269 : OutDevState& rState, const CanvasSharedPtr& rCanvas, bool isColor, sal_uInt32 brushIndexOrColor)
1270 : {
1271 0 : ::basegfx::B2DPolyPolygon localPolygon (polygon);
1272 :
1273 : SAL_INFO("cppcanvas.emf", "EMF+\tfill polygon");
1274 :
1275 0 : localPolygon.transform( rState.mapModeTransform );
1276 :
1277 0 : ActionSharedPtr pPolyAction;
1278 :
1279 0 : if (isColor) {
1280 : SAL_INFO("cppcanvas.emf", "EMF+\t\tcolor fill:0x" << std::hex << brushIndexOrColor << std::dec);
1281 0 : rState.isFillColorSet = true;
1282 0 : rState.isLineColorSet = false;
1283 :
1284 0 : rState.fillColor = COLOR(brushIndexOrColor);
1285 :
1286 0 : pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) );
1287 :
1288 : } else {
1289 0 : rState.isFillColorSet = true;
1290 : // extract UseBrush
1291 0 : EMFPBrush* brush = static_cast<EMFPBrush*>( aObjects [brushIndexOrColor & 0xff] );
1292 : SAL_INFO("cppcanvas.emf", "EMF+\tbrush fill slot: " << brushIndexOrColor << " (type: " << brush->GetType () << ")");
1293 :
1294 : // give up in case something wrong happened
1295 0 : if( !brush )
1296 0 : return;
1297 :
1298 0 : rState.isFillColorSet = false;
1299 0 : rState.isLineColorSet = false;
1300 :
1301 0 : if (brush->type == 1)
1302 : {
1303 : // EMF+ like hatching is currently not supported. These are just color blends which serve as an approximation for some of them
1304 : // for the others the hatch "background" color (secondColor in brush) is used.
1305 :
1306 0 : bool isHatchBlend = true;
1307 0 : double blendFactor = 0.0;
1308 :
1309 0 : switch (brush->hatchStyle)
1310 : {
1311 0 : case HatchStyle05Percent: blendFactor = 0.05; break;
1312 0 : case HatchStyle10Percent: blendFactor = 0.10; break;
1313 0 : case HatchStyle20Percent: blendFactor = 0.20; break;
1314 0 : case HatchStyle25Percent: blendFactor = 0.25; break;
1315 0 : case HatchStyle30Percent: blendFactor = 0.30; break;
1316 0 : case HatchStyle40Percent: blendFactor = 0.40; break;
1317 0 : case HatchStyle50Percent: blendFactor = 0.50; break;
1318 0 : case HatchStyle60Percent: blendFactor = 0.60; break;
1319 0 : case HatchStyle70Percent: blendFactor = 0.70; break;
1320 0 : case HatchStyle75Percent: blendFactor = 0.75; break;
1321 0 : case HatchStyle80Percent: blendFactor = 0.80; break;
1322 0 : case HatchStyle90Percent: blendFactor = 0.90; break;
1323 : default:
1324 0 : isHatchBlend = false;
1325 0 : break;
1326 : }
1327 0 : rState.isFillColorSet = true;
1328 0 : rState.isLineColorSet = false;
1329 0 : ::Color fillColor;
1330 0 : if (isHatchBlend)
1331 : {
1332 0 : fillColor = brush->solidColor;
1333 0 : fillColor.Merge(brush->secondColor, static_cast<sal_uInt8>(255 * blendFactor));
1334 : }
1335 : else
1336 : {
1337 0 : fillColor = brush->secondColor;
1338 : }
1339 0 : rState.fillColor = ::vcl::unotools::colorToDoubleSequence(fillColor, rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
1340 0 : pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) );
1341 : }
1342 0 : else if (brush->type == 3 || brush->type == 4)
1343 : {
1344 0 : if (brush->type == 3 && !(brush->additionalFlags & 0x1))
1345 0 : return; // we are unable to parse these brushes yet
1346 :
1347 0 : ::basegfx::B2DHomMatrix aTextureTransformation;
1348 0 : ::basegfx::B2DHomMatrix aWorldTransformation;
1349 0 : ::basegfx::B2DHomMatrix aBaseTransformation;
1350 0 : rendering::Texture aTexture;
1351 :
1352 0 : aWorldTransformation.set (0, 0, aWorldTransform.eM11);
1353 0 : aWorldTransformation.set (0, 1, aWorldTransform.eM21);
1354 0 : aWorldTransformation.set (0, 2, aWorldTransform.eDx);
1355 0 : aWorldTransformation.set (1, 0, aWorldTransform.eM12);
1356 0 : aWorldTransformation.set (1, 1, aWorldTransform.eM22);
1357 0 : aWorldTransformation.set (1, 2, aWorldTransform.eDy);
1358 :
1359 0 : aBaseTransformation.set (0, 0, aBaseTransform.eM11);
1360 0 : aBaseTransformation.set (0, 1, aBaseTransform.eM21);
1361 0 : aBaseTransformation.set (0, 2, aBaseTransform.eDx);
1362 0 : aBaseTransformation.set (1, 0, aBaseTransform.eM12);
1363 0 : aBaseTransformation.set (1, 1, aBaseTransform.eM22);
1364 0 : aBaseTransformation.set (1, 2, aBaseTransform.eDy);
1365 :
1366 0 : if (brush->type == 4) {
1367 0 : aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
1368 0 : aTextureTransformation.translate (brush->areaX, brush->areaY);
1369 : } else {
1370 0 : aTextureTransformation.translate (-0.5, -0.5);
1371 0 : aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
1372 0 : aTextureTransformation.translate (brush->areaX,brush->areaY);
1373 : }
1374 :
1375 0 : if (brush->hasTransformation) {
1376 0 : ::basegfx::B2DHomMatrix aTransformation;
1377 :
1378 0 : aTransformation.set (0, 0, brush->transformation.eM11);
1379 0 : aTransformation.set (0, 1, brush->transformation.eM21);
1380 0 : aTransformation.set (0, 2, brush->transformation.eDx);
1381 0 : aTransformation.set (1, 0, brush->transformation.eM12);
1382 0 : aTransformation.set (1, 1, brush->transformation.eM22);
1383 0 : aTransformation.set (1, 2, brush->transformation.eDy);
1384 :
1385 0 : aTextureTransformation *= aTransformation;
1386 : }
1387 :
1388 0 : aTextureTransformation *= aWorldTransformation;
1389 0 : aTextureTransformation.scale (100.0*nMmX/nPixX, 100.0*nMmY/nPixY);
1390 0 : aTextureTransformation.translate (-nFrameLeft, -nFrameTop);
1391 0 : aTextureTransformation *= rState.mapModeTransform;
1392 0 : aTextureTransformation *= aBaseTransformation;
1393 :
1394 0 : aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
1395 0 : aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
1396 0 : aTexture.Alpha = 1.0;
1397 :
1398 0 : basegfx::ODFGradientInfo aGradInfo;
1399 0 : OUString aGradientService;
1400 :
1401 : const uno::Sequence< double > aStartColor(
1402 : ::vcl::unotools::colorToDoubleSequence( brush->solidColor,
1403 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
1404 : const uno::Sequence< double > aEndColor(
1405 : ::vcl::unotools::colorToDoubleSequence( brush->secondColor,
1406 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
1407 0 : uno::Sequence< uno::Sequence < double > > aColors (2);
1408 0 : uno::Sequence< double > aStops (2);
1409 :
1410 0 : if (brush->blendPositions) {
1411 : SAL_INFO("cppcanvas.emf", "EMF+\t\tuse blend");
1412 0 : aColors.realloc (brush->blendPoints);
1413 0 : aStops.realloc (brush->blendPoints);
1414 0 : int length = aStartColor.getLength ();
1415 0 : uno::Sequence< double > aColor (length);
1416 :
1417 : OSL_ASSERT (length == aEndColor.getLength());
1418 :
1419 0 : for (int i = 0; i < brush->blendPoints; i++) {
1420 0 : aStops[i] = brush->blendPositions [i];
1421 :
1422 0 : for (int j = 0; j < length; j++) {
1423 0 : if (brush->type == 4) {
1424 0 : aColor [j] = aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i];
1425 : } else
1426 0 : aColor [j] = aStartColor [j]*brush->blendFactors[i] + aEndColor [j]*(1 - brush->blendFactors[i]);
1427 : }
1428 :
1429 0 : aColors[i] = aColor;
1430 0 : }
1431 0 : } else if (brush->colorblendPositions) {
1432 : SAL_INFO("cppcanvas.emf", "EMF+\t\tuse color blend");
1433 0 : aColors.realloc (brush->colorblendPoints);
1434 0 : aStops.realloc (brush->colorblendPoints);
1435 :
1436 0 : for (int i = 0; i < brush->colorblendPoints; i++) {
1437 0 : aStops[i] = brush->colorblendPositions [i];
1438 0 : aColors[(brush->type == 4) ? i : brush->colorblendPoints - 1 - i] = ::vcl::unotools::colorToDoubleSequence( brush->colorblendColors [i],
1439 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
1440 : }
1441 : } else {
1442 0 : aStops[0] = 0.0;
1443 0 : aStops[1] = 1.0;
1444 :
1445 0 : if (brush->type == 4) {
1446 0 : aColors[0] = aStartColor;
1447 0 : aColors[1] = aEndColor;
1448 : } else {
1449 0 : aColors[1] = aStartColor;
1450 0 : aColors[0] = aEndColor;
1451 : }
1452 : }
1453 :
1454 : SAL_INFO("cppcanvas.emf", "EMF+\t\tset gradient");
1455 0 : basegfx::B2DRange aBoundsRectangle (0, 0, 1, 1);
1456 0 : if (brush->type == 4) {
1457 0 : aGradientService = "LinearGradient";
1458 0 : aGradInfo = basegfx::tools::createLinearODFGradientInfo(
1459 : aBoundsRectangle,
1460 0 : aStops.getLength(),
1461 : 0,
1462 0 : 0);
1463 :
1464 : } else {
1465 0 : aGradientService = "EllipticalGradient";
1466 0 : aGradInfo = basegfx::tools::createEllipticalODFGradientInfo(
1467 : aBoundsRectangle,
1468 : ::basegfx::B2DVector( 0, 0 ),
1469 0 : aStops.getLength(),
1470 : 0,
1471 0 : 0);
1472 : }
1473 :
1474 : uno::Reference< lang::XMultiServiceFactory > xFactory(
1475 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
1476 :
1477 0 : if( xFactory.is() ) {
1478 0 : uno::Sequence<uno::Any> args( 3 );
1479 0 : beans::PropertyValue aProp;
1480 0 : aProp.Name = "Colors";
1481 0 : aProp.Value <<= aColors;
1482 0 : args[0] <<= aProp;
1483 0 : aProp.Name = "Stops";
1484 0 : aProp.Value <<= aStops;
1485 0 : args[1] <<= aProp;
1486 0 : aProp.Name = "AspectRatio";
1487 0 : aProp.Value <<= static_cast<sal_Int32>(1);
1488 0 : args[2] <<= aProp;
1489 :
1490 : aTexture.Gradient.set(
1491 0 : xFactory->createInstanceWithArguments( aGradientService,
1492 0 : args ),
1493 0 : uno::UNO_QUERY);
1494 : }
1495 :
1496 : ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
1497 0 : aTextureTransformation );
1498 :
1499 0 : if( aTexture.Gradient.is() )
1500 0 : pPolyAction =
1501 : ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon,
1502 : rParms.mrCanvas,
1503 : rState,
1504 0 : aTexture ) );
1505 : }
1506 : }
1507 :
1508 0 : if( pPolyAction )
1509 : {
1510 : SAL_INFO("cppcanvas.emf", "EMF+\t\tadd poly action");
1511 :
1512 : maActions.push_back(
1513 : MtfAction(
1514 : pPolyAction,
1515 0 : rParms.mrCurrActionIndex ) );
1516 :
1517 0 : rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1518 0 : }
1519 : }
1520 :
1521 0 : double ImplRenderer::EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon& rPolygon, double fPolyLength,
1522 : const ::basegfx::B2DPolyPolygon& rLineCap, bool bIsFilled, bool bStart, const rendering::StrokeAttributes& rAttributes,
1523 : const ActionFactoryParameters& rParms, OutDevState& rState)
1524 : {
1525 0 : if (!rLineCap.count())
1526 0 : return 0.0;
1527 :
1528 : // createAreaGeometryForLineStartEnd normalises the arrows height
1529 : // before scaling (i.e. scales down by rPolygon.height), hence
1530 : // we pre-scale it (which means we can avoid changing the logic
1531 : // that would affect arrows rendered outside of EMF+).
1532 0 : const double fWidth = rAttributes.StrokeWidth*rLineCap.getB2DRange().getWidth();
1533 :
1534 : // When drawing an outline (as opposed to a filled endCap), we also
1535 : // need to take account that the brush width also adds to the area
1536 : // of the polygon.
1537 0 : const double fShift = bIsFilled ? 0 : rAttributes.StrokeWidth;
1538 0 : double fConsumed = 0;
1539 : basegfx::B2DPolyPolygon aArrow(basegfx::tools::createAreaGeometryForLineStartEnd(
1540 : rPolygon, rLineCap, bStart,
1541 0 : fWidth, fPolyLength, 0, &fConsumed, fShift));
1542 :
1543 : // createAreaGeometryForLineStartEnd from some reason always sets
1544 : // the path as closed, correct it
1545 0 : aArrow.setClosed(rLineCap.isClosed());
1546 :
1547 : // If the endcap is filled, we draw ONLY the filling, if it isn't
1548 : // filled we draw ONLY the outline, but never both.
1549 0 : if (bIsFilled)
1550 : {
1551 0 : bool bWasFillColorSet = rState.isFillColorSet;
1552 0 : rState.isFillColorSet = true;
1553 0 : rState.fillColor = rState.lineColor;
1554 0 : ActionSharedPtr pAction2(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState));
1555 0 : if (pAction2)
1556 : {
1557 0 : maActions.push_back(MtfAction(pAction2, rParms.mrCurrActionIndex));
1558 0 : rParms.mrCurrActionIndex += pAction2->getActionCount()-1;
1559 : }
1560 0 : rState.isFillColorSet = bWasFillColorSet;
1561 : }
1562 : else
1563 : {
1564 0 : ActionSharedPtr pAction(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState, rAttributes));
1565 0 : if (pAction)
1566 : {
1567 0 : maActions.push_back(MtfAction(pAction, rParms.mrCurrActionIndex));
1568 0 : rParms.mrCurrActionIndex += pAction->getActionCount()-1;
1569 0 : }
1570 : }
1571 :
1572 : // There isn't any clear definition of how far the line should extend
1573 : // for arrows, however the following values seem to give best results
1574 : // (fConsumed/2 draws the line to the center-point of the endcap
1575 : // for filled caps -- however it is likely this will need to be
1576 : // changed once we start taking baseInset into account).
1577 0 : if (bIsFilled)
1578 0 : return fConsumed/2;
1579 : else
1580 0 : return rAttributes.StrokeWidth;
1581 : }
1582 :
1583 0 : void ImplRenderer::EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
1584 : OutDevState& rState, const CanvasSharedPtr& rCanvas, sal_uInt32 penIndex)
1585 : {
1586 0 : EMFPPen* pen = static_cast<EMFPPen*>( aObjects [penIndex & 0xff] );
1587 :
1588 : SAL_WARN_IF( !pen, "cppcanvas.emf", "emf+ missing pen" );
1589 :
1590 0 : if (pen)
1591 : {
1592 0 : rState.isFillColorSet = false;
1593 0 : rState.isLineColorSet = true;
1594 0 : rState.lineColor = ::vcl::unotools::colorToDoubleSequence (pen->GetColor (),
1595 0 : rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace());
1596 :
1597 0 : basegfx::B2DPolyPolygon aPolyPolygon(polygon);
1598 0 : aPolyPolygon.transform(rState.mapModeTransform);
1599 0 : rendering::StrokeAttributes aCommonAttributes;
1600 :
1601 : // some attributes are common for the polygon, and the line
1602 : // starts & ends - like the stroke width
1603 0 : pen->SetStrokeWidth(aCommonAttributes, *this, rState);
1604 :
1605 : // but eg. dashing has to be additionally set only on the
1606 : // polygon
1607 0 : rendering::StrokeAttributes aPolygonAttributes(aCommonAttributes);
1608 0 : pen->SetStrokeAttributes(aPolygonAttributes);
1609 :
1610 0 : basegfx::B2DPolyPolygon aFinalPolyPolygon;
1611 :
1612 : // render line starts & ends if present
1613 0 : if (!pen->customStartCap && !pen->customEndCap)
1614 0 : aFinalPolyPolygon = aPolyPolygon;
1615 : else
1616 : {
1617 0 : for (sal_uInt32 i = 0; i < aPolyPolygon.count(); ++i)
1618 : {
1619 0 : basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(i));
1620 :
1621 0 : if (!aPolygon.isClosed())
1622 : {
1623 0 : double fStart = 0.0;
1624 0 : double fEnd = 0.0;
1625 0 : double fPolyLength = basegfx::tools::getLength(aPolygon);
1626 :
1627 : // line start
1628 0 : if (pen->customStartCap)
1629 : {
1630 0 : rendering::StrokeAttributes aAttributes(aCommonAttributes);
1631 0 : pen->customStartCap->SetAttributes(aAttributes);
1632 :
1633 : fStart = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon,
1634 : pen->customStartCap->mbIsFilled,
1635 0 : true, aAttributes, rParms, rState);
1636 : }
1637 :
1638 : // line end
1639 0 : if (pen->customEndCap)
1640 : {
1641 0 : rendering::StrokeAttributes aAttributes(aCommonAttributes);
1642 0 : pen->customEndCap->SetAttributes(aAttributes);
1643 :
1644 : fEnd = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon,
1645 : pen->customEndCap->mbIsFilled,
1646 0 : false, aAttributes, rParms, rState);
1647 : }
1648 :
1649 : // build new poly, consume something from the old poly
1650 0 : if (fStart != 0.0 || fEnd != 0.0)
1651 0 : aPolygon = basegfx::tools::getSnippetAbsolute(aPolygon, fStart, fPolyLength - fEnd, fPolyLength);
1652 : }
1653 :
1654 0 : aFinalPolyPolygon.append(aPolygon);
1655 0 : }
1656 : }
1657 :
1658 : // finally render the polygon
1659 0 : ActionSharedPtr pPolyAction(internal::PolyPolyActionFactory::createPolyPolyAction(aFinalPolyPolygon, rParms.mrCanvas, rState, aPolygonAttributes));
1660 0 : if( pPolyAction )
1661 : {
1662 0 : maActions.push_back(MtfAction(pPolyAction, rParms.mrCurrActionIndex));
1663 0 : rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1664 0 : }
1665 : }
1666 0 : }
1667 :
1668 0 : void ImplRenderer::processObjectRecord(SvMemoryStream& rObjectStream, sal_uInt16 flags, sal_uInt32 dataSize, bool bUseWholeStream)
1669 : {
1670 : sal_uInt32 index;
1671 :
1672 : SAL_INFO("cppcanvas.emf", "EMF+ Object slot: " << (flags & 0xff) << " flags: " << (flags & 0xff00));
1673 :
1674 0 : index = flags & 0xff;
1675 0 : if (aObjects [index] != NULL) {
1676 0 : delete aObjects [index];
1677 0 : aObjects [index] = NULL;
1678 : }
1679 :
1680 0 : switch (flags & 0x7f00) {
1681 : case EmfPlusObjectTypeBrush:
1682 : {
1683 : EMFPBrush *brush;
1684 0 : aObjects [index] = brush = new EMFPBrush ();
1685 0 : brush->Read (rObjectStream, *this);
1686 :
1687 0 : break;
1688 : }
1689 : case EmfPlusObjectTypePen:
1690 : {
1691 : EMFPPen *pen;
1692 0 : aObjects [index] = pen = new EMFPPen ();
1693 0 : pen->Read (rObjectStream, *this, nHDPI, nVDPI);
1694 :
1695 0 : break;
1696 : }
1697 : case EmfPlusObjectTypePath:
1698 : sal_uInt32 header, pathFlags;
1699 : sal_Int32 points;
1700 :
1701 0 : rObjectStream.ReadUInt32( header ).ReadInt32( points ).ReadUInt32( pathFlags );
1702 :
1703 : SAL_INFO("cppcanvas.emf", "EMF+\tpath");
1704 : SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " points: " << std::dec << points << " additional flags: 0x" << std::hex << pathFlags << std::dec);
1705 :
1706 : EMFPPath *path;
1707 0 : aObjects [index] = path = new EMFPPath (points);
1708 0 : path->Read (rObjectStream, pathFlags, *this);
1709 :
1710 0 : break;
1711 : case EmfPlusObjectTypeRegion: {
1712 : EMFPRegion *region;
1713 :
1714 0 : aObjects [index] = region = new EMFPRegion ();
1715 0 : region->Read (rObjectStream);
1716 :
1717 0 : break;
1718 : }
1719 : case EmfPlusObjectTypeImage:
1720 : {
1721 : EMFPImage *image;
1722 0 : aObjects [index] = image = new EMFPImage ();
1723 0 : image->Read (rObjectStream, dataSize, bUseWholeStream);
1724 :
1725 0 : break;
1726 : }
1727 : case EmfPlusObjectTypeFont:
1728 : {
1729 : EMFPFont *font;
1730 0 : aObjects [index] = font = new EMFPFont ();
1731 0 : font->Read (rObjectStream);
1732 :
1733 0 : break;
1734 : }
1735 : case EmfPlusObjectTypeStringFormat:
1736 : {
1737 : SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'string format' not yet implemented");
1738 0 : break;
1739 : }
1740 : case EmfPlusObjectTypeImageAttributes:
1741 : {
1742 : SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'image attributes' not yet implemented");
1743 0 : break;
1744 : }
1745 : case EmfPlusObjectTypeCustomLineCap:
1746 : {
1747 : SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'custom line cap' not yet implemented");
1748 0 : break;
1749 : }
1750 : default:
1751 : SAL_INFO("cppcanvas.emf", "EMF+\tObject unhandled flags: 0x" << std::hex << (flags & 0xff00) << std::dec);
1752 0 : break;
1753 : }
1754 0 : }
1755 :
1756 0 : double ImplRenderer::setFont (sal_uInt8 objectId, const ActionFactoryParameters& rParms, OutDevState& rState)
1757 : {
1758 0 : EMFPFont *font = static_cast<EMFPFont*>( aObjects[ objectId ] );
1759 :
1760 0 : rendering::FontRequest aFontRequest;
1761 0 : aFontRequest.FontDescription.FamilyName = font->family;
1762 0 : double cellSize = font->emSize;
1763 0 : aFontRequest.CellSize = (rState.mapModeTransform*MapSize( cellSize, 0 )).getX();
1764 0 : rState.xFont = rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest,
1765 : uno::Sequence< beans::PropertyValue >(),
1766 0 : geometry::Matrix2D() );
1767 :
1768 0 : return cellSize;
1769 : }
1770 :
1771 0 : void ImplRenderer::GraphicStatePush(GraphicStateMap& map, sal_Int32 index, OutDevState& rState)
1772 : {
1773 0 : GraphicStateMap::iterator iter = map.find( index );
1774 :
1775 0 : if ( iter != map.end() )
1776 : {
1777 0 : EmfPlusGraphicState state = iter->second;
1778 0 : map.erase( iter );
1779 :
1780 0 : SAL_INFO("cppcanvas.emf", "stack index: " << index << " found and erased");
1781 : }
1782 :
1783 0 : EmfPlusGraphicState state;
1784 :
1785 0 : state.aWorldTransform = aWorldTransform;
1786 0 : state.aDevState = rState;
1787 :
1788 0 : map[ index ] = state;
1789 0 : }
1790 :
1791 0 : void ImplRenderer::GraphicStatePop(GraphicStateMap& map, sal_Int32 index, OutDevState& rState)
1792 : {
1793 0 : GraphicStateMap::iterator iter = map.find( index );
1794 :
1795 0 : if ( iter != map.end() )
1796 : {
1797 : SAL_INFO("cppcanvas.emf", "stack index: " << index << " found");
1798 :
1799 0 : EmfPlusGraphicState state = iter->second;
1800 :
1801 0 : aWorldTransform = state.aWorldTransform;
1802 0 : rState.clip = state.aDevState.clip;
1803 0 : rState.clipRect = state.aDevState.clipRect;
1804 0 : rState.xClipPoly = state.aDevState.xClipPoly;
1805 : }
1806 0 : }
1807 :
1808 0 : void ImplRenderer::processEMFPlus( MetaCommentAction* pAct, const ActionFactoryParameters& rFactoryParms,
1809 : OutDevState& rState, const CanvasSharedPtr& rCanvas )
1810 : {
1811 0 : sal_uInt32 length = pAct->GetDataSize ();
1812 0 : SvMemoryStream rMF ((void*) pAct->GetData (), length, STREAM_READ);
1813 :
1814 0 : length -= 4;
1815 :
1816 0 : while (length > 0) {
1817 : sal_uInt16 type, flags;
1818 : sal_uInt32 size, dataSize;
1819 : sal_Size next;
1820 :
1821 0 : rMF.ReadUInt16( type ).ReadUInt16( flags ).ReadUInt32( size ).ReadUInt32( dataSize );
1822 :
1823 0 : next = rMF.Tell() + ( size - 12 );
1824 :
1825 0 : if (size < 12) {
1826 : SAL_INFO("cppcanvas.emf", "Size field is less than 12 bytes");
1827 : }
1828 :
1829 : SAL_INFO("cppcanvas.emf", "EMF+ record size: " << size << " type: " << emfTypeToName(type) << " flags: " << flags << " data size: " << dataSize);
1830 :
1831 0 : if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000))) {
1832 0 : if (!mbMultipart) {
1833 0 : mbMultipart = true;
1834 0 : mMFlags = flags;
1835 0 : mMStream.Seek(0);
1836 : }
1837 :
1838 : // 1st 4 bytes are unknown
1839 0 : mMStream.Write (((const char *)rMF.GetData()) + rMF.Tell() + 4, dataSize - 4);
1840 0 : SAL_INFO("cppcanvas.emf", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
1841 : } else {
1842 0 : if (mbMultipart) {
1843 : SAL_INFO("cppcanvas.emf", "EMF+ multipart record flags: " << mMFlags);
1844 0 : mMStream.Seek (0);
1845 0 : processObjectRecord (mMStream, mMFlags, dataSize, true);
1846 : }
1847 0 : mbMultipart = false;
1848 : }
1849 :
1850 0 : if (type != EmfPlusRecordTypeObject || !(flags & 0x8000))
1851 : {
1852 0 : switch (type) {
1853 : case EmfPlusRecordTypeHeader:
1854 : sal_uInt32 header, version;
1855 :
1856 0 : rMF.ReadUInt32( header ).ReadUInt32( version ).ReadInt32( nHDPI ).ReadInt32( nVDPI );
1857 :
1858 : SAL_INFO("cppcanvas.emf", "EMF+ Header");
1859 : SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " version: " << std::dec << version << " horizontal DPI: " << nHDPI << " vertical DPI: " << nVDPI << " dual: " << (flags & 1));
1860 :
1861 0 : break;
1862 : case EmfPlusRecordTypeEndOfFile:
1863 : SAL_INFO("cppcanvas.emf", "EMF+ EndOfFile");
1864 0 : break;
1865 : case EmfPlusRecordTypeGetDC:
1866 : SAL_INFO("cppcanvas.emf", "EMF+ GetDC");
1867 : SAL_INFO("cppcanvas.emf", "EMF+\talready used in svtools wmf/emf filter parser");
1868 0 : break;
1869 : case EmfPlusRecordTypeObject:
1870 0 : processObjectRecord (rMF, flags, dataSize);
1871 0 : break;
1872 : case EmfPlusRecordTypeFillPie:
1873 : {
1874 : sal_uInt32 brushIndexOrColor;
1875 : float startAngle, sweepAngle;
1876 :
1877 0 : rMF.ReadUInt32( brushIndexOrColor ).ReadFloat( startAngle ).ReadFloat( sweepAngle );
1878 :
1879 : SAL_INFO("cppcanvas.emf", "EMF+ FillPie colorOrIndex: " << brushIndexOrColor << " startAngle: " << startAngle << " sweepAngle: " << sweepAngle);
1880 :
1881 : float dx, dy, dw, dh;
1882 :
1883 0 : ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1884 :
1885 : SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1886 :
1887 0 : startAngle = 2*M_PI*startAngle/360;
1888 0 : sweepAngle = 2*M_PI*sweepAngle/360;
1889 :
1890 0 : B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
1891 0 : B2DSize mappedSize( MapSize (dw/2, dh/2));
1892 :
1893 0 : float endAngle = startAngle + sweepAngle;
1894 0 : startAngle = fmodf(startAngle, static_cast<float>(M_PI*2));
1895 0 : if (startAngle < 0)
1896 0 : startAngle += static_cast<float>(M_PI*2);
1897 0 : endAngle = fmodf(endAngle, static_cast<float>(M_PI*2));
1898 0 : if (endAngle < 0)
1899 0 : endAngle += static_cast<float>(M_PI*2);
1900 :
1901 0 : if (sweepAngle < 0)
1902 0 : std::swap (endAngle, startAngle);
1903 :
1904 : SAL_INFO("cppcanvas.emf", "EMF+ adjusted angles: start " <<
1905 : (360.0*startAngle/M_PI) << ", end: " << (360.0*endAngle/M_PI));
1906 :
1907 0 : B2DPolygon polygon = basegfx::tools::createPolygonFromEllipseSegment (mappedCenter, mappedSize.getX (), mappedSize.getY (), startAngle, endAngle);
1908 0 : polygon.append (mappedCenter);
1909 0 : polygon.setClosed (true);
1910 :
1911 0 : B2DPolyPolygon polyPolygon (polygon);
1912 0 : EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1913 : }
1914 0 : break;
1915 : case EmfPlusRecordTypeFillPath:
1916 : {
1917 0 : sal_uInt32 index = flags & 0xff;
1918 : sal_uInt32 brushIndexOrColor;
1919 :
1920 0 : rMF.ReadUInt32( brushIndexOrColor );
1921 :
1922 : SAL_INFO("cppcanvas.emf", "EMF+ FillPath slot: " << index);
1923 :
1924 0 : EMFPPlusFillPolygon( static_cast<EMFPPath*>( aObjects [index])->GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1925 : }
1926 0 : break;
1927 : case EmfPlusRecordTypeDrawEllipse:
1928 : case EmfPlusRecordTypeFillEllipse:
1929 : {
1930 : // Intentionally very bogus initial value to avoid MSVC complaining about potentially uninitialized local
1931 : // variable. As long as the code stays as intended, this variable will be assigned a (real) value in the case
1932 : // when it is later used.
1933 0 : sal_uInt32 brushIndexOrColor = 1234567;
1934 :
1935 0 : if ( type == EmfPlusRecordTypeFillEllipse )
1936 0 : rMF.ReadUInt32( brushIndexOrColor );
1937 :
1938 : SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeFillEllipse ? "Fill" : "Draw") << "Ellipse slot: " << (flags & 0xff));
1939 :
1940 : float dx, dy, dw, dh;
1941 :
1942 0 : ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1943 :
1944 : SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1945 :
1946 0 : B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
1947 0 : B2DSize mappedSize( MapSize (dw/2, dh/2));
1948 :
1949 0 : ::basegfx::B2DPolyPolygon polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromEllipse( mappedCenter, mappedSize.getX (), mappedSize.getY () ) ) );
1950 :
1951 0 : if ( type == EmfPlusRecordTypeFillEllipse )
1952 : EMFPPlusFillPolygon( polyPolygon,
1953 0 : rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor );
1954 : else
1955 : EMFPPlusDrawPolygon( polyPolygon,
1956 0 : rFactoryParms, rState, rCanvas, flags & 0xff );
1957 : }
1958 0 : break;
1959 : case EmfPlusRecordTypeFillRects:
1960 : {
1961 : SAL_INFO("cppcanvas.emf", "EMF+ FillRects");
1962 :
1963 : sal_uInt32 brushIndexOrColor;
1964 : sal_Int32 rectangles;
1965 0 : bool isColor = (flags & 0x8000);
1966 0 : ::basegfx::B2DPolygon polygon;
1967 :
1968 0 : rMF.ReadUInt32( brushIndexOrColor ).ReadInt32( rectangles );
1969 :
1970 : SAL_INFO("cppcanvas.emf", "EMF+\t" << ((flags & 0x8000) ? "color" : "brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
1971 :
1972 0 : for (int i=0; i < rectangles; i++) {
1973 0 : if (flags & 0x4000) {
1974 : /* 16bit integers */
1975 : sal_Int16 x, y, width, height;
1976 :
1977 0 : rMF.ReadInt16( x ).ReadInt16( y ).ReadInt16( width ).ReadInt16( height );
1978 :
1979 0 : polygon.append (Map (x, y));
1980 0 : polygon.append (Map (x + width, y));
1981 0 : polygon.append (Map (x + width, y + height));
1982 0 : polygon.append (Map (x, y + height));
1983 :
1984 : SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x << ", " << width << "x" << height);
1985 : } else {
1986 : /* Single's */
1987 : float x, y, width, height;
1988 :
1989 0 : rMF.ReadFloat( x ).ReadFloat( y ).ReadFloat( width ).ReadFloat( height );
1990 :
1991 0 : polygon.append (Map (x, y));
1992 0 : polygon.append (Map (x + width, y));
1993 0 : polygon.append (Map (x + width, y + height));
1994 0 : polygon.append (Map (x, y + height));
1995 :
1996 : SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x << ", " << width << "x" << height);
1997 : }
1998 :
1999 0 : ::basegfx::B2DPolyPolygon polyPolygon (polygon);
2000 :
2001 0 : EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, isColor, brushIndexOrColor);
2002 0 : }
2003 0 : break;
2004 : }
2005 : case EmfPlusRecordTypeFillPolygon:
2006 : {
2007 0 : sal_uInt8 index = flags & 0xff;
2008 : sal_uInt32 brushIndexOrColor;
2009 : sal_Int32 points;
2010 :
2011 0 : rMF.ReadUInt32( brushIndexOrColor );
2012 0 : rMF.ReadInt32( points );
2013 :
2014 : SAL_INFO("cppcanvas.emf", "EMF+ FillPolygon in slot: " << +index << " points: " << points);
2015 : SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags & 0x8000) ? "color" : "brush index") << " 0x" << std::hex << brushIndexOrColor << std::dec);
2016 :
2017 0 : EMFPPath path (points, true);
2018 0 : path.Read (rMF, flags, *this);
2019 :
2020 0 : EMFPPlusFillPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
2021 :
2022 0 : break;
2023 : }
2024 : case EmfPlusRecordTypeDrawLines:
2025 : {
2026 : sal_uInt32 points;
2027 :
2028 0 : rMF.ReadUInt32( points );
2029 :
2030 : SAL_INFO("cppcanvas.emf", "EMF+ DrawLines in slot: " << (flags & 0xff) << " points: " << points);
2031 :
2032 0 : EMFPPath path (points, true);
2033 0 : path.Read (rMF, flags, *this);
2034 :
2035 0 : EMFPPlusDrawPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags);
2036 :
2037 0 : break;
2038 : }
2039 : case EmfPlusRecordTypeDrawPath:
2040 : {
2041 : sal_uInt32 penIndex;
2042 :
2043 0 : rMF.ReadUInt32( penIndex );
2044 :
2045 : SAL_INFO("cppcanvas.emf", "EMF+ DrawPath");
2046 : SAL_INFO("cppcanvas.emf", "EMF+\tpen: " << penIndex);
2047 :
2048 0 : EMFPPath* path = static_cast<EMFPPath*>( aObjects [flags & 0xff] );
2049 : SAL_WARN_IF( !path, "cppcanvas.emf", "EmfPlusRecordTypeDrawPath missing path" );
2050 :
2051 0 : EMFPPlusDrawPolygon (path->GetPolygon (*this), rFactoryParms, rState, rCanvas, penIndex);
2052 :
2053 0 : break;
2054 : }
2055 : case EmfPlusRecordTypeDrawImage:
2056 : case EmfPlusRecordTypeDrawImagePoints:
2057 : {
2058 : sal_uInt32 attrIndex;
2059 : sal_Int32 sourceUnit;
2060 :
2061 0 : rMF.ReadUInt32( attrIndex ).ReadInt32( sourceUnit );
2062 :
2063 : SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << "attributes index: " << attrIndex << "source unit: " << sourceUnit);
2064 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO: use image attributes");
2065 :
2066 0 : if (sourceUnit == 2 && aObjects [flags & 0xff]) { // we handle only GraphicsUnit.Pixel now
2067 0 : EMFPImage& image = *static_cast<EMFPImage *>( aObjects [flags & 0xff]);
2068 : float sx, sy, sw, sh;
2069 : sal_Int32 aCount;
2070 :
2071 0 : ReadRectangle (rMF, sx, sy, sw, sh);
2072 0 : Rectangle aSource(Point(sx, sy), Size(sw, sh));
2073 :
2074 : SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << " source rectangle: " << sx << "," << sy << " " << sw << "x" << sh);
2075 :
2076 0 : ::basegfx::B2DPoint aDstPoint;
2077 0 : ::basegfx::B2DSize aDstSize;
2078 0 : bool bValid = false;
2079 :
2080 0 : if (type == EmfPlusRecordTypeDrawImagePoints) {
2081 0 : rMF.ReadInt32( aCount );
2082 :
2083 0 : if( aCount == 3) { // TODO: now that we now that this value is count we should support it better
2084 : float x1, y1, x2, y2, x3, y3;
2085 :
2086 0 : ReadPoint (rMF, x1, y1, flags);
2087 0 : ReadPoint (rMF, x2, y2, flags);
2088 0 : ReadPoint (rMF, x3, y3, flags);
2089 :
2090 : SAL_INFO("cppcanvas.emf", "EMF+ destination points: " << x1 << "," << y1 << " " << x2 << "," << y2 << " " << x3 << "," << y3);
2091 : SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << x1 << "," << y1 << " " << x2 - x1 << "x" << y3 - y1);
2092 :
2093 0 : aDstPoint = Map (x1, y1);
2094 0 : aDstSize = MapSize(x2 - x1, y3 - y1);
2095 :
2096 0 : bValid = true;
2097 : }
2098 0 : } else if (type == EmfPlusRecordTypeDrawImage) {
2099 : float dx, dy, dw, dh;
2100 :
2101 0 : ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
2102 :
2103 : SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
2104 :
2105 0 : aDstPoint = Map (dx, dy);
2106 0 : aDstSize = MapSize(dw, dh);
2107 :
2108 0 : bValid = true;
2109 : }
2110 :
2111 0 : if (bValid) {
2112 0 : BitmapEx aBmp( image.graphic.GetBitmapEx () );
2113 0 : aBmp.Crop( aSource );
2114 :
2115 0 : Size aSize( aBmp.GetSizePixel() );
2116 : SAL_INFO("cppcanvas.emf", "EMF+ bitmap size: " << aSize.Width() << "x" << aSize.Height());
2117 0 : if( aSize.Width() > 0 && aSize.Height() > 0 ) {
2118 : ActionSharedPtr pBmpAction (
2119 : internal::BitmapActionFactory::createBitmapAction (
2120 : aBmp,
2121 0 : rState.mapModeTransform * aDstPoint,
2122 0 : rState.mapModeTransform * aDstSize,
2123 : rCanvas,
2124 0 : rState));
2125 :
2126 0 : if( pBmpAction ) {
2127 : maActions.push_back( MtfAction( pBmpAction,
2128 0 : rFactoryParms.mrCurrActionIndex ) );
2129 :
2130 0 : rFactoryParms.mrCurrActionIndex += pBmpAction->getActionCount()-1;
2131 0 : }
2132 : } else {
2133 : SAL_INFO("cppcanvas.emf", "EMF+ warning: empty bitmap");
2134 0 : }
2135 : } else {
2136 : SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme)");
2137 0 : }
2138 : } else {
2139 : SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme) - possibly unsupported source units for crop rectangle");
2140 : }
2141 0 : break;
2142 : }
2143 : case EmfPlusRecordTypeDrawString:
2144 : {
2145 : SAL_INFO("cppcanvas.emf", "EMF+ DrawString");
2146 :
2147 : sal_uInt32 brushId;
2148 : sal_uInt32 formatId;
2149 : sal_uInt32 stringLength;
2150 :
2151 0 : rMF.ReadUInt32( brushId ).ReadUInt32( formatId ).ReadUInt32( stringLength );
2152 : SAL_INFO("cppcanvas.emf", "EMF+ DrawString brushId: " << brushId << " formatId: " << formatId << " length: " << stringLength);
2153 :
2154 0 : if (flags & 0x8000) {
2155 : float lx, ly, lw, lh;
2156 :
2157 0 : rMF.ReadFloat( lx ).ReadFloat( ly ).ReadFloat( lw ).ReadFloat( lh );
2158 :
2159 : SAL_INFO("cppcanvas.emf", "EMF+ DrawString layoutRect: " << lx << "," << ly << " - " << lw << "x" << lh);
2160 :
2161 0 : OUString text = read_uInt16s_ToOUString(rMF, stringLength);
2162 :
2163 0 : double cellSize = setFont (flags & 0xff, rFactoryParms, rState);
2164 0 : rState.textColor = COLOR( brushId );
2165 :
2166 0 : ::basegfx::B2DPoint point( Map( lx + 0.15*cellSize, ly + cellSize ) );
2167 :
2168 : ActionSharedPtr pTextAction(
2169 : TextActionFactory::createTextAction(
2170 : // position is just rough guess for now
2171 : // we should calculate it exactly from layoutRect or font
2172 : ::vcl::unotools::pointFromB2DPoint ( point ),
2173 : ::Size(),
2174 : ::Color(),
2175 : ::Size(),
2176 : ::Color(),
2177 : text,
2178 : 0,
2179 : stringLength,
2180 : NULL,
2181 : rFactoryParms.mrVDev,
2182 : rFactoryParms.mrCanvas,
2183 : rState,
2184 : rFactoryParms.mrParms,
2185 0 : false ) );
2186 0 : if( pTextAction )
2187 : {
2188 : SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
2189 :
2190 : maActions.push_back(
2191 : MtfAction(
2192 : pTextAction,
2193 0 : rFactoryParms.mrCurrActionIndex ) );
2194 :
2195 0 : rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
2196 0 : }
2197 : } else {
2198 : SAL_INFO("cppcanvas.emf", "EMF+ DrawString TODO - drawing with brush not yet supported");
2199 : }
2200 : }
2201 0 : break;
2202 : case EmfPlusRecordTypeSetPageTransform:
2203 0 : rMF.ReadFloat( fPageScale );
2204 :
2205 : SAL_INFO("cppcanvas.emf", "EMF+ SetPageTransform");
2206 : SAL_INFO("cppcanvas.emf", "EMF+\tscale: " << fPageScale << " unit: " << flags);
2207 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2208 0 : break;
2209 : case EmfPlusRecordTypeSetRenderingOrigin:
2210 0 : rMF.ReadInt32( nOriginX ).ReadInt32( nOriginY );
2211 : SAL_INFO("cppcanvas.emf", "EMF+ SetRenderingOrigin");
2212 : SAL_INFO("cppcanvas.emf", "EMF+\torigin [x,y]: " << nOriginX << "," << nOriginY);
2213 0 : break;
2214 : case EmfPlusRecordTypeSetTextRenderingHint:
2215 : SAL_INFO("cppcanvas.emf", "EMF+ SetTextRenderingHint");
2216 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2217 0 : break;
2218 : case EmfPlusRecordTypeSetAntiAliasMode:
2219 : SAL_INFO("cppcanvas.emf", "EMF+ SetAntiAliasMode");
2220 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2221 0 : break;
2222 : case EmfPlusRecordTypeSetInterpolationMode:
2223 : SAL_INFO("cppcanvas.emf", "EMF+ InterpolationMode");
2224 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2225 0 : break;
2226 : case EmfPlusRecordTypeSetPixelOffsetMode:
2227 : SAL_INFO("cppcanvas.emf", "EMF+ SetPixelOffsetMode");
2228 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2229 0 : break;
2230 : case EmfPlusRecordTypeSetCompositingQuality:
2231 : SAL_INFO("cppcanvas.emf", "EMF+ SetCompositingQuality");
2232 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2233 0 : break;
2234 : case EmfPlusRecordTypeSave:
2235 : {
2236 : sal_uInt32 stackIndex;
2237 :
2238 0 : rMF.ReadUInt32( stackIndex );
2239 :
2240 : SAL_INFO("cppcanvas.emf", "EMF+ Save stack index: " << stackIndex);
2241 :
2242 0 : GraphicStatePush( mGSStack, stackIndex, rState );
2243 :
2244 0 : break;
2245 : }
2246 : case EmfPlusRecordTypeRestore:
2247 : {
2248 : sal_uInt32 stackIndex;
2249 :
2250 0 : rMF.ReadUInt32( stackIndex );
2251 :
2252 : SAL_INFO("cppcanvas.emf", "EMF+ Restore stack index: " << stackIndex);
2253 :
2254 0 : GraphicStatePop( mGSStack, stackIndex, rState );
2255 :
2256 0 : break;
2257 : }
2258 : case EmfPlusRecordTypeBeginContainerNoParams:
2259 : {
2260 : sal_uInt32 stackIndex;
2261 :
2262 0 : rMF.ReadUInt32( stackIndex );
2263 :
2264 : SAL_INFO("cppcanvas.emf", "EMF+ Begin Container No Params stack index: " << stackIndex);
2265 :
2266 0 : GraphicStatePush( mGSContainerStack, stackIndex, rState );
2267 : }
2268 0 : break;
2269 : case EmfPlusRecordTypeEndContainer:
2270 : {
2271 : sal_uInt32 stackIndex;
2272 :
2273 0 : rMF.ReadUInt32( stackIndex );
2274 :
2275 : SAL_INFO("cppcanvas.emf", "EMF+ End Container stack index: " << stackIndex);
2276 :
2277 0 : GraphicStatePop( mGSContainerStack, stackIndex, rState );
2278 : }
2279 0 : break;
2280 : case EmfPlusRecordTypeSetWorldTransform: {
2281 : SAL_INFO("cppcanvas.emf", "EMF+ SetWorldTransform");
2282 0 : XForm transform;
2283 0 : ReadXForm( rMF, transform );
2284 0 : aWorldTransform.Set (transform);
2285 : SAL_INFO("cppcanvas.emf",
2286 : "EMF+\tm11: " << aWorldTransform.eM11 << "\tm12: " << aWorldTransform.eM12 <<
2287 : "\tm21: " << aWorldTransform.eM21 << "\tm22: " << aWorldTransform.eM22 <<
2288 : "\tdx: " << aWorldTransform.eDx << "\tdy: " << aWorldTransform.eDy);
2289 0 : break;
2290 : }
2291 : case EmfPlusRecordTypeResetWorldTransform:
2292 : SAL_INFO("cppcanvas.emf", "EMF+ ResetWorldTransform");
2293 0 : aWorldTransform.SetIdentity ();
2294 0 : break;
2295 : case EmfPlusRecordTypeMultiplyWorldTransform: {
2296 : SAL_INFO("cppcanvas.emf", "EMF+ MultiplyWorldTransform");
2297 0 : XForm transform;
2298 0 : ReadXForm( rMF, transform );
2299 :
2300 : SAL_INFO("cppcanvas.emf",
2301 : "EMF+\tmatrix m11: " << transform.eM11 << "m12: " << transform.eM12 <<
2302 : "EMF+\tm21: " << transform.eM21 << "m22: " << transform.eM22 <<
2303 : "EMF+\tdx: " << transform.eDx << "dy: " << transform.eDy);
2304 :
2305 0 : if (flags & 0x2000) // post multiply
2306 0 : aWorldTransform.Multiply (transform);
2307 : else { // pre multiply
2308 0 : transform.Multiply (aWorldTransform);
2309 0 : aWorldTransform.Set (transform);
2310 : }
2311 : SAL_INFO("cppcanvas.emf",
2312 : "EMF+\tm11: " << aWorldTransform.eM11 << "m12: " << aWorldTransform.eM12 <<
2313 : "EMF+\tm21: " << aWorldTransform.eM21 << "m22: " << aWorldTransform.eM22 <<
2314 : "EMF+\tdx: " << aWorldTransform.eDx << "dy: " << aWorldTransform.eDy);
2315 0 : break;
2316 : }
2317 : case EmfPlusRecordTypeSetClipRect:
2318 : {
2319 0 : int combineMode = (flags >> 8) & 0xf;
2320 :
2321 : SAL_INFO("cppcanvas.emf", "EMF+ SetClipRect combine mode: " << combineMode);
2322 : #if OSL_DEBUG_LEVEL > 1
2323 : if (combineMode > 1) {
2324 : SAL_INFO ("cppcanvas.emf", "EMF+ TODO combine mode > 1");
2325 : }
2326 : #endif
2327 :
2328 : float dx, dy, dw, dh;
2329 :
2330 0 : ReadRectangle (rMF, dx, dy, dw, dh, false);
2331 :
2332 : SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
2333 :
2334 0 : B2DPoint mappedPoint (Map (dx, dy));
2335 0 : B2DSize mappedSize( MapSize (dw, dh));
2336 :
2337 : ::basegfx::B2DPolyPolygon polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromRect( ::basegfx::B2DRectangle( mappedPoint.getX(), mappedPoint.getY(),
2338 0 : mappedPoint.getX() + mappedSize.getX(),
2339 0 : mappedPoint.getY() + mappedSize.getY() ) ) ) );
2340 0 : polyPolygon.transform(rState.mapModeTransform);
2341 :
2342 0 : updateClipping (polyPolygon, rFactoryParms, combineMode == 1);
2343 :
2344 0 : break;
2345 : }
2346 : case EmfPlusRecordTypeSetClipPath:
2347 : {
2348 0 : int combineMode = (flags >> 8) & 0xf;
2349 :
2350 : SAL_INFO("cppcanvas.emf", "EMF+ SetClipPath combine mode: " << combineMode);
2351 : SAL_INFO("cppcanvas.emf", "EMF+\tpath in slot: " << (flags & 0xff));
2352 :
2353 0 : EMFPPath& path = *static_cast<EMFPPath*>( aObjects [flags & 0xff] );
2354 0 : ::basegfx::B2DPolyPolygon& clipPoly (path.GetPolygon (*this));
2355 :
2356 0 : clipPoly.transform (rState.mapModeTransform);
2357 0 : switch (combineMode)
2358 : {
2359 : case EmfPlusCombineModeReplace:
2360 : case EmfPlusCombineModeIntersect:
2361 : case EmfPlusCombineModeUnion: // Is this, EmfPlusCombineModeXOR and EmfPlusCombineModeComplement correct?
2362 : case EmfPlusCombineModeXOR:
2363 : case EmfPlusCombineModeComplement:
2364 0 : updateClipping (clipPoly, rFactoryParms, combineMode == 1);
2365 0 : break;
2366 : case EmfPlusCombineModeExclude:
2367 : // Not doing anything is better then including exactly what we wanted to exclude.
2368 0 : break;
2369 : }
2370 :
2371 0 : break;
2372 : }
2373 : case EmfPlusRecordTypeSetClipRegion: {
2374 0 : int combineMode = (flags >> 8) & 0xf;
2375 :
2376 : SAL_INFO("cppcanvas.emf", "EMF+ SetClipRegion");
2377 : SAL_INFO("cppcanvas.emf", "EMF+\tregion in slot: " << (flags & 0xff) << " combine mode: " << combineMode);
2378 0 : EMFPRegion *region = static_cast<EMFPRegion*>(aObjects [flags & 0xff]);
2379 :
2380 : // reset clip
2381 0 : if (region && region->parts == 0 && region->initialState == EmfPlusRegionInitialStateInfinite) {
2382 0 : updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms, combineMode == 1);
2383 : } else {
2384 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2385 : }
2386 0 : break;
2387 : }
2388 : case EmfPlusRecordTypeDrawDriverString: {
2389 : SAL_INFO("cppcanvas.emf", "EMF+ DrawDriverString, flags: 0x" << std::hex << flags << std::dec);
2390 : sal_uInt32 brushIndexOrColor;
2391 : sal_uInt32 optionFlags;
2392 : sal_uInt32 hasMatrix;
2393 : sal_uInt32 glyphsCount;
2394 :
2395 0 : rMF.ReadUInt32( brushIndexOrColor ).ReadUInt32( optionFlags ).ReadUInt32( hasMatrix ).ReadUInt32( glyphsCount );
2396 :
2397 : SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags & 0x8000) ? "color" : "brush index") << " 0x" << std::hex << brushIndexOrColor << std::dec);
2398 : SAL_INFO("cppcanvas.emf", "EMF+\toption flags: 0x" << std::hex << optionFlags << std::dec);
2399 : SAL_INFO("cppcanvas.emf", "EMF+\thas matrix: " << hasMatrix);
2400 : SAL_INFO("cppcanvas.emf", "EMF+\tglyphs: " << glyphsCount);
2401 :
2402 0 : if( ( optionFlags & 1 ) && glyphsCount > 0 ) {
2403 0 : float *charsPosX = new float[glyphsCount];
2404 0 : float *charsPosY = new float[glyphsCount];
2405 :
2406 0 : OUString text = read_uInt16s_ToOUString(rMF, glyphsCount);
2407 :
2408 0 : for( sal_uInt32 i=0; i<glyphsCount; i++) {
2409 0 : rMF.ReadFloat( charsPosX[i] ).ReadFloat( charsPosY[i] );
2410 : SAL_INFO("cppcanvas.emf", "EMF+\tglyphPosition[" << i << "]: " << charsPosX[i] << "," << charsPosY[i]);
2411 : }
2412 :
2413 0 : XForm transform;
2414 0 : if( hasMatrix ) {
2415 0 : ReadXForm( rMF, transform );
2416 : SAL_INFO("cppcanvas.emf", "EMF+\tmatrix: " << transform.eM11 << ", " << transform.eM12 << ", " << transform.eM21 << ", " << transform.eM22 << ", " << transform.eDx << ", " << transform.eDy);
2417 : }
2418 :
2419 : // add the text action
2420 0 : setFont (flags & 0xff, rFactoryParms, rState);
2421 :
2422 0 : if( flags & 0x8000 )
2423 0 : rState.textColor = COLOR( brushIndexOrColor );
2424 :
2425 0 : ::basegfx::B2DPoint point( Map( charsPosX[0], charsPosY[0] ) );
2426 :
2427 : ActionSharedPtr pTextAction(
2428 : TextActionFactory::createTextAction(
2429 : ::vcl::unotools::pointFromB2DPoint ( point ),
2430 : ::Size(),
2431 : ::Color(),
2432 : ::Size(),
2433 : ::Color(),
2434 : text,
2435 : 0,
2436 : glyphsCount,
2437 : NULL,
2438 : rFactoryParms.mrVDev,
2439 : rFactoryParms.mrCanvas,
2440 : rState,
2441 : rFactoryParms.mrParms,
2442 0 : false ) );
2443 :
2444 0 : if( pTextAction )
2445 : {
2446 : SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
2447 :
2448 : maActions.push_back(
2449 : MtfAction(
2450 : pTextAction,
2451 0 : rFactoryParms.mrCurrActionIndex ) );
2452 :
2453 0 : rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
2454 : }
2455 :
2456 0 : delete[] charsPosX;
2457 0 : delete[] charsPosY;
2458 : } else {
2459 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
2460 : }
2461 :
2462 0 : break;
2463 : }
2464 : default:
2465 : SAL_INFO("cppcanvas.emf", "EMF+ unhandled record type: " << type);
2466 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2467 : }
2468 : }
2469 :
2470 0 : rMF.Seek (next);
2471 :
2472 0 : if (size <= length)
2473 : {
2474 0 : length -= size;
2475 : }
2476 : else
2477 : {
2478 : SAL_WARN("cppcanvas.emf", "ImplRenderer::processEMFPlus: "
2479 : "size " << size << " > length " << length);
2480 0 : length = 0;
2481 : }
2482 0 : }
2483 0 : }
2484 : }
2485 1143 : }
2486 :
2487 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|