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/b2dpolygon.hxx>
32 : #include <basegfx/polygon/b2dpolygontools.hxx>
33 : #include <basegfx/polygon/b2dpolypolygon.hxx>
34 : #include <basegfx/polygon/b2dpolypolygontools.hxx>
35 : #include <vcl/canvastools.hxx>
36 : #include <rtl/ustring.hxx>
37 : #include <sal/alloca.h>
38 :
39 : #include <com/sun/star/rendering/XCanvas.hpp>
40 : #include <com/sun/star/rendering/TexturingMode.hpp>
41 :
42 : #include <bitmapaction.hxx>
43 : #include <implrenderer.hxx>
44 : #include <outdevstate.hxx>
45 : #include <polypolyaction.hxx>
46 : #include <textaction.hxx>
47 : #include <stdio.h>
48 :
49 : #define EmfPlusRecordTypeHeader 16385
50 : #define EmfPlusRecordTypeEndOfFile 16386
51 : #define EmfPlusRecordTypeGetDC 16388
52 : #define EmfPlusRecordTypeObject 16392
53 : #define EmfPlusRecordTypeFillRects 16394
54 : #define EmfPlusRecordTypeFillPolygon 16396
55 : #define EmfPlusRecordTypeDrawLines 16397
56 : #define EmfPlusRecordTypeFillEllipse 16398
57 : #define EmfPlusRecordTypeDrawEllipse 16399
58 : #define EmfPlusRecordTypeFillPie 16400
59 : #define EmfPlusRecordTypeFillPath 16404
60 : #define EmfPlusRecordTypeDrawPath 16405
61 : #define EmfPlusRecordTypeDrawImage 16410
62 : #define EmfPlusRecordTypeDrawImagePoints 16411
63 : #define EmfPlusRecordTypeDrawString 16412
64 : #define EmfPlusRecordTypeSetRenderingOrigin 16413
65 : #define EmfPlusRecordTypeSetAntiAliasMode 16414
66 : #define EmfPlusRecordTypeSetTextRenderingHint 16415
67 : #define EmfPlusRecordTypeSetInterpolationMode 16417
68 : #define EmfPlusRecordTypeSetPixelOffsetMode 16418
69 : #define EmfPlusRecordTypeSetCompositingQuality 16420
70 : #define EmfPlusRecordTypeSave 16421
71 : #define EmfPlusRecordTypeRestore 16422
72 : #define EmfPlusRecordTypeBeginContainerNoParams 16424
73 : #define EmfPlusRecordTypeEndContainer 16425
74 : #define EmfPlusRecordTypeSetWorldTransform 16426
75 : #define EmfPlusRecordTypeResetWorldTransform 16427
76 : #define EmfPlusRecordTypeMultiplyWorldTransform 16428
77 : #define EmfPlusRecordTypeSetPageTransform 16432
78 : #define EmfPlusRecordTypeSetClipRect 16434
79 : #define EmfPlusRecordTypeSetClipPath 16435
80 : #define EmfPlusRecordTypeSetClipRegion 16436
81 : #define EmfPlusRecordTypeDrawDriverString 16438
82 :
83 : #define EmfPlusObjectTypeBrush 0x100
84 : #define EmfPlusObjectTypePen 0x200
85 : #define EmfPlusObjectTypePath 0x300
86 : #define EmfPlusObjectTypeRegion 0x400
87 : #define EmfPlusObjectTypeImage 0x500
88 : #define EmfPlusObjectTypeFont 0x600
89 :
90 : #define EmfPlusRegionInitialStateInfinite 0x10000003
91 :
92 : using namespace ::com::sun::star;
93 : using namespace ::basegfx;
94 :
95 : namespace cppcanvas
96 : {
97 : namespace internal
98 : {
99 :
100 : #if OSL_DEBUG_LEVEL > 1
101 : void dumpWords (SvStream& s, int i)
102 : {
103 : sal_uInt32 pos = s.Tell ();
104 : sal_Int16 data;
105 : SAL_INFO ("cppcanvas.emf", "EMF+ dumping words");
106 : for (; i > 0; i --) {
107 : s >> data;
108 : SAL_INFO ("cppcanvas.emf", "EMF+\tdata: " << std::hex << data << std::dec);
109 : }
110 : SAL_INFO ("cppcanvas.emf", "EMF+ end dumping words");
111 : s.Seek (pos);
112 : }
113 : #endif
114 :
115 : struct EMFPPath : public EMFPObject
116 : {
117 : ::basegfx::B2DPolyPolygon aPolygon;
118 : sal_Int32 nPoints;
119 : float* pPoints;
120 : sal_uInt8* pPointTypes;
121 :
122 : public:
123 0 : EMFPPath (sal_Int32 _nPoints, bool bLines = false)
124 0 : {
125 0 : if( _nPoints<0 || sal_uInt32(_nPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
126 0 : _nPoints = SAL_MAX_INT32/(2*sizeof(float));
127 0 : nPoints = _nPoints;
128 0 : pPoints = new float [nPoints*2];
129 0 : if (!bLines)
130 0 : pPointTypes = new sal_uInt8 [_nPoints];
131 : else
132 0 : pPointTypes = NULL;
133 0 : }
134 :
135 0 : ~EMFPPath ()
136 0 : {
137 0 : delete [] pPoints;
138 0 : delete [] pPointTypes;
139 0 : }
140 :
141 : // TODO: remove rR argument when debug code is not longer needed
142 0 : void Read (SvStream& s, sal_uInt32 pathFlags, ImplRenderer& rR)
143 : {
144 0 : for (int i = 0; i < nPoints; i ++) {
145 0 : if (pathFlags & 0x4000) {
146 : // points are stored in short 16bit integer format
147 : sal_uInt16 x, y;
148 :
149 0 : s >> x >> y;
150 : SAL_INFO ("cppcanvas.emf", "EMF+\tpoint [x,y]: " << x << "," << y);
151 0 : pPoints [i*2] = x;
152 0 : pPoints [i*2 + 1] = y;
153 : } else {
154 : // points are stored in Single (float) format
155 0 : s >> pPoints [i*2] >> pPoints [i*2 + 1];
156 : SAL_INFO ("cppcanvas.emf", "EMF+\tpoint [x,y]: " << pPoints [i*2] << "," << pPoints [i*2 + 1]);
157 : }
158 : }
159 :
160 0 : if (pPointTypes)
161 0 : for (int i = 0; i < nPoints; i ++) {
162 0 : s >> pPointTypes [i];
163 : SAL_INFO ("cppcanvas.emf", "EMF+\tpoint type: " << (int)pPointTypes [i]);
164 : }
165 :
166 0 : aPolygon.clear ();
167 :
168 : #if OSL_DEBUG_LEVEL > 1
169 : const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (GetPolygon (rR)));
170 :
171 : SAL_INFO ("cppcanvas.emf",
172 : "EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << aBounds.getWidth () << "x" << aBounds.getHeight () << " (mapped)");
173 : #else
174 : (void) rR; // avoid warnings
175 : #endif
176 0 : }
177 :
178 0 : ::basegfx::B2DPolyPolygon& GetPolygon (ImplRenderer& rR, bool bMapIt = true)
179 : {
180 0 : ::basegfx::B2DPolygon polygon;
181 :
182 0 : aPolygon.clear ();
183 :
184 0 : int last_normal = 0, p = 0;
185 0 : ::basegfx::B2DPoint prev, mapped;
186 0 : bool hasPrev = false;
187 0 : for (int i = 0; i < nPoints; i ++) {
188 0 : if (p && pPointTypes && (pPointTypes [i] == 0)) {
189 0 : aPolygon.append (polygon);
190 0 : last_normal = i;
191 0 : p = 0;
192 0 : polygon.clear ();
193 : }
194 :
195 0 : if (bMapIt)
196 0 : mapped = rR.Map (pPoints [i*2], pPoints [i*2 + 1]);
197 : else
198 0 : mapped = ::basegfx::B2DPoint (pPoints [i*2], pPoints [i*2 + 1]);
199 0 : if (pPointTypes) {
200 0 : if ((pPointTypes [i] & 0x07) == 3) {
201 0 : if (((i - last_normal )% 3) == 1) {
202 0 : polygon.setNextControlPoint (p - 1, mapped);
203 : SAL_INFO ("cppcanvas.emf", "polygon append next: " << p - 1 << " mapped: " << mapped.getX () << "," << mapped.getY ());
204 0 : continue;
205 0 : } else if (((i - last_normal) % 3) == 2) {
206 0 : prev = mapped;
207 0 : hasPrev = true;
208 0 : continue;
209 : }
210 : } else
211 0 : last_normal = i;
212 : }
213 0 : polygon.append (mapped);
214 : SAL_INFO ("cppcanvas.emf", "polygon append point: " << pPoints [i*2] << "," << pPoints [i*2 + 1] << " mapped: " << mapped.getX () << ":" << mapped.getY ());
215 0 : if (hasPrev) {
216 0 : polygon.setPrevControlPoint (p, prev);
217 : SAL_INFO ("cppcanvas.emf", "polygon append prev: " << p << " mapped: " << prev.getX () << "," << prev.getY ());
218 0 : hasPrev = false;
219 : }
220 0 : p ++;
221 0 : if (pPointTypes && (pPointTypes [i] & 0x80)) { // closed polygon
222 0 : polygon.setClosed (true);
223 0 : aPolygon.append (polygon);
224 : SAL_INFO ("cppcanvas.emf", "close polygon");
225 0 : last_normal = i + 1;
226 0 : p = 0;
227 0 : polygon.clear ();
228 : }
229 : }
230 :
231 0 : if (polygon.count ()) {
232 0 : aPolygon.append (polygon);
233 :
234 : #if OSL_DEBUG_LEVEL > 1
235 : for (unsigned int i=0; i<aPolygon.count(); i++) {
236 : polygon = aPolygon.getB2DPolygon(i);
237 : SAL_INFO ("cppcanvas.emf", "polygon: " << i);
238 : for (unsigned int j=0; j<polygon.count(); j++) {
239 : ::basegfx::B2DPoint point = polygon.getB2DPoint(j);
240 : SAL_INFO ("cppcanvas.emf", "point: " << point.getX() << "," << point.getY());
241 : if (polygon.isPrevControlPointUsed(j)) {
242 : point = polygon.getPrevControlPoint(j);
243 : SAL_INFO ("cppcanvas.emf", "prev: " << point.getX() << "," << point.getY());
244 : }
245 : if (polygon.isNextControlPointUsed(j)) {
246 : point = polygon.getNextControlPoint(j);
247 : SAL_INFO ("cppcanvas.emf", "next: " << point.getX() << "," << point.getY());
248 : }
249 : }
250 : }
251 : #endif
252 : }
253 :
254 0 : return aPolygon;
255 : }
256 : };
257 :
258 : struct EMFPRegion : public EMFPObject
259 : {
260 : sal_Int32 parts;
261 : sal_Int32 *combineMode;
262 : sal_Int32 initialState;
263 : EMFPPath *initialPath;
264 : float ix, iy, iw, ih;
265 :
266 0 : EMFPRegion ()
267 0 : {
268 0 : combineMode = NULL;
269 0 : initialPath = NULL;
270 0 : }
271 :
272 0 : ~EMFPRegion ()
273 0 : {
274 0 : if (combineMode) {
275 0 : delete [] combineMode;
276 0 : combineMode = NULL;
277 : }
278 0 : if (initialPath) {
279 0 : delete initialPath;
280 0 : initialPath = NULL;
281 : }
282 0 : }
283 :
284 0 : void Read (SvStream& s)
285 : {
286 : sal_uInt32 header;
287 :
288 0 : s >> header >> parts;
289 :
290 : SAL_INFO ("cppcanvas.emf", "EMF+\tregion");
291 : SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " parts: " << parts << std::dec );
292 :
293 0 : if (parts) {
294 0 : if( parts<0 || sal_uInt32(parts)>SAL_MAX_INT32/sizeof(sal_Int32) )
295 0 : parts = SAL_MAX_INT32/sizeof(sal_Int32);
296 :
297 0 : combineMode = new sal_Int32 [parts];
298 :
299 0 : for (int i = 0; i < parts; i ++) {
300 0 : s >> combineMode [i];
301 : SAL_INFO ("cppcanvas.emf", "EMF+\tcombine mode [" << i << "]: 0x" << std::hex << combineMode [i] << std::dec);
302 : }
303 : }
304 :
305 0 : s >> initialState;
306 : SAL_INFO ("cppcanvas.emf", "EMF+\tinitial state: 0x" << std::hex << initialState << std::dec);
307 0 : }
308 : };
309 :
310 : struct EMFPBrush : public EMFPObject
311 : {
312 : ::Color solidColor;
313 : sal_uInt32 type;
314 : sal_uInt32 additionalFlags;
315 :
316 : /* linear gradient */
317 : sal_Int32 wrapMode;
318 : float areaX, areaY, areaWidth, areaHeight;
319 : ::Color secondColor; // first color is stored in solidColor;
320 : XForm transformation;
321 : bool hasTransformation;
322 : sal_Int32 blendPoints;
323 : float* blendPositions;
324 : float* blendFactors;
325 : sal_Int32 colorblendPoints;
326 : float* colorblendPositions;
327 : ::Color* colorblendColors;
328 : sal_Int32 surroundColorsNumber;
329 : ::Color* surroundColors;
330 : EMFPPath *path;
331 :
332 : public:
333 0 : EMFPBrush ()
334 0 : {
335 0 : blendPositions = NULL;
336 0 : colorblendPositions = NULL;
337 0 : colorblendColors = NULL;
338 0 : surroundColors = NULL;
339 0 : path = NULL;
340 0 : hasTransformation = false;
341 0 : }
342 :
343 0 : ~EMFPBrush ()
344 0 : {
345 0 : if (blendPositions != NULL) {
346 0 : delete[] blendPositions;
347 0 : blendPositions = NULL;
348 : }
349 0 : if (colorblendPositions != NULL) {
350 0 : delete[] colorblendPositions;
351 0 : colorblendPositions = NULL;
352 : }
353 0 : if (colorblendColors != NULL) {
354 0 : delete[] colorblendColors;
355 0 : colorblendColors = NULL;
356 : }
357 0 : if (surroundColors != NULL) {
358 0 : delete[] surroundColors;
359 0 : surroundColors = NULL;
360 : }
361 0 : if (path) {
362 0 : delete path;
363 0 : path = NULL;
364 : }
365 0 : }
366 :
367 : sal_uInt32 GetType() const { return type; }
368 0 : const ::Color& GetColor() const { return solidColor; }
369 :
370 0 : void Read (SvStream& s, ImplRenderer& rR)
371 : {
372 : sal_uInt32 header;
373 :
374 0 : s >> header >> type;
375 :
376 : SAL_INFO ("cppcanvas.emf", "EMF+\tbrush");
377 : SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec);
378 :
379 0 : switch (type) {
380 : case 0:
381 : {
382 : sal_uInt32 color;
383 :
384 0 : s >> color;
385 0 : solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
386 : SAL_INFO ("cppcanvas.emf", "EMF+\tsolid color: 0x" << std::hex << color << std::dec);
387 :
388 0 : break;
389 : }
390 : // path gradient
391 : case 3:
392 : {
393 0 : s >> additionalFlags >> wrapMode;
394 :
395 : SAL_INFO ("cppcanvas.emf", "EMF+\tpath gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec);
396 :
397 : sal_uInt32 color;
398 :
399 0 : s >> color;
400 0 : solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
401 : SAL_INFO("cppcanvas.emf", "EMF+\tcenter color: 0x" << std::hex << color << std::dec);
402 :
403 0 : s >> areaX >> areaY;
404 : SAL_INFO("cppcanvas.emf", "EMF+\tcenter point: " << areaX << "," << areaY);
405 :
406 0 : s >> surroundColorsNumber;
407 : SAL_INFO("cppcanvas.emf", "EMF+\tsurround colors: " << surroundColorsNumber);
408 :
409 0 : if( surroundColorsNumber<0 || sal_uInt32(surroundColorsNumber)>SAL_MAX_INT32/sizeof(::Color) )
410 0 : surroundColorsNumber = SAL_MAX_INT32/sizeof(::Color);
411 :
412 0 : surroundColors = new ::Color [surroundColorsNumber];
413 0 : for (int i = 0; i < surroundColorsNumber; i++) {
414 0 : s >> color;
415 0 : surroundColors[i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
416 0 : if (i == 0)
417 0 : secondColor = surroundColors [0];
418 : SAL_INFO("cppcanvas.emf", "EMF+\tsurround color[" << i << "]: 0x" << std::hex << color << std::dec);
419 : }
420 :
421 0 : if (additionalFlags & 0x01) {
422 : sal_Int32 pathLength;
423 :
424 0 : s >> pathLength;
425 : SAL_INFO("cppcanvas.emf", "EMF+\tpath length: " << pathLength);
426 :
427 0 : sal_uInt32 pos = s.Tell ();
428 : #if OSL_DEBUG_LEVEL > 1
429 : dumpWords (s, 32);
430 : #endif
431 :
432 : sal_uInt32 pathHeader;
433 : sal_Int32 pathPoints, pathFlags;
434 0 : s >> pathHeader >> pathPoints >> pathFlags;
435 :
436 : SAL_INFO("cppcanvas.emf", "EMF+\tpath (brush path gradient)");
437 : SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec );
438 :
439 0 : path = new EMFPPath (pathPoints);
440 0 : path->Read (s, pathFlags, rR);
441 :
442 0 : s.Seek (pos + pathLength);
443 :
444 0 : const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (path->GetPolygon (rR, false)));
445 0 : areaWidth = aBounds.getWidth ();
446 0 : areaHeight = aBounds.getHeight ();
447 :
448 : SAL_INFO("cppcanvas.emf", "EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << " " << aBounds.getWidth () << "x" << aBounds.getHeight ());
449 :
450 :
451 0 : if (additionalFlags & 0x02) {
452 : SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
453 0 : s >> transformation;
454 0 : hasTransformation = true;
455 : SAL_INFO("cppcanvas.emf",
456 : "EMF+\tm11: " << transformation.eM11 << " m12: " << transformation.eM12 <<
457 : "\nEMF+\tm21: " << transformation.eM21 << " m22: " << transformation.eM22 <<
458 : "\nEMF+\tdx: " << transformation.eDx << " dy: " << transformation.eDy);
459 :
460 : }
461 0 : if (additionalFlags & 0x08) {
462 0 : s >> blendPoints;
463 : SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
464 0 : if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
465 0 : blendPoints = SAL_MAX_INT32/(2*sizeof(float));
466 0 : blendPositions = new float [2*blendPoints];
467 0 : blendFactors = blendPositions + blendPoints;
468 0 : for (int i=0; i < blendPoints; i ++) {
469 0 : s >> blendPositions [i];
470 : SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions [i]);
471 : }
472 0 : for (int i=0; i < blendPoints; i ++) {
473 0 : s >> blendFactors [i];
474 : SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors [i]);
475 : }
476 : }
477 :
478 0 : if (additionalFlags & 0x04) {
479 0 : s >> colorblendPoints;
480 : SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
481 0 : if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
482 0 : colorblendPoints = SAL_MAX_INT32/sizeof(float);
483 0 : if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
484 0 : colorblendPoints = SAL_MAX_INT32/sizeof(::Color);
485 0 : colorblendPositions = new float [colorblendPoints];
486 0 : colorblendColors = new ::Color [colorblendPoints];
487 0 : for (int i=0; i < colorblendPoints; i ++) {
488 0 : s >> colorblendPositions [i];
489 : SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions [i]);
490 : }
491 0 : for (int i=0; i < colorblendPoints; i ++) {
492 0 : s >> color;
493 0 : colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
494 : SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
495 : }
496 : }
497 : } else {
498 : #if OSL_DEBUG_LEVEL > 1
499 : dumpWords (s, 1024);
500 : #endif
501 : }
502 0 : break;
503 : }
504 : // linear gradient
505 : case 4:
506 : {
507 0 : s >> additionalFlags >> wrapMode;
508 :
509 : SAL_INFO("cppcanvas.emf", "EMF+\tlinear gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec);
510 :
511 0 : s >> areaX >> areaY >> areaWidth >> areaHeight;
512 :
513 : SAL_INFO("cppcanvas.emf", "EMF+\tarea: " << areaX << "," << areaY << " - " << areaWidth << "x" << areaHeight);
514 :
515 : sal_uInt32 color;
516 :
517 0 : s >> color;
518 0 : solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
519 : SAL_INFO("cppcanvas.emf", "EMF+\tfirst color: 0x" << std::hex << color << std::dec);
520 :
521 0 : s >> color;
522 0 : secondColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
523 : SAL_INFO("cppcanvas.emf", "EMF+\tsecond color: 0x" << std::hex << color << std::dec);
524 :
525 : // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
526 0 : s >> color;
527 0 : s >> color;
528 :
529 0 : if (additionalFlags & 0x02) {
530 : SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
531 0 : s >> transformation;
532 0 : hasTransformation = true;
533 : SAL_INFO("cppcanvas.emf",
534 : "EMF+\tm11: " << transformation.eM11 << " m12: " << transformation.eM12 <<
535 : "\nEMF+\tm21: " << transformation.eM21 << " m22: " << transformation.eM22 <<
536 : "\nEMF+\tdx: " << transformation.eDx << " dy: " << transformation.eDy);
537 : }
538 0 : if (additionalFlags & 0x08) {
539 0 : s >> blendPoints;
540 : SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
541 0 : if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
542 0 : blendPoints = SAL_MAX_INT32/(2*sizeof(float));
543 0 : blendPositions = new float [2*blendPoints];
544 0 : blendFactors = blendPositions + blendPoints;
545 0 : for (int i=0; i < blendPoints; i ++) {
546 0 : s >> blendPositions [i];
547 : SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions [i]);
548 : }
549 0 : for (int i=0; i < blendPoints; i ++) {
550 0 : s >> blendFactors [i];
551 : SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors [i]);
552 : }
553 : }
554 :
555 0 : if (additionalFlags & 0x04) {
556 0 : s >> colorblendPoints;
557 : SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
558 0 : if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
559 0 : colorblendPoints = SAL_MAX_INT32/sizeof(float);
560 0 : if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
561 0 : colorblendPoints = sal_uInt32(SAL_MAX_INT32)/sizeof(::Color);
562 0 : colorblendPositions = new float [colorblendPoints];
563 0 : colorblendColors = new ::Color [colorblendPoints];
564 0 : for (int i=0; i < colorblendPoints; i ++) {
565 0 : s >> colorblendPositions [i];
566 : SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions [i]);
567 : }
568 0 : for (int i=0; i < colorblendPoints; i ++) {
569 0 : s >> color;
570 0 : colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
571 : SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
572 : }
573 : }
574 :
575 0 : break;
576 : }
577 : default:
578 : SAL_INFO("cppcanvas.emf", "EMF+\tunhandled brush type: " << std::hex << type << std::dec);
579 : }
580 0 : }
581 : };
582 :
583 0 : struct EMFPPen : public EMFPBrush
584 : {
585 : XForm transformation;
586 : float width;
587 : sal_Int32 startCap;
588 : sal_Int32 endCap;
589 : sal_Int32 lineJoin;
590 : float mitterLimit;
591 : sal_Int32 dashStyle;
592 : sal_Int32 dashCap;
593 : float dashOffset;
594 : sal_Int32 dashPatternLen;
595 : float *dashPattern;
596 : sal_Int32 alignment;
597 : sal_Int32 compoundArrayLen;
598 : float *compoundArray;
599 : sal_Int32 customStartCapLen;
600 : sal_uInt8 *customStartCap;
601 : sal_Int32 customEndCapLen;
602 : sal_uInt8 *customEndCap;
603 :
604 : public:
605 0 : EMFPPen () : EMFPBrush ()
606 : {
607 0 : }
608 :
609 0 : void SetStrokeAttributes (rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
610 : {
611 : #if OSL_DEBUG_LEVEL > 1
612 : if (width == 0.0) {
613 : SAL_INFO ("cppcanvas.emf", "TODO: pen with zero width - using minimal which might not be correct\n");
614 : }
615 : #endif
616 0 : rStrokeAttributes.StrokeWidth = (rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getX ();
617 0 : }
618 :
619 0 : void Read (SvStream& s, ImplRenderer& rR, sal_Int32, sal_Int32 )
620 : {
621 : sal_uInt32 header, unknown, penFlags, unknown2;
622 : int i;
623 :
624 0 : s >> header >> unknown >> penFlags >> unknown2 >> width;
625 :
626 : SAL_INFO("cppcanvas.emf", "EMF+\tpen");
627 : SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " unknown: 0x" << unknown <<
628 : " additional flags: 0x" << penFlags << " unknown: 0x" << unknown2 << " width: " << std::dec << width );
629 :
630 0 : if (penFlags & 1)
631 0 : s >> transformation;
632 :
633 0 : if (penFlags & 2)
634 0 : s >> startCap;
635 : else
636 0 : startCap = 0;
637 :
638 0 : if (penFlags & 4)
639 0 : s >> endCap;
640 : else
641 0 : endCap = 0;
642 :
643 0 : if (penFlags & 8)
644 0 : s >> lineJoin;
645 : else
646 0 : lineJoin = 0;
647 :
648 0 : if (penFlags & 16)
649 0 : s >> mitterLimit;
650 : else
651 0 : mitterLimit = 0;
652 :
653 0 : if (penFlags & 32)
654 0 : s >> dashStyle;
655 : else
656 0 : dashStyle = 0;
657 :
658 0 : if (penFlags & 64)
659 0 : s >> dashCap;
660 : else
661 0 : dashCap = 0;
662 :
663 0 : if (penFlags & 128)
664 0 : s >> dashOffset;
665 : else
666 0 : dashOffset = 0;
667 :
668 0 : if (penFlags & 256) {
669 0 : s >> dashPatternLen;
670 0 : if( dashPatternLen<0 || sal_uInt32(dashPatternLen)>SAL_MAX_INT32/sizeof(float) )
671 0 : dashPatternLen = SAL_MAX_INT32/sizeof(float);
672 0 : dashPattern = new float [dashPatternLen];
673 0 : for (i = 0; i < dashPatternLen; i++)
674 0 : s >> dashPattern [i];
675 : } else
676 0 : dashPatternLen = 0;
677 :
678 0 : if (penFlags & 512)
679 0 : s >> alignment;
680 : else
681 0 : alignment = 0;
682 :
683 0 : if (penFlags & 1024) {
684 0 : s >> compoundArrayLen;
685 0 : if( compoundArrayLen<0 || sal_uInt32(compoundArrayLen)>SAL_MAX_INT32/sizeof(float) )
686 0 : compoundArrayLen = SAL_MAX_INT32/sizeof(float);
687 0 : compoundArray = new float [compoundArrayLen];
688 0 : for (i = 0; i < compoundArrayLen; i++)
689 0 : s >> compoundArray [i];
690 : } else
691 0 : compoundArrayLen = 0;
692 :
693 0 : if (penFlags & 2048) {
694 0 : s >> customStartCapLen;
695 0 : if( customStartCapLen<0 )
696 0 : customStartCapLen=0;
697 0 : customStartCap = new sal_uInt8 [customStartCapLen];
698 0 : for (i = 0; i < customStartCapLen; i++)
699 0 : s >> customStartCap [i];
700 : } else
701 0 : customStartCapLen = 0;
702 :
703 0 : if (penFlags & 4096) {
704 0 : s >> customEndCapLen;
705 0 : if( customEndCapLen<0 )
706 0 : customEndCapLen=0;
707 0 : customEndCap = new sal_uInt8 [customEndCapLen];
708 0 : for (i = 0; i < customEndCapLen; i++)
709 0 : s >> customEndCap [i];
710 : } else
711 0 : customEndCapLen = 0;
712 :
713 0 : EMFPBrush::Read (s, rR);
714 0 : }
715 : };
716 :
717 0 : struct EMFPImage : public EMFPObject
718 : {
719 : sal_uInt32 type;
720 : sal_Int32 width;
721 : sal_Int32 height;
722 : sal_Int32 stride;
723 : sal_Int32 pixelFormat;
724 : Graphic graphic;
725 :
726 :
727 0 : void Read (SvMemoryStream &s, sal_uInt32 dataSize, sal_Bool bUseWholeStream)
728 : {
729 : sal_uInt32 header, unknown;
730 :
731 0 : s >> header >> type;
732 :
733 : SAL_INFO("cppcanvas.emf", "EMF+\timage\nEMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec );
734 :
735 0 : if (type == 1) { // bitmap
736 0 : s >> width >> height >> stride >> pixelFormat >> unknown;
737 : SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << width << " height: " << height << " stride: " << "pixelFormat: 0x" << std::hex << pixelFormat << std::dec);
738 0 : if (width == 0) { // non native formats
739 0 : GraphicFilter filter;
740 :
741 0 : filter.ImportGraphic (graphic, String (), s);
742 0 : SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << graphic.GetBitmap().GetSizePixel().Width() << " height: " << graphic.GetBitmap().GetSizePixel().Height());
743 : }
744 :
745 0 : } else if (type == 2) {
746 : sal_Int32 mfType, mfSize;
747 :
748 0 : s >> mfType >> mfSize;
749 : SAL_INFO("cppcanvas.emf", "EMF+\tmetafile type: " << mfType << " dataSize: " << mfSize << " real size calculated from record dataSize: " << dataSize - 16);
750 :
751 0 : GraphicFilter filter;
752 : // workaround buggy metafiles, which have wrong mfSize set (n#705956 for example)
753 0 : SvMemoryStream mfStream (((char *)s.GetData()) + s.Tell(), bUseWholeStream ? s.remainingSize() : dataSize - 16, STREAM_READ);
754 :
755 0 : filter.ImportGraphic (graphic, String (), mfStream);
756 :
757 : // debug code - write the stream to debug file /tmp/emf-stream.emf
758 : #if OSL_DEBUG_LEVEL > 1
759 : mfStream.Seek(0);
760 : static sal_Int32 emfp_debug_stream_number = 0;
761 : OUString emfp_debug_filename("/tmp/emf-embedded-stream");
762 : emfp_debug_filename += OUString::valueOf(emfp_debug_stream_number++);
763 : emfp_debug_filename += OUString(".emf");
764 :
765 : SvFileStream file( emfp_debug_filename, STREAM_WRITE | STREAM_TRUNC );
766 :
767 : mfStream >> file;
768 : file.Flush();
769 : file.Close();
770 : #endif
771 : }
772 0 : }
773 : };
774 :
775 0 : struct EMFPFont : public EMFPObject
776 : {
777 : sal_uInt32 version;
778 : float emSize;
779 : sal_uInt32 sizeUnit;
780 : sal_Int32 fontFlags;
781 : OUString family;
782 :
783 0 : void Read (SvMemoryStream &s)
784 : {
785 : sal_uInt32 header;
786 : sal_uInt32 reserved;
787 : sal_uInt32 length;
788 :
789 0 : s >> header >> emSize >> sizeUnit >> fontFlags >> reserved >> length;
790 :
791 : OSL_ASSERT( ( header >> 12 ) == 0xdbc01 );
792 :
793 : SAL_INFO("cppcanvas.emf", "EMF+\tfont\n"
794 : << "EMF+\theader: 0x" << std::hex << (header >> 12) << " version: 0x" << (header & 0x1fff) << " size: " << std::dec << emSize << " unit: 0x" << std::hex << sizeUnit << std::dec);
795 : SAL_INFO("cppcanvas.emf", "EMF+\tflags: 0x" << std::hex << fontFlags << " reserved: 0x" << reserved << " length: 0x" << std::hex << length << std::dec);
796 :
797 0 : if( length > 0 && length < 0x4000 ) {
798 0 : sal_Unicode *chars = (sal_Unicode *) alloca( sizeof( sal_Unicode ) * length );
799 :
800 0 : for( sal_uInt32 i = 0; i < length; i++ )
801 0 : s >> chars[ i ];
802 :
803 0 : family = OUString( chars, length );
804 : SAL_INFO("cppcanvas.emf", "EMF+\tfamily: " << OUStringToOString( family, RTL_TEXTENCODING_UTF8).getStr()); // TODO: can we just use family?
805 : }
806 0 : }
807 : };
808 :
809 0 : void ImplRenderer::ReadRectangle (SvStream& s, float& x, float& y, float &width, float& height, bool bCompressed)
810 : {
811 0 : if (bCompressed) {
812 : sal_Int16 ix, iy, iw, ih;
813 :
814 0 : s >> ix >> iy >> iw >> ih;
815 :
816 0 : x = ix;
817 0 : y = iy;
818 0 : width = iw;
819 0 : height = ih;
820 : } else
821 0 : s >> x >> y >> width >> height;
822 0 : }
823 :
824 0 : void ImplRenderer::ReadPoint (SvStream& s, float& x, float& y, sal_uInt32 flags)
825 : {
826 0 : if (flags & 0x4000) {
827 : sal_Int16 ix, iy;
828 :
829 0 : s >> ix >> iy;
830 :
831 0 : x = ix;
832 0 : y = iy;
833 : } else
834 0 : s >> x >> y;
835 0 : }
836 :
837 0 : void ImplRenderer::MapToDevice (double& x, double& y)
838 : {
839 : // TODO: other units
840 0 : x = 100*nMmX*x/nPixX;
841 0 : y = 100*nMmY*y/nPixY;
842 0 : }
843 :
844 0 : ::basegfx::B2DPoint ImplRenderer::Map (double ix, double iy)
845 : {
846 : double x, y;
847 :
848 0 : x = ix*aWorldTransform.eM11 + iy*aWorldTransform.eM21 + aWorldTransform.eDx;
849 0 : y = ix*aWorldTransform.eM12 + iy*aWorldTransform.eM22 + aWorldTransform.eDy;
850 :
851 0 : MapToDevice (x, y);
852 :
853 0 : x -= nFrameLeft;
854 0 : y -= nFrameTop;
855 :
856 0 : return ::basegfx::B2DPoint (x, y);
857 : }
858 :
859 0 : ::basegfx::B2DSize ImplRenderer::MapSize (double iwidth, double iheight)
860 : {
861 : double w, h;
862 :
863 0 : w = iwidth*aWorldTransform.eM11 + iheight*aWorldTransform.eM21;
864 0 : h = iwidth*aWorldTransform.eM12 + iheight*aWorldTransform.eM22;
865 :
866 0 : MapToDevice (w, h);
867 :
868 0 : return ::basegfx::B2DSize (w, h);
869 : }
870 :
871 : #define COLOR(x) \
872 : ::vcl::unotools::colorToDoubleSequence( ::Color (0xff - (x >> 24), \
873 : (x >> 16) & 0xff, \
874 : (x >> 8) & 0xff, \
875 : x & 0xff), \
876 : rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
877 :
878 0 : void ImplRenderer::EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
879 : OutDevState& rState, const CanvasSharedPtr& rCanvas, bool isColor, sal_uInt32 brushIndexOrColor)
880 : {
881 0 : ::basegfx::B2DPolyPolygon localPolygon (polygon);
882 :
883 : SAL_INFO("cppcanvas.emf", "EMF+\tfill polygon");
884 :
885 0 : localPolygon.transform( rState.mapModeTransform );
886 :
887 0 : ActionSharedPtr pPolyAction;
888 :
889 0 : if (isColor) {
890 : SAL_INFO("cppcanvas.emf", "EMF+\t\tcolor fill:0x" << std::hex << brushIndexOrColor << std::dec);
891 0 : rState.isFillColorSet = true;
892 0 : rState.isLineColorSet = false;
893 :
894 0 : rState.fillColor = COLOR(brushIndexOrColor);
895 :
896 0 : pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) );
897 :
898 : } else {
899 0 : rState.isFillColorSet = true;
900 : // extract UseBrush
901 0 : EMFPBrush* brush = (EMFPBrush*) aObjects [brushIndexOrColor & 0xff];
902 : SAL_INFO("cppcanvas.emf", "EMF+\tbrush fill slot: " << brushIndexOrColor << " (type: " << brush->GetType () << ")");
903 :
904 : // give up in case something wrong happened
905 0 : if( !brush )
906 0 : return;
907 :
908 0 : rState.isFillColorSet = false;
909 0 : rState.isLineColorSet = false;
910 :
911 0 : if (brush->type == 3 || brush->type == 4) {
912 :
913 0 : if (brush->type == 3 && !(brush->additionalFlags & 0x1))
914 0 : return; // we are unable to parse these brushes yet
915 :
916 0 : ::basegfx::B2DHomMatrix aTextureTransformation;
917 0 : ::basegfx::B2DHomMatrix aWorldTransformation;
918 0 : rendering::Texture aTexture;
919 :
920 0 : aWorldTransformation.set (0, 0, aWorldTransform.eM11);
921 0 : aWorldTransformation.set (0, 1, aWorldTransform.eM21);
922 0 : aWorldTransformation.set (0, 2, aWorldTransform.eDx);
923 0 : aWorldTransformation.set (1, 0, aWorldTransform.eM12);
924 0 : aWorldTransformation.set (1, 1, aWorldTransform.eM22);
925 0 : aWorldTransformation.set (1, 2, aWorldTransform.eDy);
926 :
927 0 : if (brush->type == 4) {
928 0 : aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
929 0 : aTextureTransformation.translate (brush->areaX, brush->areaY);
930 : } else {
931 0 : aTextureTransformation.translate (-0.5, -0.5);
932 0 : aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
933 0 : aTextureTransformation.translate (brush->areaX,brush->areaY);
934 : }
935 :
936 0 : if (brush->hasTransformation) {
937 0 : ::basegfx::B2DHomMatrix aTransformation;
938 :
939 0 : aTransformation.set (0, 0, brush->transformation.eM11);
940 0 : aTransformation.set (0, 1, brush->transformation.eM21);
941 0 : aTransformation.set (0, 2, brush->transformation.eDx);
942 0 : aTransformation.set (1, 0, brush->transformation.eM12);
943 0 : aTransformation.set (1, 1, brush->transformation.eM22);
944 0 : aTransformation.set (1, 2, brush->transformation.eDy);
945 :
946 0 : aTextureTransformation *= aTransformation;
947 : }
948 :
949 0 : aTextureTransformation *= aWorldTransformation;
950 0 : aTextureTransformation.scale (100.0*nMmX/nPixX, 100.0*nMmY/nPixY);
951 0 : aTextureTransformation.translate (-nFrameLeft, -nFrameTop);
952 0 : aTextureTransformation *= rState.mapModeTransform;
953 :
954 0 : aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
955 0 : aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
956 0 : aTexture.Alpha = 1.0;
957 :
958 0 : basegfx::ODFGradientInfo aGradInfo;
959 0 : OUString aGradientService;
960 :
961 : const uno::Sequence< double > aStartColor(
962 : ::vcl::unotools::colorToDoubleSequence( brush->solidColor,
963 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
964 : const uno::Sequence< double > aEndColor(
965 : ::vcl::unotools::colorToDoubleSequence( brush->secondColor,
966 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
967 0 : uno::Sequence< uno::Sequence < double > > aColors (2);
968 0 : uno::Sequence< double > aStops (2);
969 :
970 0 : if (brush->blendPositions) {
971 : SAL_INFO("cppcanvas.emf", "EMF+\t\tuse blend");
972 0 : aColors.realloc (brush->blendPoints);
973 0 : aStops.realloc (brush->blendPoints);
974 0 : int length = aStartColor.getLength ();
975 0 : uno::Sequence< double > aColor (length);
976 :
977 : OSL_ASSERT (length == aEndColor.getLength());
978 :
979 0 : for (int i = 0; i < brush->blendPoints; i++) {
980 0 : aStops[i] = brush->blendPositions [i];
981 :
982 0 : for (int j = 0; j < length; j++) {
983 0 : if (brush->type == 4) {
984 0 : aColor [j] = aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i];
985 : } else
986 0 : aColor [j] = aStartColor [j]*brush->blendFactors[i] + aEndColor [j]*(1 - brush->blendFactors[i]);
987 : }
988 :
989 0 : aColors[i] = aColor;
990 0 : }
991 0 : } else if (brush->colorblendPositions) {
992 : SAL_INFO("cppcanvas.emf", "EMF+\t\tuse color blend");
993 0 : aColors.realloc (brush->colorblendPoints);
994 0 : aStops.realloc (brush->colorblendPoints);
995 :
996 0 : for (int i = 0; i < brush->colorblendPoints; i++) {
997 0 : aStops[i] = brush->colorblendPositions [i];
998 0 : aColors[(brush->type == 4) ? i : brush->colorblendPoints - 1 - i] = ::vcl::unotools::colorToDoubleSequence( brush->colorblendColors [i],
999 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
1000 : }
1001 : } else {
1002 0 : aStops[0] = 0.0;
1003 0 : aStops[1] = 1.0;
1004 :
1005 0 : if (brush->type == 4) {
1006 0 : aColors[0] = aStartColor;
1007 0 : aColors[1] = aEndColor;
1008 : } else {
1009 0 : aColors[1] = aStartColor;
1010 0 : aColors[0] = aEndColor;
1011 : }
1012 : }
1013 :
1014 : SAL_INFO("cppcanvas.emf", "EMF+\t\tset gradient");
1015 0 : basegfx::B2DRange aBoundsRectangle (0, 0, 1, 1);
1016 0 : if (brush->type == 4) {
1017 0 : aGradientService = "LinearGradient";
1018 0 : aGradInfo = basegfx::tools::createLinearODFGradientInfo(
1019 : aBoundsRectangle,
1020 0 : aStops.getLength(),
1021 : 0,
1022 0 : 0);
1023 :
1024 : } else {
1025 0 : aGradientService = "EllipticalGradient";
1026 0 : aGradInfo = basegfx::tools::createEllipticalODFGradientInfo(
1027 : aBoundsRectangle,
1028 : ::basegfx::B2DVector( 0, 0 ),
1029 0 : aStops.getLength(),
1030 : 0,
1031 0 : 0);
1032 : }
1033 :
1034 : uno::Reference< lang::XMultiServiceFactory > xFactory(
1035 0 : rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
1036 :
1037 0 : if( xFactory.is() ) {
1038 0 : uno::Sequence<uno::Any> args( 3 );
1039 0 : beans::PropertyValue aProp;
1040 0 : aProp.Name = "Colors";
1041 0 : aProp.Value <<= aColors;
1042 0 : args[0] <<= aProp;
1043 0 : aProp.Name = "Stops";
1044 0 : aProp.Value <<= aStops;
1045 0 : args[1] <<= aProp;
1046 0 : aProp.Name = "AspectRatio";
1047 0 : aProp.Value <<= static_cast<sal_Int32>(1);
1048 0 : args[2] <<= aProp;
1049 :
1050 : aTexture.Gradient.set(
1051 0 : xFactory->createInstanceWithArguments( aGradientService,
1052 0 : args ),
1053 0 : uno::UNO_QUERY);
1054 : }
1055 :
1056 : ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
1057 0 : aTextureTransformation );
1058 :
1059 0 : if( aTexture.Gradient.is() )
1060 0 : pPolyAction =
1061 : ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon,
1062 : rParms.mrCanvas,
1063 : rState,
1064 0 : aTexture ) );
1065 : }
1066 : }
1067 :
1068 0 : if( pPolyAction )
1069 : {
1070 : SAL_INFO("cppcanvas.emf", "EMF+\t\tadd poly action");
1071 :
1072 : maActions.push_back(
1073 : MtfAction(
1074 : pPolyAction,
1075 0 : rParms.mrCurrActionIndex ) );
1076 :
1077 0 : rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1078 0 : }
1079 : }
1080 :
1081 0 : void ImplRenderer::EMFPPlusDrawPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
1082 : OutDevState& rState, const CanvasSharedPtr& rCanvas, sal_uInt32 penIndex)
1083 : {
1084 0 : EMFPPen* pen = (EMFPPen*) aObjects [penIndex & 0xff];
1085 :
1086 : SAL_WARN_IF( !pen, "cppcanvas.emf", "emf+ missing pen" );
1087 :
1088 0 : if (pen)
1089 : {
1090 0 : rState.isFillColorSet = false;
1091 0 : rState.isLineColorSet = true;
1092 0 : rState.lineColor = ::vcl::unotools::colorToDoubleSequence (pen->GetColor (),
1093 0 : rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace());
1094 :
1095 0 : polygon.transform( rState.mapModeTransform );
1096 0 : rendering::StrokeAttributes aStrokeAttributes;
1097 :
1098 0 : pen->SetStrokeAttributes (aStrokeAttributes, *this, rState);
1099 :
1100 : ActionSharedPtr pPolyAction(
1101 : internal::PolyPolyActionFactory::createPolyPolyAction(
1102 0 : polygon, rParms.mrCanvas, rState, aStrokeAttributes ) );
1103 :
1104 0 : if( pPolyAction )
1105 : {
1106 : maActions.push_back(
1107 : MtfAction(
1108 : pPolyAction,
1109 0 : rParms.mrCurrActionIndex ) );
1110 :
1111 0 : rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
1112 0 : }
1113 : }
1114 0 : }
1115 :
1116 0 : void ImplRenderer::processObjectRecord(SvMemoryStream& rObjectStream, sal_uInt16 flags, sal_uInt32 dataSize, sal_Bool bUseWholeStream)
1117 : {
1118 : sal_uInt32 index;
1119 :
1120 : SAL_INFO("cppcanvas.emf", "EMF+ Object slot: " << (flags & 0xff) << " flags: " << (flags & 0xff00));
1121 :
1122 0 : index = flags & 0xff;
1123 0 : if (aObjects [index] != NULL) {
1124 0 : delete aObjects [index];
1125 0 : aObjects [index] = NULL;
1126 : }
1127 :
1128 0 : switch (flags & 0x7f00) {
1129 : case EmfPlusObjectTypeBrush:
1130 : {
1131 : EMFPBrush *brush;
1132 0 : aObjects [index] = brush = new EMFPBrush ();
1133 0 : brush->Read (rObjectStream, *this);
1134 :
1135 0 : break;
1136 : }
1137 : case EmfPlusObjectTypePen:
1138 : {
1139 : EMFPPen *pen;
1140 0 : aObjects [index] = pen = new EMFPPen ();
1141 0 : pen->Read (rObjectStream, *this, nHDPI, nVDPI);
1142 :
1143 0 : break;
1144 : }
1145 : case EmfPlusObjectTypePath:
1146 : sal_uInt32 header, pathFlags;
1147 : sal_Int32 points;
1148 :
1149 0 : rObjectStream >> header >> points >> pathFlags;
1150 :
1151 : SAL_INFO("cppcanvas.emf", "EMF+\tpath");
1152 : SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " points: " << std::dec << points << " additional flags: 0x" << std::hex << pathFlags << std::dec);
1153 :
1154 : EMFPPath *path;
1155 0 : aObjects [index] = path = new EMFPPath (points);
1156 0 : path->Read (rObjectStream, pathFlags, *this);
1157 :
1158 0 : break;
1159 : case EmfPlusObjectTypeRegion: {
1160 : EMFPRegion *region;
1161 :
1162 0 : aObjects [index] = region = new EMFPRegion ();
1163 0 : region->Read (rObjectStream);
1164 :
1165 0 : break;
1166 : }
1167 : case EmfPlusObjectTypeImage:
1168 : {
1169 : EMFPImage *image;
1170 0 : aObjects [index] = image = new EMFPImage ();
1171 0 : image->Read (rObjectStream, dataSize, bUseWholeStream);
1172 :
1173 0 : break;
1174 : }
1175 : case EmfPlusObjectTypeFont:
1176 : {
1177 : EMFPFont *font;
1178 0 : aObjects [index] = font = new EMFPFont ();
1179 0 : font->Read (rObjectStream);
1180 :
1181 0 : break;
1182 : }
1183 : default:
1184 : SAL_INFO("cppcanvas.emf", "EMF+\tObject unhandled flags: 0x" << std::hex << (flags & 0xff00) << std::dec);
1185 0 : break;
1186 : }
1187 0 : }
1188 :
1189 0 : double ImplRenderer::setFont (sal_uInt8 objectId, const ActionFactoryParameters& rParms, OutDevState& rState)
1190 : {
1191 0 : EMFPFont *font = (EMFPFont*) aObjects[ objectId ];
1192 :
1193 0 : rendering::FontRequest aFontRequest;
1194 0 : aFontRequest.FontDescription.FamilyName = font->family;
1195 0 : double cellSize = font->emSize;
1196 0 : aFontRequest.CellSize = (rState.mapModeTransform*MapSize( cellSize, 0 )).getX();
1197 0 : rState.xFont = rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest,
1198 : uno::Sequence< beans::PropertyValue >(),
1199 0 : geometry::Matrix2D() );
1200 :
1201 0 : return cellSize;
1202 : }
1203 :
1204 0 : void ImplRenderer::GraphicStatePush(GraphicStateMap& map, sal_Int32 index, OutDevState& rState)
1205 : {
1206 0 : GraphicStateMap::iterator iter = map.find( index );
1207 :
1208 0 : if ( iter != map.end() )
1209 : {
1210 0 : EmfPlusGraphicState state = iter->second;
1211 0 : map.erase( iter );
1212 :
1213 0 : SAL_INFO("cppcanvas.emf", "stack index: " << index << " found and erased");
1214 : }
1215 :
1216 0 : EmfPlusGraphicState state;
1217 :
1218 0 : state.aWorldTransform = aWorldTransform;
1219 0 : state.aDevState = rState;
1220 :
1221 0 : map[ index ] = state;
1222 0 : }
1223 :
1224 0 : void ImplRenderer::GraphicStatePop(GraphicStateMap& map, sal_Int32 index, OutDevState& rState)
1225 : {
1226 0 : GraphicStateMap::iterator iter = map.find( index );
1227 :
1228 0 : if ( iter != map.end() )
1229 : {
1230 : SAL_INFO("cppcanvas.emf", "stack index: " << index << " found");
1231 :
1232 0 : EmfPlusGraphicState state = iter->second;
1233 :
1234 0 : aWorldTransform = state.aWorldTransform;
1235 0 : rState.clip = state.aDevState.clip;
1236 0 : rState.clipRect = state.aDevState.clipRect;
1237 0 : rState.xClipPoly = state.aDevState.xClipPoly;
1238 : }
1239 0 : }
1240 :
1241 0 : void ImplRenderer::processEMFPlus( MetaCommentAction* pAct, const ActionFactoryParameters& rFactoryParms,
1242 : OutDevState& rState, const CanvasSharedPtr& rCanvas )
1243 : {
1244 0 : sal_uInt32 length = pAct->GetDataSize ();
1245 0 : SvMemoryStream rMF ((void*) pAct->GetData (), length, STREAM_READ);
1246 :
1247 : #if OSL_DEBUG_LEVEL > 2
1248 : SAL_INFO("cppcanvas.emf", "EMF+\tDump of EMF+ record");
1249 : dumpWords(rMF, length);
1250 : #endif
1251 0 : length -= 4;
1252 :
1253 0 : while (length > 0) {
1254 : sal_uInt16 type, flags;
1255 : sal_uInt32 size, dataSize;
1256 : sal_uInt32 next;
1257 :
1258 0 : rMF >> type >> flags >> size >> dataSize;
1259 :
1260 0 : next = rMF.Tell() + ( size - 12 );
1261 :
1262 0 : if (size < 12) {
1263 : SAL_INFO("cppcanvas.emf", "Size field is less than 12 bytes");
1264 : }
1265 :
1266 : SAL_INFO("cppcanvas.emf", "EMF+ record size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
1267 :
1268 0 : if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000))) {
1269 0 : if (!mbMultipart) {
1270 0 : mbMultipart = true;
1271 0 : mMFlags = flags;
1272 0 : mMStream.Seek(0);
1273 : }
1274 :
1275 : // 1st 4 bytes are unknown
1276 0 : mMStream.Write (((const char *)rMF.GetData()) + rMF.Tell() + 4, dataSize - 4);
1277 0 : SAL_INFO("cppcanvas.emf", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
1278 : } else {
1279 0 : if (mbMultipart) {
1280 : SAL_INFO("cppcanvas.emf", "EMF+ multipart record flags: " << mMFlags);
1281 0 : mMStream.Seek (0);
1282 0 : processObjectRecord (mMStream, mMFlags, dataSize, sal_True);
1283 : }
1284 0 : mbMultipart = false;
1285 : }
1286 :
1287 0 : if (type != EmfPlusRecordTypeObject || !(flags & 0x8000))
1288 : {
1289 0 : switch (type) {
1290 : case EmfPlusRecordTypeHeader:
1291 : sal_uInt32 header, version;
1292 :
1293 0 : rMF >> header >> version >> nHDPI >> nVDPI;
1294 :
1295 : SAL_INFO("cppcanvas.emf", "EMF+ Header");
1296 : SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " version: " << std::dec << version << " horizontal DPI: " << nHDPI << " vertical DPI: " << nVDPI << " dual: " << (flags & 1));
1297 :
1298 0 : break;
1299 : case EmfPlusRecordTypeEndOfFile:
1300 : SAL_INFO("cppcanvas.emf", "EMF+ EndOfFile");
1301 0 : break;
1302 : case EmfPlusRecordTypeGetDC:
1303 : SAL_INFO("cppcanvas.emf", "EMF+ GetDC");
1304 : SAL_INFO("cppcanvas.emf", "EMF+\talready used in svtools wmf/emf filter parser");
1305 0 : break;
1306 : case EmfPlusRecordTypeObject:
1307 0 : processObjectRecord (rMF, flags, dataSize);
1308 0 : break;
1309 : case EmfPlusRecordTypeFillPie:
1310 : {
1311 : sal_uInt32 brushIndexOrColor;
1312 : float startAngle, sweepAngle;
1313 :
1314 0 : rMF >> brushIndexOrColor >> startAngle >> sweepAngle;
1315 :
1316 : SAL_INFO("cppcanvas.emf", "EMF+ FillPie colorOrIndex: " << brushIndexOrColor << " startAngle: " << startAngle << " sweepAngle: " << sweepAngle);
1317 :
1318 : float dx, dy, dw, dh;
1319 :
1320 0 : ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1321 :
1322 : SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1323 :
1324 0 : startAngle = 2*M_PI*startAngle/360;
1325 0 : sweepAngle = 2*M_PI*sweepAngle/360;
1326 :
1327 0 : B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
1328 0 : B2DSize mappedSize( MapSize (dw/2, dh/2));
1329 :
1330 0 : float endAngle = startAngle + sweepAngle;
1331 0 : startAngle = fmodf(startAngle, static_cast<float>(M_PI*2));
1332 0 : if (startAngle < 0)
1333 0 : startAngle += static_cast<float>(M_PI*2);
1334 0 : endAngle = fmodf(endAngle, static_cast<float>(M_PI*2));
1335 0 : if (endAngle < 0)
1336 0 : endAngle += static_cast<float>(M_PI*2);
1337 :
1338 0 : if (sweepAngle < 0)
1339 0 : std::swap (endAngle, startAngle);
1340 :
1341 : SAL_INFO("cppcanvas.emf", "EMF+ adjusted angles: start " <<
1342 : (360.0*startAngle/M_PI) << ", end: " << (360.0*endAngle/M_PI));
1343 :
1344 0 : B2DPolygon polygon = tools::createPolygonFromEllipseSegment (mappedCenter, mappedSize.getX (), mappedSize.getY (), startAngle, endAngle);
1345 0 : polygon.append (mappedCenter);
1346 0 : polygon.setClosed (true);
1347 :
1348 0 : B2DPolyPolygon polyPolygon (polygon);
1349 0 : EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1350 : }
1351 0 : break;
1352 : case EmfPlusRecordTypeFillPath:
1353 : {
1354 0 : sal_uInt32 index = flags & 0xff;
1355 : sal_uInt32 brushIndexOrColor;
1356 :
1357 0 : rMF >> brushIndexOrColor;
1358 :
1359 : SAL_INFO("cppcanvas.emf", "EMF+ FillPath slot: " << index);
1360 :
1361 0 : EMFPPlusFillPolygon (((EMFPPath*) aObjects [index])->GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1362 : }
1363 0 : break;
1364 : case EmfPlusRecordTypeDrawEllipse:
1365 : case EmfPlusRecordTypeFillEllipse:
1366 : {
1367 : // Intentionally very bogus initial value to avoid MSVC complaining about potentially uninitialized local
1368 : // variable. As long as the code stays as intended, this variable will be assigned a (real) value in the case
1369 : // when it is later used.
1370 0 : sal_uInt32 brushIndexOrColor = 1234567;
1371 :
1372 0 : if ( type == EmfPlusRecordTypeFillEllipse )
1373 0 : rMF >> brushIndexOrColor;
1374 :
1375 : SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeFillEllipse ? "Fill" : "Draw") << "Ellipse slot: " << (flags & 0xff));
1376 :
1377 : float dx, dy, dw, dh;
1378 :
1379 0 : ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1380 :
1381 : SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1382 :
1383 0 : B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
1384 0 : B2DSize mappedSize( MapSize (dw/2, dh/2));
1385 :
1386 0 : ::basegfx::B2DPolyPolygon polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromEllipse( mappedCenter, mappedSize.getX (), mappedSize.getY () ) ) );
1387 :
1388 0 : if ( type == EmfPlusRecordTypeFillEllipse )
1389 : EMFPPlusFillPolygon( polyPolygon,
1390 0 : rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor );
1391 : else
1392 : EMFPPlusDrawPolygon( polyPolygon,
1393 0 : rFactoryParms, rState, rCanvas, flags & 0xff );
1394 : }
1395 0 : break;
1396 : case EmfPlusRecordTypeFillRects:
1397 : {
1398 : SAL_INFO("cppcanvas.emf", "EMF+ FillRects");
1399 :
1400 : sal_uInt32 brushIndexOrColor;
1401 : sal_Int32 rectangles;
1402 0 : bool isColor = (flags & 0x8000);
1403 0 : ::basegfx::B2DPolygon polygon;
1404 :
1405 0 : rMF >> brushIndexOrColor >> rectangles;
1406 :
1407 : SAL_INFO("cppcanvas.emf", "EMF+\t" << ((flags & 0x8000) ? "color" : "brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
1408 :
1409 0 : for (int i=0; i < rectangles; i++) {
1410 0 : if (flags & 0x4000) {
1411 : /* 16bit integers */
1412 : sal_Int16 x, y, width, height;
1413 :
1414 0 : rMF >> x >> y >> width >> height;
1415 :
1416 0 : polygon.append (Map (x, y));
1417 0 : polygon.append (Map (x + width, y));
1418 0 : polygon.append (Map (x + width, y + height));
1419 0 : polygon.append (Map (x, y + height));
1420 :
1421 : SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x << "," << " " << width << "x" << height);
1422 : } else {
1423 : /* Single's */
1424 : float x, y, width, height;
1425 :
1426 0 : rMF >> x >> y >> width >> height;
1427 :
1428 0 : polygon.append (Map (x, y));
1429 0 : polygon.append (Map (x + width, y));
1430 0 : polygon.append (Map (x + width, y + height));
1431 0 : polygon.append (Map (x, y + height));
1432 :
1433 : SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x << "," << " " << width << "x" << height);
1434 : }
1435 :
1436 0 : ::basegfx::B2DPolyPolygon polyPolygon (polygon);
1437 :
1438 : // n#812793: EMF+ Seems to specify transparent background with Alpha=0xFF !
1439 : // Workaround for the problem.
1440 0 : if( isColor && brushIndexOrColor == 0xFFFFFFFF && rectangles == 1 )
1441 0 : brushIndexOrColor = 0xFFFFFF;
1442 :
1443 0 : EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, isColor, brushIndexOrColor);
1444 0 : }
1445 0 : break;
1446 : }
1447 : case EmfPlusRecordTypeFillPolygon:
1448 : {
1449 0 : sal_uInt8 index = flags & 0xff;
1450 : sal_uInt32 brushIndexOrColor;
1451 : sal_Int32 points;
1452 :
1453 0 : rMF >> brushIndexOrColor;
1454 0 : rMF >> points;
1455 :
1456 : SAL_INFO("cppcanvas.emf", "EMF+ FillPolygon in slot: " << +index << " points: " << points);
1457 : SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags & 0x8000) ? "color" : "brush index") << " 0x" << std::hex << brushIndexOrColor << std::dec);
1458 :
1459 0 : EMFPPath path (points, true);
1460 0 : path.Read (rMF, flags, *this);
1461 :
1462 0 : EMFPPlusFillPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
1463 :
1464 0 : break;
1465 : }
1466 : case EmfPlusRecordTypeDrawLines:
1467 : {
1468 : sal_uInt32 points;
1469 :
1470 0 : rMF >> points;
1471 :
1472 : SAL_INFO("cppcanvas.emf", "EMF+ DrawLines in slot: " << (flags && 0xff) << " points: " << points);
1473 :
1474 0 : EMFPPath path (points, true);
1475 0 : path.Read (rMF, flags, *this);
1476 :
1477 0 : EMFPPlusDrawPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags);
1478 :
1479 0 : break;
1480 : }
1481 : case EmfPlusRecordTypeDrawPath:
1482 : {
1483 : sal_uInt32 penIndex;
1484 :
1485 0 : rMF >> penIndex;
1486 :
1487 : SAL_INFO("cppcanvas.emf", "EMF+ DrawPath");
1488 : SAL_INFO("cppcanvas.emf", "EMF+\tpen: " << penIndex);
1489 :
1490 0 : EMFPPath* path = (EMFPPath*) aObjects [flags & 0xff];
1491 : SAL_WARN_IF( !path, "cppcanvas.emf", "EmfPlusRecordTypeDrawPath missing path" );
1492 :
1493 0 : EMFPPlusDrawPolygon (path->GetPolygon (*this), rFactoryParms, rState, rCanvas, penIndex);
1494 :
1495 0 : break;
1496 : }
1497 : case EmfPlusRecordTypeDrawImage:
1498 : case EmfPlusRecordTypeDrawImagePoints:
1499 : {
1500 : sal_uInt32 attrIndex;
1501 : sal_Int32 sourceUnit;
1502 :
1503 0 : rMF >> attrIndex >> sourceUnit;
1504 :
1505 : SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << "attributes index: " << attrIndex << "source unit: " << sourceUnit);
1506 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO: use image attributes");
1507 :
1508 0 : if (sourceUnit == 2 && aObjects [flags & 0xff]) { // we handle only GraphicsUnit.Pixel now
1509 0 : EMFPImage& image = *(EMFPImage *) aObjects [flags & 0xff];
1510 : float sx, sy, sw, sh;
1511 : sal_Int32 aCount;
1512 :
1513 0 : ReadRectangle (rMF, sx, sy, sw, sh);
1514 :
1515 : SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << " source rectangle: " << sx << "," << sy << " " << sw << "x" << sh);
1516 :
1517 0 : ::basegfx::B2DPoint aDstPoint;
1518 0 : ::basegfx::B2DSize aDstSize;
1519 0 : bool bValid = false;
1520 :
1521 0 : if (type == EmfPlusRecordTypeDrawImagePoints) {
1522 0 : rMF >> aCount;
1523 :
1524 0 : if( aCount == 3) { // TODO: now that we now that this value is count we should support it better
1525 : float x1, y1, x2, y2, x3, y3;
1526 :
1527 0 : ReadPoint (rMF, x1, y1, flags);
1528 0 : ReadPoint (rMF, x2, y2, flags);
1529 0 : ReadPoint (rMF, x3, y3, flags);
1530 :
1531 : SAL_INFO("cppcanvas.emf", "EMF+ destination points: " << x1 << "," << y1 << " " << x2 << "," << y2 << " " << x3 << "," << y3);
1532 : SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << x1 << "," << y1 << " " << x2 - x1 << "x" << y3 - y1);
1533 :
1534 0 : aDstPoint = Map (x1, y1);
1535 0 : aDstSize = MapSize(x2 - x1, y3 - y1);
1536 :
1537 0 : bValid = true;
1538 : }
1539 0 : } else if (type == EmfPlusRecordTypeDrawImage) {
1540 : float dx, dy, dw, dh;
1541 :
1542 0 : ReadRectangle (rMF, dx, dy, dw, dh, flags & 0x4000);
1543 :
1544 : SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
1545 :
1546 0 : aDstPoint = Map (dx, dy);
1547 0 : aDstSize = MapSize(dw, dh);
1548 :
1549 0 : bValid = true;
1550 : }
1551 :
1552 0 : if (bValid) {
1553 0 : BitmapEx aBmp( image.graphic.GetBitmapEx () );
1554 :
1555 0 : Size aSize( aBmp.GetSizePixel() );
1556 : SAL_INFO("cppcanvas.emf", "EMF+ bitmap size: " << aSize.Width() << "x" << aSize.Height());
1557 0 : if( aSize.Width() > 0 && aSize.Height() > 0 ) {
1558 : ActionSharedPtr pBmpAction (
1559 : internal::BitmapActionFactory::createBitmapAction (
1560 : aBmp,
1561 0 : rState.mapModeTransform * aDstPoint,
1562 0 : rState.mapModeTransform * aDstSize,
1563 : rCanvas,
1564 0 : rState));
1565 :
1566 0 : if( pBmpAction ) {
1567 : maActions.push_back( MtfAction( pBmpAction,
1568 0 : rFactoryParms.mrCurrActionIndex ) );
1569 :
1570 0 : rFactoryParms.mrCurrActionIndex += pBmpAction->getActionCount()-1;
1571 0 : }
1572 : } else {
1573 : SAL_INFO("cppcanvas.emf", "EMF+ warning: empty bitmap");
1574 0 : }
1575 : } else {
1576 : SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme)");
1577 0 : }
1578 : } else {
1579 : SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme) - possibly unsupported source units for crop rectangle");
1580 : }
1581 0 : break;
1582 : }
1583 : case EmfPlusRecordTypeDrawString:
1584 : {
1585 : SAL_INFO("cppcanvas.emf", "EMF+ DrawString");
1586 :
1587 : sal_uInt32 brushId;
1588 : sal_uInt32 formatId;
1589 : sal_uInt32 stringLength;
1590 :
1591 0 : rMF >> brushId >> formatId >> stringLength;
1592 : SAL_INFO("cppcanvas.emf", "EMF+ DrawString brushId: " << brushId << " formatId: " << formatId << " length: " << stringLength);
1593 :
1594 0 : if (flags & 0x8000) {
1595 : float lx, ly, lw, lh;
1596 :
1597 0 : rMF >> lx >> ly >> lw >> lh;
1598 :
1599 : SAL_INFO("cppcanvas.emf", "EMF+ DrawString layoutRect: " << lx << "," << ly << " - " << lw << "x" << lh);
1600 :
1601 0 : OUString text = read_uInt16s_ToOUString(rMF, stringLength);
1602 :
1603 0 : double cellSize = setFont (flags & 0xff, rFactoryParms, rState);
1604 0 : rState.textColor = COLOR( brushId );
1605 :
1606 0 : ::basegfx::B2DPoint point( Map( lx + 0.15*cellSize, ly + cellSize ) );
1607 :
1608 : ActionSharedPtr pTextAction(
1609 : TextActionFactory::createTextAction(
1610 : // position is just rough guess for now
1611 : // we should calculate it exactly from layoutRect or font
1612 : ::vcl::unotools::pointFromB2DPoint ( point ),
1613 : ::Size(),
1614 : ::Color(),
1615 : ::Size(),
1616 : ::Color(),
1617 : text,
1618 : 0,
1619 : stringLength,
1620 : NULL,
1621 : rFactoryParms.mrVDev,
1622 : rFactoryParms.mrCanvas,
1623 : rState,
1624 : rFactoryParms.mrParms,
1625 0 : false ) );
1626 0 : if( pTextAction )
1627 : {
1628 : SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
1629 :
1630 : maActions.push_back(
1631 : MtfAction(
1632 : pTextAction,
1633 0 : rFactoryParms.mrCurrActionIndex ) );
1634 :
1635 0 : rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
1636 0 : }
1637 : } else {
1638 : SAL_INFO("cppcanvas.emf", "EMF+ DrawString TODO - drawing with brush not yet supported");
1639 : }
1640 : }
1641 0 : break;
1642 : case EmfPlusRecordTypeSetPageTransform:
1643 0 : rMF >> fPageScale;
1644 :
1645 : SAL_INFO("cppcanvas.emf", "EMF+ SetPageTransform");
1646 : SAL_INFO("cppcanvas.emf", "EMF+\tscale: " << fPageScale << " unit: " << flags);
1647 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1648 0 : break;
1649 : case EmfPlusRecordTypeSetRenderingOrigin:
1650 0 : rMF >> nOriginX >> nOriginY;
1651 : SAL_INFO("cppcanvas.emf", "EMF+ SetRenderingOrigin");
1652 : SAL_INFO("cppcanvas.emf", "EMF+\torigin [x,y]: " << nOriginX << "," << nOriginY);
1653 0 : break;
1654 : case EmfPlusRecordTypeSetTextRenderingHint:
1655 : SAL_INFO("cppcanvas.emf", "EMF+ SetTextRenderingHint");
1656 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1657 0 : break;
1658 : case EmfPlusRecordTypeSetAntiAliasMode:
1659 : SAL_INFO("cppcanvas.emf", "EMF+ SetAntiAliasMode");
1660 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1661 0 : break;
1662 : case EmfPlusRecordTypeSetInterpolationMode:
1663 : SAL_INFO("cppcanvas.emf", "EMF+ InterpolationMode");
1664 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1665 0 : break;
1666 : case EmfPlusRecordTypeSetPixelOffsetMode:
1667 : SAL_INFO("cppcanvas.emf", "EMF+ SetPixelOffsetMode");
1668 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1669 0 : break;
1670 : case EmfPlusRecordTypeSetCompositingQuality:
1671 : SAL_INFO("cppcanvas.emf", "EMF+ SetCompositingQuality");
1672 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1673 0 : break;
1674 : case EmfPlusRecordTypeSave:
1675 : {
1676 : sal_uInt32 stackIndex;
1677 :
1678 0 : rMF >> stackIndex;
1679 :
1680 : SAL_INFO("cppcanvas.emf", "EMF+ Save stack index: " << stackIndex);
1681 :
1682 0 : GraphicStatePush( mGSStack, stackIndex, rState );
1683 :
1684 0 : break;
1685 : }
1686 : case EmfPlusRecordTypeRestore:
1687 : {
1688 : sal_uInt32 stackIndex;
1689 :
1690 0 : rMF >> stackIndex;
1691 :
1692 : SAL_INFO("cppcanvas.emf", "EMF+ Restore stack index: " << stackIndex);
1693 :
1694 0 : GraphicStatePop( mGSStack, stackIndex, rState );
1695 :
1696 0 : break;
1697 : }
1698 : case EmfPlusRecordTypeBeginContainerNoParams:
1699 : {
1700 : sal_uInt32 stackIndex;
1701 :
1702 0 : rMF >> stackIndex;
1703 :
1704 : SAL_INFO("cppcanvas.emf", "EMF+ Begin Container No Params stack index: " << stackIndex);
1705 :
1706 0 : GraphicStatePush( mGSContainerStack, stackIndex, rState );
1707 : }
1708 0 : break;
1709 : case EmfPlusRecordTypeEndContainer:
1710 : {
1711 : sal_uInt32 stackIndex;
1712 :
1713 0 : rMF >> stackIndex;
1714 :
1715 : SAL_INFO("cppcanvas.emf", "EMF+ End Container stack index: " << stackIndex);
1716 :
1717 0 : GraphicStatePop( mGSContainerStack, stackIndex, rState );
1718 : }
1719 0 : break;
1720 : case EmfPlusRecordTypeSetWorldTransform: {
1721 : SAL_INFO("cppcanvas.emf", "EMF+ SetWorldTransform");
1722 0 : XForm transform;
1723 0 : rMF >> transform;
1724 0 : aWorldTransform.Set (transform);
1725 : SAL_INFO("cppcanvas.emf",
1726 : "EMF+\tm11: " << aWorldTransform.eM11 << "\tm12: " << aWorldTransform.eM12 <<
1727 : "\tm21: " << aWorldTransform.eM21 << "\tm22: " << aWorldTransform.eM22 <<
1728 : "\tdx: " << aWorldTransform.eDx << "\tdy: " << aWorldTransform.eDy);
1729 0 : break;
1730 : }
1731 : case EmfPlusRecordTypeResetWorldTransform:
1732 : SAL_INFO("cppcanvas.emf", "EMF+ ResetWorldTransform");
1733 0 : aWorldTransform.SetIdentity ();
1734 0 : break;
1735 : case EmfPlusRecordTypeMultiplyWorldTransform: {
1736 : SAL_INFO("cppcanvas.emf", "EMF+ MultiplyWorldTransform");
1737 0 : XForm transform;
1738 0 : rMF >> transform;
1739 :
1740 : SAL_INFO("cppcanvas.emf",
1741 : "EMF+\tmatrix m11: " << transform.eM11 << "m12: " << transform.eM12 <<
1742 : "EMF+\tm21: " << transform.eM21 << "m22: " << transform.eM22 <<
1743 : "EMF+\tdx: " << transform.eDx << "dy: " << transform.eDy);
1744 :
1745 0 : if (flags & 0x2000) // post multiply
1746 0 : aWorldTransform.Multiply (transform);
1747 : else { // pre multiply
1748 0 : transform.Multiply (aWorldTransform);
1749 0 : aWorldTransform.Set (transform);
1750 : }
1751 : SAL_INFO("cppcanvas.emf",
1752 : "EMF+\tm11: " << aWorldTransform.eM11 << "m12: " << aWorldTransform.eM12 <<
1753 : "EMF+\tm21: " << aWorldTransform.eM21 << "m22: " << aWorldTransform.eM22 <<
1754 : "EMF+\tdx: " << aWorldTransform.eDx << "dy: " << aWorldTransform.eDy);
1755 0 : break;
1756 : }
1757 : case EmfPlusRecordTypeSetClipRect:
1758 : {
1759 0 : int combineMode = (flags >> 8) & 0xf;
1760 :
1761 : SAL_INFO("cppcanvas.emf", "EMF+ SetClipRect combine mode: " << combineMode);
1762 : #if OSL_DEBUG_LEVEL > 1
1763 : if (combineMode > 1) {
1764 : SAL_INFO ("cppcanvas.emf", "EMF+ TODO combine mode > 1");
1765 : }
1766 : #endif
1767 :
1768 : float dx, dy, dw, dh;
1769 :
1770 0 : ReadRectangle (rMF, dx, dy, dw, dh, false);
1771 :
1772 : SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
1773 :
1774 0 : B2DPoint mappedPoint (Map (dx, dy));
1775 0 : B2DSize mappedSize( MapSize (dw, dh));
1776 :
1777 : ::basegfx::B2DPolyPolygon polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromRect( ::basegfx::B2DRectangle( mappedPoint.getX(), mappedPoint.getY(),
1778 0 : mappedPoint.getX() + mappedSize.getX(),
1779 0 : mappedPoint.getY() + mappedSize.getY() ) ) ) );
1780 0 : polyPolygon.transform(rState.mapModeTransform);
1781 :
1782 0 : updateClipping (polyPolygon, rFactoryParms, combineMode == 1);
1783 :
1784 0 : break;
1785 : }
1786 : case EmfPlusRecordTypeSetClipPath:
1787 : {
1788 0 : int combineMode = (flags >> 8) & 0xf;
1789 :
1790 : SAL_INFO("cppcanvas.emf", "EMF+ SetClipPath combine mode: " << combineMode);
1791 : SAL_INFO("cppcanvas.emf", "EMF+\tpath in slot: " << (flags & 0xff));
1792 :
1793 0 : EMFPPath& path = *(EMFPPath*) aObjects [flags & 0xff];
1794 0 : ::basegfx::B2DPolyPolygon& clipPoly (path.GetPolygon (*this));
1795 :
1796 0 : clipPoly.transform (rState.mapModeTransform);
1797 0 : updateClipping (clipPoly, rFactoryParms, combineMode == 1);
1798 :
1799 0 : break;
1800 : }
1801 : case EmfPlusRecordTypeSetClipRegion: {
1802 0 : int combineMode = (flags >> 8) & 0xf;
1803 :
1804 : SAL_INFO("cppcanvas.emf", "EMF+ SetClipRegion");
1805 : SAL_INFO("cppcanvas.emf", "EMF+\tregion in slot: " << (flags & 0xff) << " combine mode: " << combineMode);
1806 0 : EMFPRegion *region = (EMFPRegion*)aObjects [flags & 0xff];
1807 :
1808 : // reset clip
1809 0 : if (region && region->parts == 0 && region->initialState == EmfPlusRegionInitialStateInfinite) {
1810 0 : updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms, combineMode == 1);
1811 : } else {
1812 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1813 : }
1814 0 : break;
1815 : }
1816 : case EmfPlusRecordTypeDrawDriverString: {
1817 : SAL_INFO("cppcanvas.emf", "EMF+ DrawDriverString, flags: 0x" << std::hex << flags << std::dec);
1818 : sal_uInt32 brushIndexOrColor;
1819 : sal_uInt32 optionFlags;
1820 : sal_uInt32 hasMatrix;
1821 : sal_uInt32 glyphsCount;
1822 :
1823 0 : rMF >> brushIndexOrColor >> optionFlags >> hasMatrix >> glyphsCount;
1824 :
1825 : SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags & 0x8000) ? "color" : "brush index") << " 0x" << std::hex << brushIndexOrColor << std::dec);
1826 : SAL_INFO("cppcanvas.emf", "EMF+\toption flags: 0x" << std::hex << optionFlags << std::dec);
1827 : SAL_INFO("cppcanvas.emf", "EMF+\thas matrix: " << hasMatrix);
1828 : SAL_INFO("cppcanvas.emf", "EMF+\tglyphs: " << glyphsCount);
1829 :
1830 0 : if( ( optionFlags & 1 ) && glyphsCount > 0 ) {
1831 0 : float *charsPosX = new float[glyphsCount];
1832 0 : float *charsPosY = new float[glyphsCount];
1833 :
1834 0 : OUString text = read_uInt16s_ToOUString(rMF, glyphsCount);
1835 :
1836 0 : for( sal_uInt32 i=0; i<glyphsCount; i++) {
1837 0 : rMF >> charsPosX[i] >> charsPosY[i];
1838 : SAL_INFO("cppcanvas.emf", "EMF+\tglyphPosition[" << i << "]: " << charsPosX[i] << "," << charsPosY[i]);
1839 : }
1840 :
1841 0 : XForm transform;
1842 0 : if( hasMatrix ) {
1843 0 : rMF >> transform;
1844 : SAL_INFO("cppcanvas.emf", "EMF+\tmatrix: " << transform.eM11 << ", " << transform.eM12 << ", " << transform.eM21 << ", " << transform.eM22 << ", " << transform.eDx << ", " << transform.eDy);
1845 : }
1846 :
1847 : // add the text action
1848 0 : setFont (flags & 0xff, rFactoryParms, rState);
1849 :
1850 0 : if( flags & 0x8000 )
1851 0 : rState.textColor = COLOR( brushIndexOrColor );
1852 :
1853 0 : ::basegfx::B2DPoint point( Map( charsPosX[0], charsPosY[0] ) );
1854 :
1855 : ActionSharedPtr pTextAction(
1856 : TextActionFactory::createTextAction(
1857 : ::vcl::unotools::pointFromB2DPoint ( point ),
1858 : ::Size(),
1859 : ::Color(),
1860 : ::Size(),
1861 : ::Color(),
1862 : text,
1863 : 0,
1864 : glyphsCount,
1865 : NULL,
1866 : rFactoryParms.mrVDev,
1867 : rFactoryParms.mrCanvas,
1868 : rState,
1869 : rFactoryParms.mrParms,
1870 0 : false ) );
1871 :
1872 0 : if( pTextAction )
1873 : {
1874 : SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
1875 :
1876 : maActions.push_back(
1877 : MtfAction(
1878 : pTextAction,
1879 0 : rFactoryParms.mrCurrActionIndex ) );
1880 :
1881 0 : rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
1882 : }
1883 :
1884 0 : delete[] charsPosX;
1885 0 : delete[] charsPosY;
1886 : } else {
1887 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
1888 : }
1889 :
1890 0 : break;
1891 : }
1892 : default:
1893 : SAL_INFO("cppcanvas.emf", "EMF+ unhandled record type: " << type);
1894 : SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1895 : }
1896 : }
1897 :
1898 0 : rMF.Seek (next);
1899 :
1900 0 : if (size <= length)
1901 : {
1902 0 : length -= size;
1903 : }
1904 : else
1905 : {
1906 : SAL_WARN("cppcanvas.emf", "ImplRenderer::processEMFPlus: "
1907 : "size " << size << " > length " << length);
1908 : #if OSL_DEBUG_LEVEL > 1
1909 : dumpWords(rMF, length);
1910 : #endif
1911 0 : length = 0;
1912 : }
1913 0 : }
1914 0 : }
1915 : }
1916 411 : }
1917 :
1918 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|