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