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