1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
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>
45 #include <bitmapaction.hxx>
46 #include <implrenderer.hxx>
47 #include <outdevstate.hxx>
48 #include <polypolyaction.hxx>
49 #include <textaction.hxx>
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
86 #define EmfPlusObjectTypeBrush 0x100
87 #define EmfPlusObjectTypePen 0x200
88 #define EmfPlusObjectTypePath 0x300
89 #define EmfPlusObjectTypeRegion 0x400
90 #define EmfPlusObjectTypeImage 0x500
91 #define EmfPlusObjectTypeFont 0x600
93 #define EmfPlusRegionInitialStateInfinite 0x10000003
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;
102 const sal_uInt32 EmfPlusCustomLineCapDataTypeDefault
= 0x00000000;
103 const sal_uInt32 EmfPlusCustomLineCapDataTypeAdjustableArrow
= 0x00000001;
105 const sal_uInt32 EmfPlusCustomLineCapDataFillPath
= 0x00000001;
106 const sal_uInt32 EmfPlusCustomLineCapDataLinePath
= 0x00000002;
108 const sal_uInt32 EmfPlusLineCapTypeSquare
= 0x00000001;
109 const sal_uInt32 EmfPlusLineCapTypeRound
= 0x00000002;
111 const sal_uInt32 EmfPlusLineJoinTypeMiter
= 0x00000000;
112 const sal_uInt32 EmfPlusLineJoinTypeBevel
= 0x00000001;
113 const sal_uInt32 EmfPlusLineJoinTypeRound
= 0x00000002;
114 const sal_uInt32 EmfPlusLineJoinTypeMiterClipped
= 0x00000003;
116 using namespace ::com::sun::star
;
117 using namespace ::basegfx
;
124 #if OSL_DEBUG_LEVEL > 1
125 void dumpWords (SvStream
& s
, int i
)
127 sal_uInt32 pos
= s
.Tell ();
129 SAL_INFO ("cppcanvas.emf", "EMF+ dumping words");
130 for (; i
> 0; i
--) {
132 SAL_INFO ("cppcanvas.emf", "EMF+\tdata: " << std::hex
<< data
<< std::dec
);
134 SAL_INFO ("cppcanvas.emf", "EMF+ end dumping words");
139 struct EMFPPath
: public EMFPObject
141 ::basegfx::B2DPolyPolygon aPolygon
;
144 sal_uInt8
* pPointTypes
;
147 EMFPPath (sal_Int32 _nPoints
, bool bLines
= false)
149 if( _nPoints
<0 || sal_uInt32(_nPoints
)>SAL_MAX_INT32
/(2*sizeof(float)) )
150 _nPoints
= SAL_MAX_INT32
/(2*sizeof(float));
152 pPoints
= new float [nPoints
*2];
154 pPointTypes
= new sal_uInt8
[_nPoints
];
162 delete [] pPointTypes
;
165 // TODO: remove rR argument when debug code is not longer needed
166 void Read (SvStream
& s
, sal_uInt32 pathFlags
, ImplRenderer
& rR
)
168 for (int i
= 0; i
< nPoints
; i
++) {
169 if (pathFlags
& 0x4000) {
170 // points are stored in short 16bit integer format
174 SAL_INFO ("cppcanvas.emf", "EMF+\tpoint [x,y]: " << x
<< "," << y
);
176 pPoints
[i
*2 + 1] = y
;
178 // points are stored in Single (float) format
179 s
>> pPoints
[i
*2] >> pPoints
[i
*2 + 1];
180 SAL_INFO ("cppcanvas.emf", "EMF+\tpoint [x,y]: " << pPoints
[i
*2] << "," << pPoints
[i
*2 + 1]);
185 for (int i
= 0; i
< nPoints
; i
++) {
186 s
>> pPointTypes
[i
];
187 SAL_INFO ("cppcanvas.emf", "EMF+\tpoint type: " << (int)pPointTypes
[i
]);
192 #if OSL_DEBUG_LEVEL > 1
193 const ::basegfx::B2DRectangle
aBounds (::basegfx::tools::getRange (GetPolygon (rR
)));
195 SAL_INFO ("cppcanvas.emf",
196 "EMF+\tpolygon bounding box: " << aBounds
.getMinX () << "," << aBounds
.getMinY () << aBounds
.getWidth () << "x" << aBounds
.getHeight () << " (mapped)");
198 (void) rR
; // avoid warnings
202 ::basegfx::B2DPolyPolygon
& GetPolygon (ImplRenderer
& rR
, bool bMapIt
= true)
204 ::basegfx::B2DPolygon polygon
;
208 int last_normal
= 0, p
= 0;
209 ::basegfx::B2DPoint prev
, mapped
;
210 bool hasPrev
= false;
211 for (int i
= 0; i
< nPoints
; i
++) {
212 if (p
&& pPointTypes
&& (pPointTypes
[i
] == 0)) {
213 aPolygon
.append (polygon
);
220 mapped
= rR
.Map (pPoints
[i
*2], pPoints
[i
*2 + 1]);
222 mapped
= ::basegfx::B2DPoint (pPoints
[i
*2], pPoints
[i
*2 + 1]);
224 if ((pPointTypes
[i
] & 0x07) == 3) {
225 if (((i
- last_normal
)% 3) == 1) {
226 polygon
.setNextControlPoint (p
- 1, mapped
);
227 SAL_INFO ("cppcanvas.emf", "polygon append next: " << p
- 1 << " mapped: " << mapped
.getX () << "," << mapped
.getY ());
229 } else if (((i
- last_normal
) % 3) == 2) {
237 polygon
.append (mapped
);
238 SAL_INFO ("cppcanvas.emf", "polygon append point: " << pPoints
[i
*2] << "," << pPoints
[i
*2 + 1] << " mapped: " << mapped
.getX () << ":" << mapped
.getY ());
240 polygon
.setPrevControlPoint (p
, prev
);
241 SAL_INFO ("cppcanvas.emf", "polygon append prev: " << p
<< " mapped: " << prev
.getX () << "," << prev
.getY ());
245 if (pPointTypes
&& (pPointTypes
[i
] & 0x80)) { // closed polygon
246 polygon
.setClosed (true);
247 aPolygon
.append (polygon
);
248 SAL_INFO ("cppcanvas.emf", "close polygon");
255 if (polygon
.count ()) {
256 aPolygon
.append (polygon
);
258 #if OSL_DEBUG_LEVEL > 1
259 for (unsigned int i
=0; i
<aPolygon
.count(); i
++) {
260 polygon
= aPolygon
.getB2DPolygon(i
);
261 SAL_INFO ("cppcanvas.emf", "polygon: " << i
);
262 for (unsigned int j
=0; j
<polygon
.count(); j
++) {
263 ::basegfx::B2DPoint point
= polygon
.getB2DPoint(j
);
264 SAL_INFO ("cppcanvas.emf", "point: " << point
.getX() << "," << point
.getY());
265 if (polygon
.isPrevControlPointUsed(j
)) {
266 point
= polygon
.getPrevControlPoint(j
);
267 SAL_INFO ("cppcanvas.emf", "prev: " << point
.getX() << "," << point
.getY());
269 if (polygon
.isNextControlPointUsed(j
)) {
270 point
= polygon
.getNextControlPoint(j
);
271 SAL_INFO ("cppcanvas.emf", "next: " << point
.getX() << "," << point
.getY());
282 struct EMFPRegion
: public EMFPObject
285 sal_Int32
*combineMode
;
286 sal_Int32 initialState
;
287 EMFPPath
*initialPath
;
288 float ix
, iy
, iw
, ih
;
299 delete [] combineMode
;
308 void Read (SvStream
& s
)
312 s
>> header
>> parts
;
314 SAL_INFO ("cppcanvas.emf", "EMF+\tregion");
315 SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " parts: " << parts
<< std::dec
);
318 if( parts
<0 || sal_uInt32(parts
)>SAL_MAX_INT32
/sizeof(sal_Int32
) )
319 parts
= SAL_MAX_INT32
/sizeof(sal_Int32
);
321 combineMode
= new sal_Int32
[parts
];
323 for (int i
= 0; i
< parts
; i
++) {
324 s
>> combineMode
[i
];
325 SAL_INFO ("cppcanvas.emf", "EMF+\tcombine mode [" << i
<< "]: 0x" << std::hex
<< combineMode
[i
] << std::dec
);
330 SAL_INFO ("cppcanvas.emf", "EMF+\tinitial state: 0x" << std::hex
<< initialState
<< std::dec
);
334 struct EMFPBrush
: public EMFPObject
338 sal_uInt32 additionalFlags
;
340 /* linear gradient */
342 float areaX
, areaY
, areaWidth
, areaHeight
;
343 ::Color secondColor
; // first color is stored in solidColor;
344 XForm transformation
;
345 bool hasTransformation
;
346 sal_Int32 blendPoints
;
347 float* blendPositions
;
349 sal_Int32 colorblendPoints
;
350 float* colorblendPositions
;
351 ::Color
* colorblendColors
;
352 sal_Int32 surroundColorsNumber
;
353 ::Color
* surroundColors
;
359 blendPositions
= NULL
;
360 colorblendPositions
= NULL
;
361 colorblendColors
= NULL
;
362 surroundColors
= NULL
;
364 hasTransformation
= false;
369 if (blendPositions
!= NULL
) {
370 delete[] blendPositions
;
371 blendPositions
= NULL
;
373 if (colorblendPositions
!= NULL
) {
374 delete[] colorblendPositions
;
375 colorblendPositions
= NULL
;
377 if (colorblendColors
!= NULL
) {
378 delete[] colorblendColors
;
379 colorblendColors
= NULL
;
381 if (surroundColors
!= NULL
) {
382 delete[] surroundColors
;
383 surroundColors
= NULL
;
391 sal_uInt32
GetType() const { return type
; }
392 const ::Color
& GetColor() const { return solidColor
; }
394 void Read (SvStream
& s
, ImplRenderer
& rR
)
400 SAL_INFO ("cppcanvas.emf", "EMF+\tbrush");
401 SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " type: " << type
<< std::dec
);
409 solidColor
= ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
410 SAL_INFO ("cppcanvas.emf", "EMF+\tsolid color: 0x" << std::hex
<< color
<< std::dec
);
417 s
>> additionalFlags
>> wrapMode
;
419 SAL_INFO ("cppcanvas.emf", "EMF+\tpath gradient, additional flags: 0x" << std::hex
<< additionalFlags
<< std::dec
);
424 solidColor
= ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
425 SAL_INFO("cppcanvas.emf", "EMF+\tcenter color: 0x" << std::hex
<< color
<< std::dec
);
428 SAL_INFO("cppcanvas.emf", "EMF+\tcenter point: " << areaX
<< "," << areaY
);
430 s
>> surroundColorsNumber
;
431 SAL_INFO("cppcanvas.emf", "EMF+\tsurround colors: " << surroundColorsNumber
);
433 if( surroundColorsNumber
<0 || sal_uInt32(surroundColorsNumber
)>SAL_MAX_INT32
/sizeof(::Color
) )
434 surroundColorsNumber
= SAL_MAX_INT32
/sizeof(::Color
);
436 surroundColors
= new ::Color
[surroundColorsNumber
];
437 for (int i
= 0; i
< surroundColorsNumber
; i
++) {
439 surroundColors
[i
] = ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
441 secondColor
= surroundColors
[0];
442 SAL_INFO("cppcanvas.emf", "EMF+\tsurround color[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
445 if (additionalFlags
& 0x01) {
446 sal_Int32 pathLength
;
449 SAL_INFO("cppcanvas.emf", "EMF+\tpath length: " << pathLength
);
451 sal_uInt32 pos
= s
.Tell ();
452 #if OSL_DEBUG_LEVEL > 1
456 sal_uInt32 pathHeader
;
457 sal_Int32 pathPoints
, pathFlags
;
458 s
>> pathHeader
>> pathPoints
>> pathFlags
;
460 SAL_INFO("cppcanvas.emf", "EMF+\tpath (brush path gradient)");
461 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< pathHeader
<< " points: " << std::dec
<< pathPoints
<< " additional flags: 0x" << std::hex
<< pathFlags
<< std::dec
);
463 path
= new EMFPPath (pathPoints
);
464 path
->Read (s
, pathFlags
, rR
);
466 s
.Seek (pos
+ pathLength
);
468 const ::basegfx::B2DRectangle
aBounds (::basegfx::tools::getRange (path
->GetPolygon (rR
, false)));
469 areaWidth
= aBounds
.getWidth ();
470 areaHeight
= aBounds
.getHeight ();
472 SAL_INFO("cppcanvas.emf", "EMF+\tpolygon bounding box: " << aBounds
.getMinX () << "," << aBounds
.getMinY () << " " << aBounds
.getWidth () << "x" << aBounds
.getHeight ());
475 if (additionalFlags
& 0x02) {
476 SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
478 hasTransformation
= true;
479 SAL_INFO("cppcanvas.emf",
480 "EMF+\tm11: " << transformation
.eM11
<< " m12: " << transformation
.eM12
<<
481 "\nEMF+\tm21: " << transformation
.eM21
<< " m22: " << transformation
.eM22
<<
482 "\nEMF+\tdx: " << transformation
.eDx
<< " dy: " << transformation
.eDy
);
485 if (additionalFlags
& 0x08) {
487 SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints
);
488 if( blendPoints
<0 || sal_uInt32(blendPoints
)>SAL_MAX_INT32
/(2*sizeof(float)) )
489 blendPoints
= SAL_MAX_INT32
/(2*sizeof(float));
490 blendPositions
= new float [2*blendPoints
];
491 blendFactors
= blendPositions
+ blendPoints
;
492 for (int i
=0; i
< blendPoints
; i
++) {
493 s
>> blendPositions
[i
];
494 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i
<< "]: " << blendPositions
[i
]);
496 for (int i
=0; i
< blendPoints
; i
++) {
497 s
>> blendFactors
[i
];
498 SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i
<< "]: " << blendFactors
[i
]);
502 if (additionalFlags
& 0x04) {
503 s
>> colorblendPoints
;
504 SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints
);
505 if( colorblendPoints
<0 || sal_uInt32(colorblendPoints
)>SAL_MAX_INT32
/sizeof(float) )
506 colorblendPoints
= SAL_MAX_INT32
/sizeof(float);
507 if( sal_uInt32(colorblendPoints
)>SAL_MAX_INT32
/sizeof(::Color
) )
508 colorblendPoints
= SAL_MAX_INT32
/sizeof(::Color
);
509 colorblendPositions
= new float [colorblendPoints
];
510 colorblendColors
= new ::Color
[colorblendPoints
];
511 for (int i
=0; i
< colorblendPoints
; i
++) {
512 s
>> colorblendPositions
[i
];
513 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i
<< "]: " << colorblendPositions
[i
]);
515 for (int i
=0; i
< colorblendPoints
; i
++) {
517 colorblendColors
[i
] = ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
518 SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
522 #if OSL_DEBUG_LEVEL > 1
531 s
>> additionalFlags
>> wrapMode
;
533 SAL_INFO("cppcanvas.emf", "EMF+\tlinear gradient, additional flags: 0x" << std::hex
<< additionalFlags
<< std::dec
);
535 s
>> areaX
>> areaY
>> areaWidth
>> areaHeight
;
537 SAL_INFO("cppcanvas.emf", "EMF+\tarea: " << areaX
<< "," << areaY
<< " - " << areaWidth
<< "x" << areaHeight
);
542 solidColor
= ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
543 SAL_INFO("cppcanvas.emf", "EMF+\tfirst color: 0x" << std::hex
<< color
<< std::dec
);
546 secondColor
= ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
547 SAL_INFO("cppcanvas.emf", "EMF+\tsecond color: 0x" << std::hex
<< color
<< std::dec
);
549 // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
553 if (additionalFlags
& 0x02) {
554 SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
556 hasTransformation
= true;
557 SAL_INFO("cppcanvas.emf",
558 "EMF+\tm11: " << transformation
.eM11
<< " m12: " << transformation
.eM12
<<
559 "\nEMF+\tm21: " << transformation
.eM21
<< " m22: " << transformation
.eM22
<<
560 "\nEMF+\tdx: " << transformation
.eDx
<< " dy: " << transformation
.eDy
);
562 if (additionalFlags
& 0x08) {
564 SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints
);
565 if( blendPoints
<0 || sal_uInt32(blendPoints
)>SAL_MAX_INT32
/(2*sizeof(float)) )
566 blendPoints
= SAL_MAX_INT32
/(2*sizeof(float));
567 blendPositions
= new float [2*blendPoints
];
568 blendFactors
= blendPositions
+ blendPoints
;
569 for (int i
=0; i
< blendPoints
; i
++) {
570 s
>> blendPositions
[i
];
571 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i
<< "]: " << blendPositions
[i
]);
573 for (int i
=0; i
< blendPoints
; i
++) {
574 s
>> blendFactors
[i
];
575 SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i
<< "]: " << blendFactors
[i
]);
579 if (additionalFlags
& 0x04) {
580 s
>> colorblendPoints
;
581 SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints
);
582 if( colorblendPoints
<0 || sal_uInt32(colorblendPoints
)>SAL_MAX_INT32
/sizeof(float) )
583 colorblendPoints
= SAL_MAX_INT32
/sizeof(float);
584 if( sal_uInt32(colorblendPoints
)>SAL_MAX_INT32
/sizeof(::Color
) )
585 colorblendPoints
= sal_uInt32(SAL_MAX_INT32
)/sizeof(::Color
);
586 colorblendPositions
= new float [colorblendPoints
];
587 colorblendColors
= new ::Color
[colorblendPoints
];
588 for (int i
=0; i
< colorblendPoints
; i
++) {
589 s
>> colorblendPositions
[i
];
590 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i
<< "]: " << colorblendPositions
[i
]);
592 for (int i
=0; i
< colorblendPoints
; i
++) {
594 colorblendColors
[i
] = ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
595 SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
602 SAL_INFO("cppcanvas.emf", "EMF+\tunhandled brush type: " << std::hex
<< type
<< std::dec
);
607 /// Convert stroke caps between EMF+ and rendering API
608 sal_Int8
lcl_convertStrokeCap(sal_uInt32 nEmfStroke
)
612 case EmfPlusLineCapTypeSquare
: return rendering::PathCapType::SQUARE
;
613 case EmfPlusLineCapTypeRound
: return rendering::PathCapType::ROUND
;
616 // we have no mapping for EmfPlusLineCapTypeTriangle = 0x00000003,
617 // so return BUTT always
618 return rendering::PathCapType::BUTT
;
621 struct EMFPCustomLineCap
: public EMFPObject
624 sal_uInt32 strokeStartCap
, strokeEndCap
, strokeJoin
;
626 basegfx::B2DPolyPolygon polygon
;
630 EMFPCustomLineCap() : EMFPObject()
638 void SetAttributes(rendering::StrokeAttributes
& aAttributes
)
640 aAttributes
.StartCapType
= lcl_convertStrokeCap(strokeStartCap
);
641 aAttributes
.EndCapType
= lcl_convertStrokeCap(strokeEndCap
);
645 case EmfPlusLineJoinTypeMiter
: // fall-through
646 case EmfPlusLineJoinTypeMiterClipped
: aAttributes
.JoinType
= rendering::PathJoinType::MITER
; break;
647 case EmfPlusLineJoinTypeBevel
: aAttributes
.JoinType
= rendering::PathJoinType::BEVEL
; break;
648 case EmfPlusLineJoinTypeRound
: aAttributes
.JoinType
= rendering::PathJoinType::ROUND
; break;
651 aAttributes
.MiterLimit
= miterLimit
;
654 void ReadPath(SvStream
& s
, ImplRenderer
& rR
, bool bFill
)
656 sal_Int32 pathLength
;
658 SAL_INFO("cppcanvas.emf", "EMF+\t\tpath length: " << pathLength
);
660 sal_uInt32 pathHeader
;
661 sal_Int32 pathPoints
, pathFlags
;
662 s
>> pathHeader
>> pathPoints
>> pathFlags
;
664 SAL_INFO("cppcanvas.emf", "EMF+\t\tpath (custom cap line path)");
665 SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex
<< pathHeader
<< " points: " << std::dec
<< pathPoints
<< " additional flags: 0x" << std::hex
<< pathFlags
<< std::dec
);
667 EMFPPath
path(pathPoints
);
668 path
.Read(s
, pathFlags
, rR
);
670 polygon
= path
.GetPolygon(rR
, false);
673 // transformation to convert the path to what LibreOffice
675 B2DHomMatrix aMatrix
;
676 aMatrix
.scale(1.0, -1.0);
678 polygon
.transform(aMatrix
);
681 void Read (SvStream
& s
, ImplRenderer
& rR
)
687 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustom cap");
688 SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex
<< header
<< " type: " << type
<< std::dec
);
690 if (type
== EmfPlusCustomLineCapDataTypeDefault
)
692 sal_uInt32 customLineCapDataFlags
, baseCap
;
695 float fillHotSpotX
, fillHotSpotY
, strokeHotSpotX
, strokeHotSpotY
;
697 s
>> customLineCapDataFlags
>> baseCap
>> baseInset
698 >> strokeStartCap
>> strokeEndCap
>> strokeJoin
699 >> miterLimit
>> widthScale
700 >> fillHotSpotX
>> fillHotSpotY
>> strokeHotSpotX
>> strokeHotSpotY
;
702 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomLineCapDataFlags: 0x" << std::hex
<< customLineCapDataFlags
);
703 SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseCap: 0x" << std::hex
<< baseCap
);
704 SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseInset: " << baseInset
);
705 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeStartCap: 0x" << std::hex
<< strokeStartCap
);
706 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeEndCap: 0x" << std::hex
<< strokeEndCap
);
707 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeJoin: 0x" << std::hex
<< strokeJoin
);
708 SAL_INFO("cppcanvas.emf", "EMF+\t\tmiterLimit: " << miterLimit
);
709 SAL_INFO("cppcanvas.emf", "EMF+\t\twidthScale: " << widthScale
);
711 if (customLineCapDataFlags
& EmfPlusCustomLineCapDataFillPath
)
713 ReadPath(s
, rR
, true);
716 if (customLineCapDataFlags
& EmfPlusCustomLineCapDataLinePath
)
718 ReadPath(s
, rR
, false);
721 else if (type
== EmfPlusCustomLineCapDataTypeAdjustableArrow
)
723 // TODO only reads the data, does not use them [I've had
724 // no test document to be able to implement it]
726 sal_Int32 width
, height
, middleInset
, fillState
, lineStartCap
;
727 sal_Int32 lineEndCap
, lineJoin
, widthScale
;
728 float fillHotSpotX
, fillHotSpotY
, lineHotSpotX
, lineHotSpotY
;
730 s
>> width
>> height
>> middleInset
>> fillState
>> lineStartCap
731 >> lineEndCap
>> lineJoin
>> miterLimit
>> widthScale
732 >> fillHotSpotX
>> fillHotSpotY
>> lineHotSpotX
>> lineHotSpotY
;
734 SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - actually read EmfPlusCustomLineCapArrowData object (section 2.2.2.12)");
739 struct EMFPPen
: public EMFPBrush
741 XForm transformation
;
750 sal_Int32 dashPatternLen
;
753 sal_Int32 compoundArrayLen
;
754 float *compoundArray
;
755 sal_Int32 customStartCapLen
;
756 EMFPCustomLineCap
*customStartCap
;
757 sal_Int32 customEndCapLen
;
758 EMFPCustomLineCap
*customEndCap
;
761 EMFPPen () : EMFPBrush ()
764 compoundArray
= NULL
;
765 customStartCap
= NULL
;
771 delete[] dashPattern
;
772 delete[] compoundArray
;
773 delete customStartCap
;
777 void SetStrokeWidth(rendering::StrokeAttributes
& rStrokeAttributes
, ImplRenderer
& rR
, const OutDevState
& rState
)
779 #if OSL_DEBUG_LEVEL > 1
781 SAL_INFO ("cppcanvas.emf", "TODO: pen with zero width - using minimal which might not be correct\n");
784 rStrokeAttributes
.StrokeWidth
= fabs((rState
.mapModeTransform
* rR
.MapSize (width
== 0.0 ? 0.05 : width
, 0)).getX());
787 void SetStrokeDashing(rendering::StrokeAttributes
& rStrokeAttributes
)
789 if (dashStyle
!= EmfPlusLineStyleSolid
)
791 const float dash
[] = {3, 3};
792 const float dot
[] = {1, 3};
793 const float dashdot
[] = {3, 3, 1, 3};
794 const float dashdotdot
[] = {3, 3, 1, 3, 1, 3};
797 const float *pPattern
;
800 case EmfPlusLineStyleDash
: nLen
= SAL_N_ELEMENTS(dash
); pPattern
= dash
; break;
801 case EmfPlusLineStyleDot
: nLen
= SAL_N_ELEMENTS(dot
); pPattern
= dot
; break;
802 case EmfPlusLineStyleDashDot
: nLen
= SAL_N_ELEMENTS(dashdot
); pPattern
= dashdot
; break;
803 case EmfPlusLineStyleDashDotDot
: nLen
= SAL_N_ELEMENTS(dashdotdot
); pPattern
= dashdotdot
; break;
804 case EmfPlusLineStyleCustom
: nLen
= dashPatternLen
; pPattern
= dashPattern
; break;
808 uno::Sequence
<double> aDashArray(nLen
);
809 for (int i
= 0; i
< nLen
; ++i
)
810 aDashArray
[i
] = pPattern
[i
];
812 rStrokeAttributes
.DashArray
= aDashArray
;
817 void Read (SvStream
& s
, ImplRenderer
& rR
, sal_Int32
, sal_Int32
)
819 sal_uInt32 header
, unknown
, penFlags
, unknown2
;
822 s
>> header
>> unknown
>> penFlags
>> unknown2
>> width
;
824 SAL_INFO("cppcanvas.emf", "EMF+\tpen");
825 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " unknown: 0x" << unknown
<<
826 " additional flags: 0x" << penFlags
<< " unknown: 0x" << unknown2
<< " width: " << std::dec
<< width
);
834 SAL_INFO("cppcanvas.emf", "EMF+\t\tstartCap: 0x" << std::hex
<< startCap
);
842 SAL_INFO("cppcanvas.emf", "EMF+\t\tendCap: 0x" << std::hex
<< endCap
);
860 SAL_INFO("cppcanvas.emf", "EMF+\t\tdashStyle: 0x" << std::hex
<< dashStyle
);
877 dashStyle
= EmfPlusLineStyleCustom
;
880 SAL_INFO("cppcanvas.emf", "EMF+\t\tdashPatternLen: " << dashPatternLen
);
882 if( dashPatternLen
<0 || sal_uInt32(dashPatternLen
)>SAL_MAX_INT32
/sizeof(float) )
883 dashPatternLen
= SAL_MAX_INT32
/sizeof(float);
884 dashPattern
= new float [dashPatternLen
];
885 for (i
= 0; i
< dashPatternLen
; i
++)
887 s
>> dashPattern
[i
];
888 SAL_INFO("cppcanvas.emf", "EMF+\t\t\tdashPattern[" << i
<< "]: " << dashPattern
[i
]);
899 if (penFlags
& 1024) {
900 s
>> compoundArrayLen
;
901 if( compoundArrayLen
<0 || sal_uInt32(compoundArrayLen
)>SAL_MAX_INT32
/sizeof(float) )
902 compoundArrayLen
= SAL_MAX_INT32
/sizeof(float);
903 compoundArray
= new float [compoundArrayLen
];
904 for (i
= 0; i
< compoundArrayLen
; i
++)
905 s
>> compoundArray
[i
];
907 compoundArrayLen
= 0;
911 s
>> customStartCapLen
;
912 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomStartCapLen: " << customStartCapLen
);
913 sal_uInt32 pos
= s
.Tell();
915 customStartCap
= new EMFPCustomLineCap();
916 customStartCap
->Read(s
, rR
);
918 // maybe we don't read everything yet, play it safe ;-)
919 s
.Seek(pos
+ customStartCapLen
);
922 customStartCapLen
= 0;
926 s
>> customEndCapLen
;
927 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomEndCapLen: " << customEndCapLen
);
928 sal_uInt32 pos
= s
.Tell();
930 customEndCap
= new EMFPCustomLineCap();
931 customEndCap
->Read(s
, rR
);
933 // maybe we don't read everything yet, play it safe ;-)
934 s
.Seek(pos
+ customEndCapLen
);
939 EMFPBrush::Read (s
, rR
);
943 struct EMFPImage
: public EMFPObject
949 sal_Int32 pixelFormat
;
953 void Read (SvMemoryStream
&s
, sal_uInt32 dataSize
, sal_Bool bUseWholeStream
)
955 sal_uInt32 header
, unknown
;
959 SAL_INFO("cppcanvas.emf", "EMF+\timage\nEMF+\theader: 0x" << std::hex
<< header
<< " type: " << type
<< std::dec
);
961 if (type
== 1) { // bitmap
962 s
>> width
>> height
>> stride
>> pixelFormat
>> unknown
;
963 SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << width
<< " height: " << height
<< " stride: " << "pixelFormat: 0x" << std::hex
<< pixelFormat
<< std::dec
);
964 if (width
== 0) { // non native formats
965 GraphicFilter filter
;
967 filter
.ImportGraphic (graphic
, OUString(), s
);
968 SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << graphic
.GetBitmap().GetSizePixel().Width() << " height: " << graphic
.GetBitmap().GetSizePixel().Height());
971 } else if (type
== 2) {
972 sal_Int32 mfType
, mfSize
;
974 s
>> mfType
>> mfSize
;
975 SAL_INFO("cppcanvas.emf", "EMF+\tmetafile type: " << mfType
<< " dataSize: " << mfSize
<< " real size calculated from record dataSize: " << dataSize
- 16);
977 GraphicFilter filter
;
978 // workaround buggy metafiles, which have wrong mfSize set (n#705956 for example)
979 SvMemoryStream
mfStream (((char *)s
.GetData()) + s
.Tell(), bUseWholeStream
? s
.remainingSize() : dataSize
- 16, STREAM_READ
);
981 filter
.ImportGraphic (graphic
, OUString(), mfStream
);
983 // debug code - write the stream to debug file /tmp/emf-stream.emf
984 #if OSL_DEBUG_LEVEL > 1
986 static sal_Int32 emfp_debug_stream_number
= 0;
987 OUString emfp_debug_filename
= "/tmp/emf-embedded-stream" +
988 OUString::number(emfp_debug_stream_number
++) + ".emf";
990 SvFileStream
file( emfp_debug_filename
, STREAM_WRITE
| STREAM_TRUNC
);
1000 struct EMFPFont
: public EMFPObject
1004 sal_uInt32 sizeUnit
;
1005 sal_Int32 fontFlags
;
1008 void Read (SvMemoryStream
&s
)
1011 sal_uInt32 reserved
;
1014 s
>> header
>> emSize
>> sizeUnit
>> fontFlags
>> reserved
>> length
;
1016 OSL_ASSERT( ( header
>> 12 ) == 0xdbc01 );
1018 SAL_INFO("cppcanvas.emf", "EMF+\tfont\n"
1019 << "EMF+\theader: 0x" << std::hex
<< (header
>> 12) << " version: 0x" << (header
& 0x1fff) << " size: " << std::dec
<< emSize
<< " unit: 0x" << std::hex
<< sizeUnit
<< std::dec
);
1020 SAL_INFO("cppcanvas.emf", "EMF+\tflags: 0x" << std::hex
<< fontFlags
<< " reserved: 0x" << reserved
<< " length: 0x" << std::hex
<< length
<< std::dec
);
1022 if( length
> 0 && length
< 0x4000 ) {
1023 sal_Unicode
*chars
= (sal_Unicode
*) alloca( sizeof( sal_Unicode
) * length
);
1025 for( sal_uInt32 i
= 0; i
< length
; i
++ )
1028 family
= OUString( chars
, length
);
1029 SAL_INFO("cppcanvas.emf", "EMF+\tfamily: " << OUStringToOString( family
, RTL_TEXTENCODING_UTF8
).getStr()); // TODO: can we just use family?
1034 void ImplRenderer::ReadRectangle (SvStream
& s
, float& x
, float& y
, float &width
, float& height
, bool bCompressed
)
1037 sal_Int16 ix
, iy
, iw
, ih
;
1039 s
>> ix
>> iy
>> iw
>> ih
;
1046 s
>> x
>> y
>> width
>> height
;
1049 void ImplRenderer::ReadPoint (SvStream
& s
, float& x
, float& y
, sal_uInt32 flags
)
1051 if (flags
& 0x4000) {
1062 void ImplRenderer::MapToDevice (double& x
, double& y
)
1064 // TODO: other units
1065 x
= 100*nMmX
*x
/nPixX
;
1066 y
= 100*nMmY
*y
/nPixY
;
1069 ::basegfx::B2DPoint
ImplRenderer::Map (double ix
, double iy
)
1073 x
= ix
*aWorldTransform
.eM11
+ iy
*aWorldTransform
.eM21
+ aWorldTransform
.eDx
;
1074 y
= ix
*aWorldTransform
.eM12
+ iy
*aWorldTransform
.eM22
+ aWorldTransform
.eDy
;
1081 x
*= aBaseTransform
.eM11
;
1082 y
*= aBaseTransform
.eM22
;
1084 return ::basegfx::B2DPoint (x
, y
);
1087 ::basegfx::B2DSize
ImplRenderer::MapSize (double iwidth
, double iheight
)
1091 w
= iwidth
*aWorldTransform
.eM11
+ iheight
*aWorldTransform
.eM21
;
1092 h
= iwidth
*aWorldTransform
.eM12
+ iheight
*aWorldTransform
.eM22
;
1096 w
*= aBaseTransform
.eM11
;
1097 h
*= aBaseTransform
.eM22
;
1099 return ::basegfx::B2DSize (w
, h
);
1103 ::vcl::unotools::colorToDoubleSequence( ::Color (0xff - (x >> 24), \
1107 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
1109 void ImplRenderer::EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon
& polygon
, const ActionFactoryParameters
& rParms
,
1110 OutDevState
& rState
, const CanvasSharedPtr
& rCanvas
, bool isColor
, sal_uInt32 brushIndexOrColor
)
1112 ::basegfx::B2DPolyPolygon
localPolygon (polygon
);
1114 SAL_INFO("cppcanvas.emf", "EMF+\tfill polygon");
1116 localPolygon
.transform( rState
.mapModeTransform
);
1118 ActionSharedPtr pPolyAction
;
1121 SAL_INFO("cppcanvas.emf", "EMF+\t\tcolor fill:0x" << std::hex
<< brushIndexOrColor
<< std::dec
);
1122 rState
.isFillColorSet
= true;
1123 rState
.isLineColorSet
= false;
1125 rState
.fillColor
= COLOR(brushIndexOrColor
);
1127 pPolyAction
= ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon
, rParms
.mrCanvas
, rState
) );
1130 rState
.isFillColorSet
= true;
1132 EMFPBrush
* brush
= (EMFPBrush
*) aObjects
[brushIndexOrColor
& 0xff];
1133 SAL_INFO("cppcanvas.emf", "EMF+\tbrush fill slot: " << brushIndexOrColor
<< " (type: " << brush
->GetType () << ")");
1135 // give up in case something wrong happened
1139 rState
.isFillColorSet
= false;
1140 rState
.isLineColorSet
= false;
1142 if (brush
->type
== 3 || brush
->type
== 4) {
1144 if (brush
->type
== 3 && !(brush
->additionalFlags
& 0x1))
1145 return; // we are unable to parse these brushes yet
1147 ::basegfx::B2DHomMatrix aTextureTransformation
;
1148 ::basegfx::B2DHomMatrix aWorldTransformation
;
1149 ::basegfx::B2DHomMatrix aBaseTransformation
;
1150 rendering::Texture aTexture
;
1152 aWorldTransformation
.set (0, 0, aWorldTransform
.eM11
);
1153 aWorldTransformation
.set (0, 1, aWorldTransform
.eM21
);
1154 aWorldTransformation
.set (0, 2, aWorldTransform
.eDx
);
1155 aWorldTransformation
.set (1, 0, aWorldTransform
.eM12
);
1156 aWorldTransformation
.set (1, 1, aWorldTransform
.eM22
);
1157 aWorldTransformation
.set (1, 2, aWorldTransform
.eDy
);
1159 aBaseTransformation
.set (0, 0, aBaseTransform
.eM11
);
1160 aBaseTransformation
.set (0, 1, aBaseTransform
.eM21
);
1161 aBaseTransformation
.set (0, 2, aBaseTransform
.eDx
);
1162 aBaseTransformation
.set (1, 0, aBaseTransform
.eM12
);
1163 aBaseTransformation
.set (1, 1, aBaseTransform
.eM22
);
1164 aBaseTransformation
.set (1, 2, aBaseTransform
.eDy
);
1166 if (brush
->type
== 4) {
1167 aTextureTransformation
.scale (brush
->areaWidth
, brush
->areaHeight
);
1168 aTextureTransformation
.translate (brush
->areaX
, brush
->areaY
);
1170 aTextureTransformation
.translate (-0.5, -0.5);
1171 aTextureTransformation
.scale (brush
->areaWidth
, brush
->areaHeight
);
1172 aTextureTransformation
.translate (brush
->areaX
,brush
->areaY
);
1175 if (brush
->hasTransformation
) {
1176 ::basegfx::B2DHomMatrix aTransformation
;
1178 aTransformation
.set (0, 0, brush
->transformation
.eM11
);
1179 aTransformation
.set (0, 1, brush
->transformation
.eM21
);
1180 aTransformation
.set (0, 2, brush
->transformation
.eDx
);
1181 aTransformation
.set (1, 0, brush
->transformation
.eM12
);
1182 aTransformation
.set (1, 1, brush
->transformation
.eM22
);
1183 aTransformation
.set (1, 2, brush
->transformation
.eDy
);
1185 aTextureTransformation
*= aTransformation
;
1188 aTextureTransformation
*= aWorldTransformation
;
1189 aTextureTransformation
.scale (100.0*nMmX
/nPixX
, 100.0*nMmY
/nPixY
);
1190 aTextureTransformation
.translate (-nFrameLeft
, -nFrameTop
);
1191 aTextureTransformation
*= rState
.mapModeTransform
;
1192 aTextureTransformation
*= aBaseTransformation
;
1194 aTexture
.RepeatModeX
= rendering::TexturingMode::CLAMP
;
1195 aTexture
.RepeatModeY
= rendering::TexturingMode::CLAMP
;
1196 aTexture
.Alpha
= 1.0;
1198 basegfx::ODFGradientInfo aGradInfo
;
1199 OUString aGradientService
;
1201 const uno::Sequence
< double > aStartColor(
1202 ::vcl::unotools::colorToDoubleSequence( brush
->solidColor
,
1203 rParms
.mrCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
1204 const uno::Sequence
< double > aEndColor(
1205 ::vcl::unotools::colorToDoubleSequence( brush
->secondColor
,
1206 rParms
.mrCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
1207 uno::Sequence
< uno::Sequence
< double > > aColors (2);
1208 uno::Sequence
< double > aStops (2);
1210 if (brush
->blendPositions
) {
1211 SAL_INFO("cppcanvas.emf", "EMF+\t\tuse blend");
1212 aColors
.realloc (brush
->blendPoints
);
1213 aStops
.realloc (brush
->blendPoints
);
1214 int length
= aStartColor
.getLength ();
1215 uno::Sequence
< double > aColor (length
);
1217 OSL_ASSERT (length
== aEndColor
.getLength());
1219 for (int i
= 0; i
< brush
->blendPoints
; i
++) {
1220 aStops
[i
] = brush
->blendPositions
[i
];
1222 for (int j
= 0; j
< length
; j
++) {
1223 if (brush
->type
== 4) {
1224 aColor
[j
] = aStartColor
[j
]*(1 - brush
->blendFactors
[i
]) + aEndColor
[j
]*brush
->blendFactors
[i
];
1226 aColor
[j
] = aStartColor
[j
]*brush
->blendFactors
[i
] + aEndColor
[j
]*(1 - brush
->blendFactors
[i
]);
1229 aColors
[i
] = aColor
;
1231 } else if (brush
->colorblendPositions
) {
1232 SAL_INFO("cppcanvas.emf", "EMF+\t\tuse color blend");
1233 aColors
.realloc (brush
->colorblendPoints
);
1234 aStops
.realloc (brush
->colorblendPoints
);
1236 for (int i
= 0; i
< brush
->colorblendPoints
; i
++) {
1237 aStops
[i
] = brush
->colorblendPositions
[i
];
1238 aColors
[(brush
->type
== 4) ? i
: brush
->colorblendPoints
- 1 - i
] = ::vcl::unotools::colorToDoubleSequence( brush
->colorblendColors
[i
],
1239 rParms
.mrCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
1245 if (brush
->type
== 4) {
1246 aColors
[0] = aStartColor
;
1247 aColors
[1] = aEndColor
;
1249 aColors
[1] = aStartColor
;
1250 aColors
[0] = aEndColor
;
1254 SAL_INFO("cppcanvas.emf", "EMF+\t\tset gradient");
1255 basegfx::B2DRange
aBoundsRectangle (0, 0, 1, 1);
1256 if (brush
->type
== 4) {
1257 aGradientService
= "LinearGradient";
1258 aGradInfo
= basegfx::tools::createLinearODFGradientInfo(
1265 aGradientService
= "EllipticalGradient";
1266 aGradInfo
= basegfx::tools::createEllipticalODFGradientInfo(
1268 ::basegfx::B2DVector( 0, 0 ),
1274 uno::Reference
< lang::XMultiServiceFactory
> xFactory(
1275 rParms
.mrCanvas
->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
1277 if( xFactory
.is() ) {
1278 uno::Sequence
<uno::Any
> args( 3 );
1279 beans::PropertyValue aProp
;
1280 aProp
.Name
= "Colors";
1281 aProp
.Value
<<= aColors
;
1283 aProp
.Name
= "Stops";
1284 aProp
.Value
<<= aStops
;
1286 aProp
.Name
= "AspectRatio";
1287 aProp
.Value
<<= static_cast<sal_Int32
>(1);
1290 aTexture
.Gradient
.set(
1291 xFactory
->createInstanceWithArguments( aGradientService
,
1296 ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture
.AffineTransform
,
1297 aTextureTransformation
);
1299 if( aTexture
.Gradient
.is() )
1301 ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon
,
1310 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd poly action");
1312 maActions
.push_back(
1315 rParms
.mrCurrActionIndex
) );
1317 rParms
.mrCurrActionIndex
+= pPolyAction
->getActionCount()-1;
1321 double ImplRenderer::EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon
& rPolygon
, double fPolyLength
,
1322 const ::basegfx::B2DPolyPolygon
& rLineCap
, bool bIsFilled
, bool bStart
, const rendering::StrokeAttributes
& rAttributes
,
1323 const ActionFactoryParameters
& rParms
, OutDevState
& rState
)
1325 if (!rLineCap
.count())
1328 // it seems the line caps in EMF+ are 4*larger than what
1329 // LibreOffice expects, and the mapping in
1330 // createAreaGeometryForLineStartEnd scales that down, so
1332 // [unfortunately found no proof for this in the spec :-( - please
1333 // feel free to correct this if it causes trouble]
1334 double fWidth
= rAttributes
.StrokeWidth
*4;
1336 basegfx::B2DPolyPolygon
aArrow(basegfx::tools::createAreaGeometryForLineStartEnd(
1337 rPolygon
, rLineCap
, bStart
,
1338 fWidth
, fPolyLength
, 0, NULL
, rAttributes
.StrokeWidth
));
1340 // createAreaGeometryForLineStartEnd from some reason always sets
1341 // the path as closed, correct it
1342 aArrow
.setClosed(rLineCap
.isClosed());
1344 ActionSharedPtr
pAction(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow
, rParms
.mrCanvas
, rState
, rAttributes
));
1347 maActions
.push_back(MtfAction(pAction
, rParms
.mrCurrActionIndex
));
1348 rParms
.mrCurrActionIndex
+= pAction
->getActionCount()-1;
1353 bool bWasFillColorSet
= rState
.isFillColorSet
;
1354 rState
.isFillColorSet
= true;
1355 rState
.fillColor
= rState
.lineColor
;
1356 ActionSharedPtr
pAction2(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow
, rParms
.mrCanvas
, rState
));
1359 maActions
.push_back(MtfAction(pAction2
, rParms
.mrCurrActionIndex
));
1360 rParms
.mrCurrActionIndex
+= pAction2
->getActionCount()-1;
1362 rState
.isFillColorSet
= bWasFillColorSet
;
1365 return rAttributes
.StrokeWidth
;
1368 void ImplRenderer::EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon
& polygon
, const ActionFactoryParameters
& rParms
,
1369 OutDevState
& rState
, const CanvasSharedPtr
& rCanvas
, sal_uInt32 penIndex
)
1371 EMFPPen
* pen
= (EMFPPen
*) aObjects
[penIndex
& 0xff];
1373 SAL_WARN_IF( !pen
, "cppcanvas.emf", "emf+ missing pen" );
1377 rState
.isFillColorSet
= false;
1378 rState
.isLineColorSet
= true;
1379 rState
.lineColor
= ::vcl::unotools::colorToDoubleSequence (pen
->GetColor (),
1380 rCanvas
->getUNOCanvas ()->getDevice()->getDeviceColorSpace());
1382 basegfx::B2DPolyPolygon
aPolyPolygon(polygon
);
1383 aPolyPolygon
.transform(rState
.mapModeTransform
);
1384 rendering::StrokeAttributes aCommonAttributes
;
1386 // some attributes are common for the polygon, and the line
1387 // starts & ends - like the stroke width
1388 pen
->SetStrokeWidth(aCommonAttributes
, *this, rState
);
1390 // but eg. dashing has to be additionally set only on the
1392 rendering::StrokeAttributes
aPolygonAttributes(aCommonAttributes
);
1393 pen
->SetStrokeDashing(aPolygonAttributes
);
1395 basegfx::B2DPolyPolygon aFinalPolyPolygon
;
1397 // render line starts & ends if present
1398 if (!pen
->customStartCap
&& !pen
->customEndCap
)
1399 aFinalPolyPolygon
= aPolyPolygon
;
1402 for (sal_uInt32 i
= 0; i
< aPolyPolygon
.count(); ++i
)
1404 basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(i
));
1406 if (!aPolygon
.isClosed())
1408 double fStart
= 0.0;
1410 double fPolyLength
= basegfx::tools::getLength(aPolygon
);
1413 if (pen
->customStartCap
)
1415 rendering::StrokeAttributes
aAttributes(aCommonAttributes
);
1416 pen
->customStartCap
->SetAttributes(aAttributes
);
1418 fStart
= EMFPPlusDrawLineCap(aPolygon
, fPolyLength
, pen
->customStartCap
->polygon
,
1419 pen
->customStartCap
->mbIsFilled
,
1420 true, aAttributes
, rParms
, rState
);
1424 if (pen
->customEndCap
)
1426 rendering::StrokeAttributes
aAttributes(aCommonAttributes
);
1427 pen
->customEndCap
->SetAttributes(aAttributes
);
1429 fEnd
= EMFPPlusDrawLineCap(aPolygon
, fPolyLength
, pen
->customEndCap
->polygon
,
1430 pen
->customEndCap
->mbIsFilled
,
1431 false, aAttributes
, rParms
, rState
);
1434 // build new poly, consume something from the old poly
1435 if (fStart
!= 0.0 || fEnd
!= 0.0)
1436 aPolygon
= basegfx::tools::getSnippetAbsolute(aPolygon
, fStart
, fPolyLength
- fEnd
, fPolyLength
);
1439 aFinalPolyPolygon
.append(aPolygon
);
1443 // finally render the polygon
1444 ActionSharedPtr
pPolyAction(internal::PolyPolyActionFactory::createPolyPolyAction(aFinalPolyPolygon
, rParms
.mrCanvas
, rState
, aPolygonAttributes
));
1447 maActions
.push_back(MtfAction(pPolyAction
, rParms
.mrCurrActionIndex
));
1448 rParms
.mrCurrActionIndex
+= pPolyAction
->getActionCount()-1;
1453 void ImplRenderer::processObjectRecord(SvMemoryStream
& rObjectStream
, sal_uInt16 flags
, sal_uInt32 dataSize
, sal_Bool bUseWholeStream
)
1457 SAL_INFO("cppcanvas.emf", "EMF+ Object slot: " << (flags
& 0xff) << " flags: " << (flags
& 0xff00));
1459 index
= flags
& 0xff;
1460 if (aObjects
[index
] != NULL
) {
1461 delete aObjects
[index
];
1462 aObjects
[index
] = NULL
;
1465 switch (flags
& 0x7f00) {
1466 case EmfPlusObjectTypeBrush
:
1469 aObjects
[index
] = brush
= new EMFPBrush ();
1470 brush
->Read (rObjectStream
, *this);
1474 case EmfPlusObjectTypePen
:
1477 aObjects
[index
] = pen
= new EMFPPen ();
1478 pen
->Read (rObjectStream
, *this, nHDPI
, nVDPI
);
1482 case EmfPlusObjectTypePath
:
1483 sal_uInt32 header
, pathFlags
;
1486 rObjectStream
>> header
>> points
>> pathFlags
;
1488 SAL_INFO("cppcanvas.emf", "EMF+\tpath");
1489 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " points: " << std::dec
<< points
<< " additional flags: 0x" << std::hex
<< pathFlags
<< std::dec
);
1492 aObjects
[index
] = path
= new EMFPPath (points
);
1493 path
->Read (rObjectStream
, pathFlags
, *this);
1496 case EmfPlusObjectTypeRegion
: {
1499 aObjects
[index
] = region
= new EMFPRegion ();
1500 region
->Read (rObjectStream
);
1504 case EmfPlusObjectTypeImage
:
1507 aObjects
[index
] = image
= new EMFPImage ();
1508 image
->Read (rObjectStream
, dataSize
, bUseWholeStream
);
1512 case EmfPlusObjectTypeFont
:
1515 aObjects
[index
] = font
= new EMFPFont ();
1516 font
->Read (rObjectStream
);
1521 SAL_INFO("cppcanvas.emf", "EMF+\tObject unhandled flags: 0x" << std::hex
<< (flags
& 0xff00) << std::dec
);
1526 double ImplRenderer::setFont (sal_uInt8 objectId
, const ActionFactoryParameters
& rParms
, OutDevState
& rState
)
1528 EMFPFont
*font
= (EMFPFont
*) aObjects
[ objectId
];
1530 rendering::FontRequest aFontRequest
;
1531 aFontRequest
.FontDescription
.FamilyName
= font
->family
;
1532 double cellSize
= font
->emSize
;
1533 aFontRequest
.CellSize
= (rState
.mapModeTransform
*MapSize( cellSize
, 0 )).getX();
1534 rState
.xFont
= rParms
.mrCanvas
->getUNOCanvas()->createFont( aFontRequest
,
1535 uno::Sequence
< beans::PropertyValue
>(),
1536 geometry::Matrix2D() );
1541 void ImplRenderer::GraphicStatePush(GraphicStateMap
& map
, sal_Int32 index
, OutDevState
& rState
)
1543 GraphicStateMap::iterator iter
= map
.find( index
);
1545 if ( iter
!= map
.end() )
1547 EmfPlusGraphicState state
= iter
->second
;
1550 SAL_INFO("cppcanvas.emf", "stack index: " << index
<< " found and erased");
1553 EmfPlusGraphicState state
;
1555 state
.aWorldTransform
= aWorldTransform
;
1556 state
.aDevState
= rState
;
1558 map
[ index
] = state
;
1561 void ImplRenderer::GraphicStatePop(GraphicStateMap
& map
, sal_Int32 index
, OutDevState
& rState
)
1563 GraphicStateMap::iterator iter
= map
.find( index
);
1565 if ( iter
!= map
.end() )
1567 SAL_INFO("cppcanvas.emf", "stack index: " << index
<< " found");
1569 EmfPlusGraphicState state
= iter
->second
;
1571 aWorldTransform
= state
.aWorldTransform
;
1572 rState
.clip
= state
.aDevState
.clip
;
1573 rState
.clipRect
= state
.aDevState
.clipRect
;
1574 rState
.xClipPoly
= state
.aDevState
.xClipPoly
;
1578 void ImplRenderer::processEMFPlus( MetaCommentAction
* pAct
, const ActionFactoryParameters
& rFactoryParms
,
1579 OutDevState
& rState
, const CanvasSharedPtr
& rCanvas
)
1581 sal_uInt32 length
= pAct
->GetDataSize ();
1582 SvMemoryStream
rMF ((void*) pAct
->GetData (), length
, STREAM_READ
);
1584 #if OSL_DEBUG_LEVEL > 2
1585 SAL_INFO("cppcanvas.emf", "EMF+\tDump of EMF+ record");
1586 dumpWords(rMF
, length
);
1590 while (length
> 0) {
1591 sal_uInt16 type
, flags
;
1592 sal_uInt32 size
, dataSize
;
1595 rMF
>> type
>> flags
>> size
>> dataSize
;
1597 next
= rMF
.Tell() + ( size
- 12 );
1600 SAL_INFO("cppcanvas.emf", "Size field is less than 12 bytes");
1603 SAL_INFO("cppcanvas.emf", "EMF+ record size: " << size
<< " type: " << type
<< " flags: " << flags
<< " data size: " << dataSize
);
1605 if (type
== EmfPlusRecordTypeObject
&& ((mbMultipart
&& (flags
& 0x7fff) == (mMFlags
& 0x7fff)) || (flags
& 0x8000))) {
1612 // 1st 4 bytes are unknown
1613 mMStream
.Write (((const char *)rMF
.GetData()) + rMF
.Tell() + 4, dataSize
- 4);
1614 SAL_INFO("cppcanvas.emf", "EMF+ read next object part size: " << size
<< " type: " << type
<< " flags: " << flags
<< " data size: " << dataSize
);
1617 SAL_INFO("cppcanvas.emf", "EMF+ multipart record flags: " << mMFlags
);
1619 processObjectRecord (mMStream
, mMFlags
, dataSize
, sal_True
);
1621 mbMultipart
= false;
1624 if (type
!= EmfPlusRecordTypeObject
|| !(flags
& 0x8000))
1627 case EmfPlusRecordTypeHeader
:
1628 sal_uInt32 header
, version
;
1630 rMF
>> header
>> version
>> nHDPI
>> nVDPI
;
1632 SAL_INFO("cppcanvas.emf", "EMF+ Header");
1633 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " version: " << std::dec
<< version
<< " horizontal DPI: " << nHDPI
<< " vertical DPI: " << nVDPI
<< " dual: " << (flags
& 1));
1636 case EmfPlusRecordTypeEndOfFile
:
1637 SAL_INFO("cppcanvas.emf", "EMF+ EndOfFile");
1639 case EmfPlusRecordTypeGetDC
:
1640 SAL_INFO("cppcanvas.emf", "EMF+ GetDC");
1641 SAL_INFO("cppcanvas.emf", "EMF+\talready used in svtools wmf/emf filter parser");
1643 case EmfPlusRecordTypeObject
:
1644 processObjectRecord (rMF
, flags
, dataSize
);
1646 case EmfPlusRecordTypeFillPie
:
1648 sal_uInt32 brushIndexOrColor
;
1649 float startAngle
, sweepAngle
;
1651 rMF
>> brushIndexOrColor
>> startAngle
>> sweepAngle
;
1653 SAL_INFO("cppcanvas.emf", "EMF+ FillPie colorOrIndex: " << brushIndexOrColor
<< " startAngle: " << startAngle
<< " sweepAngle: " << sweepAngle
);
1655 float dx
, dy
, dw
, dh
;
1657 ReadRectangle (rMF
, dx
, dy
, dw
, dh
, flags
& 0x4000);
1659 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx
<< "," << dy
<< " " << dw
<< "x" << dh
);
1661 startAngle
= 2*M_PI
*startAngle
/360;
1662 sweepAngle
= 2*M_PI
*sweepAngle
/360;
1664 B2DPoint
mappedCenter (Map (dx
+ dw
/2, dy
+ dh
/2));
1665 B2DSize
mappedSize( MapSize (dw
/2, dh
/2));
1667 float endAngle
= startAngle
+ sweepAngle
;
1668 startAngle
= fmodf(startAngle
, static_cast<float>(M_PI
*2));
1670 startAngle
+= static_cast<float>(M_PI
*2);
1671 endAngle
= fmodf(endAngle
, static_cast<float>(M_PI
*2));
1673 endAngle
+= static_cast<float>(M_PI
*2);
1676 std::swap (endAngle
, startAngle
);
1678 SAL_INFO("cppcanvas.emf", "EMF+ adjusted angles: start " <<
1679 (360.0*startAngle
/M_PI
) << ", end: " << (360.0*endAngle
/M_PI
));
1681 B2DPolygon polygon
= tools::createPolygonFromEllipseSegment (mappedCenter
, mappedSize
.getX (), mappedSize
.getY (), startAngle
, endAngle
);
1682 polygon
.append (mappedCenter
);
1683 polygon
.setClosed (true);
1685 B2DPolyPolygon
polyPolygon (polygon
);
1686 EMFPPlusFillPolygon (polyPolygon
, rFactoryParms
, rState
, rCanvas
, flags
& 0x8000, brushIndexOrColor
);
1689 case EmfPlusRecordTypeFillPath
:
1691 sal_uInt32 index
= flags
& 0xff;
1692 sal_uInt32 brushIndexOrColor
;
1694 rMF
>> brushIndexOrColor
;
1696 SAL_INFO("cppcanvas.emf", "EMF+ FillPath slot: " << index
);
1698 EMFPPlusFillPolygon (((EMFPPath
*) aObjects
[index
])->GetPolygon (*this), rFactoryParms
, rState
, rCanvas
, flags
& 0x8000, brushIndexOrColor
);
1701 case EmfPlusRecordTypeDrawEllipse
:
1702 case EmfPlusRecordTypeFillEllipse
:
1704 // Intentionally very bogus initial value to avoid MSVC complaining about potentially uninitialized local
1705 // variable. As long as the code stays as intended, this variable will be assigned a (real) value in the case
1706 // when it is later used.
1707 sal_uInt32 brushIndexOrColor
= 1234567;
1709 if ( type
== EmfPlusRecordTypeFillEllipse
)
1710 rMF
>> brushIndexOrColor
;
1712 SAL_INFO("cppcanvas.emf", "EMF+ " << (type
== EmfPlusRecordTypeFillEllipse
? "Fill" : "Draw") << "Ellipse slot: " << (flags
& 0xff));
1714 float dx
, dy
, dw
, dh
;
1716 ReadRectangle (rMF
, dx
, dy
, dw
, dh
, flags
& 0x4000);
1718 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx
<< "," << dy
<< " " << dw
<< "x" << dh
);
1720 B2DPoint
mappedCenter (Map (dx
+ dw
/2, dy
+ dh
/2));
1721 B2DSize
mappedSize( MapSize (dw
/2, dh
/2));
1723 ::basegfx::B2DPolyPolygon
polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromEllipse( mappedCenter
, mappedSize
.getX (), mappedSize
.getY () ) ) );
1725 if ( type
== EmfPlusRecordTypeFillEllipse
)
1726 EMFPPlusFillPolygon( polyPolygon
,
1727 rFactoryParms
, rState
, rCanvas
, flags
& 0x8000, brushIndexOrColor
);
1729 EMFPPlusDrawPolygon( polyPolygon
,
1730 rFactoryParms
, rState
, rCanvas
, flags
& 0xff );
1733 case EmfPlusRecordTypeFillRects
:
1735 SAL_INFO("cppcanvas.emf", "EMF+ FillRects");
1737 sal_uInt32 brushIndexOrColor
;
1738 sal_Int32 rectangles
;
1739 bool isColor
= (flags
& 0x8000);
1740 ::basegfx::B2DPolygon polygon
;
1742 rMF
>> brushIndexOrColor
>> rectangles
;
1744 SAL_INFO("cppcanvas.emf", "EMF+\t" << ((flags
& 0x8000) ? "color" : "brush index") << ": 0x" << std::hex
<< brushIndexOrColor
<< std::dec
);
1746 for (int i
=0; i
< rectangles
; i
++) {
1747 if (flags
& 0x4000) {
1748 /* 16bit integers */
1749 sal_Int16 x
, y
, width
, height
;
1751 rMF
>> x
>> y
>> width
>> height
;
1753 polygon
.append (Map (x
, y
));
1754 polygon
.append (Map (x
+ width
, y
));
1755 polygon
.append (Map (x
+ width
, y
+ height
));
1756 polygon
.append (Map (x
, y
+ height
));
1758 SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x
<< "," << " " << width
<< "x" << height
);
1761 float x
, y
, width
, height
;
1763 rMF
>> x
>> y
>> width
>> height
;
1765 polygon
.append (Map (x
, y
));
1766 polygon
.append (Map (x
+ width
, y
));
1767 polygon
.append (Map (x
+ width
, y
+ height
));
1768 polygon
.append (Map (x
, y
+ height
));
1770 SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x
<< "," << " " << width
<< "x" << height
);
1773 ::basegfx::B2DPolyPolygon
polyPolygon (polygon
);
1775 EMFPPlusFillPolygon (polyPolygon
, rFactoryParms
, rState
, rCanvas
, isColor
, brushIndexOrColor
);
1779 case EmfPlusRecordTypeFillPolygon
:
1781 sal_uInt8 index
= flags
& 0xff;
1782 sal_uInt32 brushIndexOrColor
;
1785 rMF
>> brushIndexOrColor
;
1788 SAL_INFO("cppcanvas.emf", "EMF+ FillPolygon in slot: " << +index
<< " points: " << points
);
1789 SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags
& 0x8000) ? "color" : "brush index") << " 0x" << std::hex
<< brushIndexOrColor
<< std::dec
);
1791 EMFPPath
path (points
, true);
1792 path
.Read (rMF
, flags
, *this);
1794 EMFPPlusFillPolygon (path
.GetPolygon (*this), rFactoryParms
, rState
, rCanvas
, flags
& 0x8000, brushIndexOrColor
);
1798 case EmfPlusRecordTypeDrawLines
:
1804 SAL_INFO("cppcanvas.emf", "EMF+ DrawLines in slot: " << (flags
&& 0xff) << " points: " << points
);
1806 EMFPPath
path (points
, true);
1807 path
.Read (rMF
, flags
, *this);
1809 EMFPPlusDrawPolygon (path
.GetPolygon (*this), rFactoryParms
, rState
, rCanvas
, flags
);
1813 case EmfPlusRecordTypeDrawPath
:
1815 sal_uInt32 penIndex
;
1819 SAL_INFO("cppcanvas.emf", "EMF+ DrawPath");
1820 SAL_INFO("cppcanvas.emf", "EMF+\tpen: " << penIndex
);
1822 EMFPPath
* path
= (EMFPPath
*) aObjects
[flags
& 0xff];
1823 SAL_WARN_IF( !path
, "cppcanvas.emf", "EmfPlusRecordTypeDrawPath missing path" );
1825 EMFPPlusDrawPolygon (path
->GetPolygon (*this), rFactoryParms
, rState
, rCanvas
, penIndex
);
1829 case EmfPlusRecordTypeDrawImage
:
1830 case EmfPlusRecordTypeDrawImagePoints
:
1832 sal_uInt32 attrIndex
;
1833 sal_Int32 sourceUnit
;
1835 rMF
>> attrIndex
>> sourceUnit
;
1837 SAL_INFO("cppcanvas.emf", "EMF+ " << (type
== EmfPlusRecordTypeDrawImagePoints
? "DrawImagePoints" : "DrawImage") << "attributes index: " << attrIndex
<< "source unit: " << sourceUnit
);
1838 SAL_INFO("cppcanvas.emf", "EMF+\tTODO: use image attributes");
1840 if (sourceUnit
== 2 && aObjects
[flags
& 0xff]) { // we handle only GraphicsUnit.Pixel now
1841 EMFPImage
& image
= *(EMFPImage
*) aObjects
[flags
& 0xff];
1842 float sx
, sy
, sw
, sh
;
1845 ReadRectangle (rMF
, sx
, sy
, sw
, sh
);
1846 Rectangle
aSource(Point(sx
, sy
), Size(sw
, sh
));
1848 SAL_INFO("cppcanvas.emf", "EMF+ " << (type
== EmfPlusRecordTypeDrawImagePoints
? "DrawImagePoints" : "DrawImage") << " source rectangle: " << sx
<< "," << sy
<< " " << sw
<< "x" << sh
);
1850 ::basegfx::B2DPoint aDstPoint
;
1851 ::basegfx::B2DSize aDstSize
;
1852 bool bValid
= false;
1854 if (type
== EmfPlusRecordTypeDrawImagePoints
) {
1857 if( aCount
== 3) { // TODO: now that we now that this value is count we should support it better
1858 float x1
, y1
, x2
, y2
, x3
, y3
;
1860 ReadPoint (rMF
, x1
, y1
, flags
);
1861 ReadPoint (rMF
, x2
, y2
, flags
);
1862 ReadPoint (rMF
, x3
, y3
, flags
);
1864 SAL_INFO("cppcanvas.emf", "EMF+ destination points: " << x1
<< "," << y1
<< " " << x2
<< "," << y2
<< " " << x3
<< "," << y3
);
1865 SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << x1
<< "," << y1
<< " " << x2
- x1
<< "x" << y3
- y1
);
1867 aDstPoint
= Map (x1
, y1
);
1868 aDstSize
= MapSize(x2
- x1
, y3
- y1
);
1872 } else if (type
== EmfPlusRecordTypeDrawImage
) {
1873 float dx
, dy
, dw
, dh
;
1875 ReadRectangle (rMF
, dx
, dy
, dw
, dh
, flags
& 0x4000);
1877 SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << dx
<< "," << dy
<< " " << dw
<< "x" << dh
);
1879 aDstPoint
= Map (dx
, dy
);
1880 aDstSize
= MapSize(dw
, dh
);
1886 BitmapEx
aBmp( image
.graphic
.GetBitmapEx () );
1887 aBmp
.Crop( aSource
);
1889 Size
aSize( aBmp
.GetSizePixel() );
1890 SAL_INFO("cppcanvas.emf", "EMF+ bitmap size: " << aSize
.Width() << "x" << aSize
.Height());
1891 if( aSize
.Width() > 0 && aSize
.Height() > 0 ) {
1892 ActionSharedPtr
pBmpAction (
1893 internal::BitmapActionFactory::createBitmapAction (
1895 rState
.mapModeTransform
* aDstPoint
,
1896 rState
.mapModeTransform
* aDstSize
,
1901 maActions
.push_back( MtfAction( pBmpAction
,
1902 rFactoryParms
.mrCurrActionIndex
) );
1904 rFactoryParms
.mrCurrActionIndex
+= pBmpAction
->getActionCount()-1;
1907 SAL_INFO("cppcanvas.emf", "EMF+ warning: empty bitmap");
1910 SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme)");
1913 SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme) - possibly unsupported source units for crop rectangle");
1917 case EmfPlusRecordTypeDrawString
:
1919 SAL_INFO("cppcanvas.emf", "EMF+ DrawString");
1922 sal_uInt32 formatId
;
1923 sal_uInt32 stringLength
;
1925 rMF
>> brushId
>> formatId
>> stringLength
;
1926 SAL_INFO("cppcanvas.emf", "EMF+ DrawString brushId: " << brushId
<< " formatId: " << formatId
<< " length: " << stringLength
);
1928 if (flags
& 0x8000) {
1929 float lx
, ly
, lw
, lh
;
1931 rMF
>> lx
>> ly
>> lw
>> lh
;
1933 SAL_INFO("cppcanvas.emf", "EMF+ DrawString layoutRect: " << lx
<< "," << ly
<< " - " << lw
<< "x" << lh
);
1935 OUString text
= read_uInt16s_ToOUString(rMF
, stringLength
);
1937 double cellSize
= setFont (flags
& 0xff, rFactoryParms
, rState
);
1938 rState
.textColor
= COLOR( brushId
);
1940 ::basegfx::B2DPoint
point( Map( lx
+ 0.15*cellSize
, ly
+ cellSize
) );
1942 ActionSharedPtr
pTextAction(
1943 TextActionFactory::createTextAction(
1944 // position is just rough guess for now
1945 // we should calculate it exactly from layoutRect or font
1946 ::vcl::unotools::pointFromB2DPoint ( point
),
1955 rFactoryParms
.mrVDev
,
1956 rFactoryParms
.mrCanvas
,
1958 rFactoryParms
.mrParms
,
1962 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
1964 maActions
.push_back(
1967 rFactoryParms
.mrCurrActionIndex
) );
1969 rFactoryParms
.mrCurrActionIndex
+= pTextAction
->getActionCount()-1;
1972 SAL_INFO("cppcanvas.emf", "EMF+ DrawString TODO - drawing with brush not yet supported");
1976 case EmfPlusRecordTypeSetPageTransform
:
1979 SAL_INFO("cppcanvas.emf", "EMF+ SetPageTransform");
1980 SAL_INFO("cppcanvas.emf", "EMF+\tscale: " << fPageScale
<< " unit: " << flags
);
1981 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1983 case EmfPlusRecordTypeSetRenderingOrigin
:
1984 rMF
>> nOriginX
>> nOriginY
;
1985 SAL_INFO("cppcanvas.emf", "EMF+ SetRenderingOrigin");
1986 SAL_INFO("cppcanvas.emf", "EMF+\torigin [x,y]: " << nOriginX
<< "," << nOriginY
);
1988 case EmfPlusRecordTypeSetTextRenderingHint
:
1989 SAL_INFO("cppcanvas.emf", "EMF+ SetTextRenderingHint");
1990 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1992 case EmfPlusRecordTypeSetAntiAliasMode
:
1993 SAL_INFO("cppcanvas.emf", "EMF+ SetAntiAliasMode");
1994 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
1996 case EmfPlusRecordTypeSetInterpolationMode
:
1997 SAL_INFO("cppcanvas.emf", "EMF+ InterpolationMode");
1998 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2000 case EmfPlusRecordTypeSetPixelOffsetMode
:
2001 SAL_INFO("cppcanvas.emf", "EMF+ SetPixelOffsetMode");
2002 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2004 case EmfPlusRecordTypeSetCompositingQuality
:
2005 SAL_INFO("cppcanvas.emf", "EMF+ SetCompositingQuality");
2006 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2008 case EmfPlusRecordTypeSave
:
2010 sal_uInt32 stackIndex
;
2014 SAL_INFO("cppcanvas.emf", "EMF+ Save stack index: " << stackIndex
);
2016 GraphicStatePush( mGSStack
, stackIndex
, rState
);
2020 case EmfPlusRecordTypeRestore
:
2022 sal_uInt32 stackIndex
;
2026 SAL_INFO("cppcanvas.emf", "EMF+ Restore stack index: " << stackIndex
);
2028 GraphicStatePop( mGSStack
, stackIndex
, rState
);
2032 case EmfPlusRecordTypeBeginContainerNoParams
:
2034 sal_uInt32 stackIndex
;
2038 SAL_INFO("cppcanvas.emf", "EMF+ Begin Container No Params stack index: " << stackIndex
);
2040 GraphicStatePush( mGSContainerStack
, stackIndex
, rState
);
2043 case EmfPlusRecordTypeEndContainer
:
2045 sal_uInt32 stackIndex
;
2049 SAL_INFO("cppcanvas.emf", "EMF+ End Container stack index: " << stackIndex
);
2051 GraphicStatePop( mGSContainerStack
, stackIndex
, rState
);
2054 case EmfPlusRecordTypeSetWorldTransform
: {
2055 SAL_INFO("cppcanvas.emf", "EMF+ SetWorldTransform");
2058 aWorldTransform
.Set (transform
);
2059 SAL_INFO("cppcanvas.emf",
2060 "EMF+\tm11: " << aWorldTransform
.eM11
<< "\tm12: " << aWorldTransform
.eM12
<<
2061 "\tm21: " << aWorldTransform
.eM21
<< "\tm22: " << aWorldTransform
.eM22
<<
2062 "\tdx: " << aWorldTransform
.eDx
<< "\tdy: " << aWorldTransform
.eDy
);
2065 case EmfPlusRecordTypeResetWorldTransform
:
2066 SAL_INFO("cppcanvas.emf", "EMF+ ResetWorldTransform");
2067 aWorldTransform
.SetIdentity ();
2069 case EmfPlusRecordTypeMultiplyWorldTransform
: {
2070 SAL_INFO("cppcanvas.emf", "EMF+ MultiplyWorldTransform");
2074 SAL_INFO("cppcanvas.emf",
2075 "EMF+\tmatrix m11: " << transform
.eM11
<< "m12: " << transform
.eM12
<<
2076 "EMF+\tm21: " << transform
.eM21
<< "m22: " << transform
.eM22
<<
2077 "EMF+\tdx: " << transform
.eDx
<< "dy: " << transform
.eDy
);
2079 if (flags
& 0x2000) // post multiply
2080 aWorldTransform
.Multiply (transform
);
2081 else { // pre multiply
2082 transform
.Multiply (aWorldTransform
);
2083 aWorldTransform
.Set (transform
);
2085 SAL_INFO("cppcanvas.emf",
2086 "EMF+\tm11: " << aWorldTransform
.eM11
<< "m12: " << aWorldTransform
.eM12
<<
2087 "EMF+\tm21: " << aWorldTransform
.eM21
<< "m22: " << aWorldTransform
.eM22
<<
2088 "EMF+\tdx: " << aWorldTransform
.eDx
<< "dy: " << aWorldTransform
.eDy
);
2091 case EmfPlusRecordTypeSetClipRect
:
2093 int combineMode
= (flags
>> 8) & 0xf;
2095 SAL_INFO("cppcanvas.emf", "EMF+ SetClipRect combine mode: " << combineMode
);
2096 #if OSL_DEBUG_LEVEL > 1
2097 if (combineMode
> 1) {
2098 SAL_INFO ("cppcanvas.emf", "EMF+ TODO combine mode > 1");
2102 float dx
, dy
, dw
, dh
;
2104 ReadRectangle (rMF
, dx
, dy
, dw
, dh
, false);
2106 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx
<< "," << dy
<< " " << dw
<< "x" << dh
);
2108 B2DPoint
mappedPoint (Map (dx
, dy
));
2109 B2DSize
mappedSize( MapSize (dw
, dh
));
2111 ::basegfx::B2DPolyPolygon
polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromRect( ::basegfx::B2DRectangle( mappedPoint
.getX(), mappedPoint
.getY(),
2112 mappedPoint
.getX() + mappedSize
.getX(),
2113 mappedPoint
.getY() + mappedSize
.getY() ) ) ) );
2114 polyPolygon
.transform(rState
.mapModeTransform
);
2116 updateClipping (polyPolygon
, rFactoryParms
, combineMode
== 1);
2120 case EmfPlusRecordTypeSetClipPath
:
2122 int combineMode
= (flags
>> 8) & 0xf;
2124 SAL_INFO("cppcanvas.emf", "EMF+ SetClipPath combine mode: " << combineMode
);
2125 SAL_INFO("cppcanvas.emf", "EMF+\tpath in slot: " << (flags
& 0xff));
2127 EMFPPath
& path
= *(EMFPPath
*) aObjects
[flags
& 0xff];
2128 ::basegfx::B2DPolyPolygon
& clipPoly (path
.GetPolygon (*this));
2130 clipPoly
.transform (rState
.mapModeTransform
);
2131 updateClipping (clipPoly
, rFactoryParms
, combineMode
== 1);
2135 case EmfPlusRecordTypeSetClipRegion
: {
2136 int combineMode
= (flags
>> 8) & 0xf;
2138 SAL_INFO("cppcanvas.emf", "EMF+ SetClipRegion");
2139 SAL_INFO("cppcanvas.emf", "EMF+\tregion in slot: " << (flags
& 0xff) << " combine mode: " << combineMode
);
2140 EMFPRegion
*region
= (EMFPRegion
*)aObjects
[flags
& 0xff];
2143 if (region
&& region
->parts
== 0 && region
->initialState
== EmfPlusRegionInitialStateInfinite
) {
2144 updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms
, combineMode
== 1);
2146 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2150 case EmfPlusRecordTypeDrawDriverString
: {
2151 SAL_INFO("cppcanvas.emf", "EMF+ DrawDriverString, flags: 0x" << std::hex
<< flags
<< std::dec
);
2152 sal_uInt32 brushIndexOrColor
;
2153 sal_uInt32 optionFlags
;
2154 sal_uInt32 hasMatrix
;
2155 sal_uInt32 glyphsCount
;
2157 rMF
>> brushIndexOrColor
>> optionFlags
>> hasMatrix
>> glyphsCount
;
2159 SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags
& 0x8000) ? "color" : "brush index") << " 0x" << std::hex
<< brushIndexOrColor
<< std::dec
);
2160 SAL_INFO("cppcanvas.emf", "EMF+\toption flags: 0x" << std::hex
<< optionFlags
<< std::dec
);
2161 SAL_INFO("cppcanvas.emf", "EMF+\thas matrix: " << hasMatrix
);
2162 SAL_INFO("cppcanvas.emf", "EMF+\tglyphs: " << glyphsCount
);
2164 if( ( optionFlags
& 1 ) && glyphsCount
> 0 ) {
2165 float *charsPosX
= new float[glyphsCount
];
2166 float *charsPosY
= new float[glyphsCount
];
2168 OUString text
= read_uInt16s_ToOUString(rMF
, glyphsCount
);
2170 for( sal_uInt32 i
=0; i
<glyphsCount
; i
++) {
2171 rMF
>> charsPosX
[i
] >> charsPosY
[i
];
2172 SAL_INFO("cppcanvas.emf", "EMF+\tglyphPosition[" << i
<< "]: " << charsPosX
[i
] << "," << charsPosY
[i
]);
2178 SAL_INFO("cppcanvas.emf", "EMF+\tmatrix: " << transform
.eM11
<< ", " << transform
.eM12
<< ", " << transform
.eM21
<< ", " << transform
.eM22
<< ", " << transform
.eDx
<< ", " << transform
.eDy
);
2181 // add the text action
2182 setFont (flags
& 0xff, rFactoryParms
, rState
);
2184 if( flags
& 0x8000 )
2185 rState
.textColor
= COLOR( brushIndexOrColor
);
2187 ::basegfx::B2DPoint
point( Map( charsPosX
[0], charsPosY
[0] ) );
2189 ActionSharedPtr
pTextAction(
2190 TextActionFactory::createTextAction(
2191 ::vcl::unotools::pointFromB2DPoint ( point
),
2200 rFactoryParms
.mrVDev
,
2201 rFactoryParms
.mrCanvas
,
2203 rFactoryParms
.mrParms
,
2208 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
2210 maActions
.push_back(
2213 rFactoryParms
.mrCurrActionIndex
) );
2215 rFactoryParms
.mrCurrActionIndex
+= pTextAction
->getActionCount()-1;
2221 SAL_INFO("cppcanvas.emf", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
2227 SAL_INFO("cppcanvas.emf", "EMF+ unhandled record type: " << type
);
2228 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2240 SAL_WARN("cppcanvas.emf", "ImplRenderer::processEMFPlus: "
2241 "size " << size
<< " > length " << length
);
2242 #if OSL_DEBUG_LEVEL > 1
2243 dumpWords(rMF
, length
);
2252 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */