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>
39 #include <com/sun/star/rendering/PathCapType.hpp>
40 #include <com/sun/star/rendering/PathJoinType.hpp>
41 #include <com/sun/star/rendering/TexturingMode.hpp>
42 #include <com/sun/star/rendering/XCanvas.hpp>
44 #include <bitmapaction.hxx>
45 #include <implrenderer.hxx>
46 #include <outdevstate.hxx>
47 #include <polypolyaction.hxx>
48 #include <textaction.hxx>
53 #define EmfPlusRecordTypeHeader 16385
54 #define EmfPlusRecordTypeEndOfFile 16386
55 #define EmfPlusRecordTypeGetDC 16388
56 #define EmfPlusRecordTypeObject 16392
57 #define EmfPlusRecordTypeFillRects 16394
58 #define EmfPlusRecordTypeFillPolygon 16396
59 #define EmfPlusRecordTypeDrawLines 16397
60 #define EmfPlusRecordTypeFillEllipse 16398
61 #define EmfPlusRecordTypeDrawEllipse 16399
62 #define EmfPlusRecordTypeFillPie 16400
63 #define EmfPlusRecordTypeFillPath 16404
64 #define EmfPlusRecordTypeDrawPath 16405
65 #define EmfPlusRecordTypeDrawImage 16410
66 #define EmfPlusRecordTypeDrawImagePoints 16411
67 #define EmfPlusRecordTypeDrawString 16412
68 #define EmfPlusRecordTypeSetRenderingOrigin 16413
69 #define EmfPlusRecordTypeSetAntiAliasMode 16414
70 #define EmfPlusRecordTypeSetTextRenderingHint 16415
71 #define EmfPlusRecordTypeSetInterpolationMode 16417
72 #define EmfPlusRecordTypeSetPixelOffsetMode 16418
73 #define EmfPlusRecordTypeSetCompositingQuality 16420
74 #define EmfPlusRecordTypeSave 16421
75 #define EmfPlusRecordTypeRestore 16422
76 #define EmfPlusRecordTypeBeginContainerNoParams 16424
77 #define EmfPlusRecordTypeEndContainer 16425
78 #define EmfPlusRecordTypeSetWorldTransform 16426
79 #define EmfPlusRecordTypeResetWorldTransform 16427
80 #define EmfPlusRecordTypeMultiplyWorldTransform 16428
81 #define EmfPlusRecordTypeSetPageTransform 16432
82 #define EmfPlusRecordTypeSetClipRect 16434
83 #define EmfPlusRecordTypeSetClipPath 16435
84 #define EmfPlusRecordTypeSetClipRegion 16436
85 #define EmfPlusRecordTypeDrawDriverString 16438
87 #define EmfPlusObjectTypeBrush 0x100
88 #define EmfPlusObjectTypePen 0x200
89 #define EmfPlusObjectTypePath 0x300
90 #define EmfPlusObjectTypeRegion 0x400
91 #define EmfPlusObjectTypeImage 0x500
92 #define EmfPlusObjectTypeFont 0x600
93 #define EmfPlusObjectTypeStringFormat 0x700
94 #define EmfPlusObjectTypeImageAttributes 0x800
95 #define EmfPlusObjectTypeCustomLineCap 0x900
97 #define EmfPlusRegionInitialStateInfinite 0x10000003
99 const sal_Int32 EmfPlusLineStyleSolid
= 0x00000000;
100 const sal_Int32 EmfPlusLineStyleDash
= 0x00000001;
101 const sal_Int32 EmfPlusLineStyleDot
= 0x00000002;
102 const sal_Int32 EmfPlusLineStyleDashDot
= 0x00000003;
103 const sal_Int32 EmfPlusLineStyleDashDotDot
= 0x00000004;
104 const sal_Int32 EmfPlusLineStyleCustom
= 0x00000005;
106 const sal_uInt32 EmfPlusCustomLineCapDataTypeDefault
= 0x00000000;
107 const sal_uInt32 EmfPlusCustomLineCapDataTypeAdjustableArrow
= 0x00000001;
109 const sal_uInt32 EmfPlusCustomLineCapDataFillPath
= 0x00000001;
110 const sal_uInt32 EmfPlusCustomLineCapDataLinePath
= 0x00000002;
112 const sal_uInt32 EmfPlusLineCapTypeSquare
= 0x00000001;
113 const sal_uInt32 EmfPlusLineCapTypeRound
= 0x00000002;
115 const sal_uInt32 EmfPlusLineJoinTypeMiter
= 0x00000000;
116 const sal_uInt32 EmfPlusLineJoinTypeBevel
= 0x00000001;
117 const sal_uInt32 EmfPlusLineJoinTypeRound
= 0x00000002;
118 const sal_uInt32 EmfPlusLineJoinTypeMiterClipped
= 0x00000003;
120 enum EmfPlusCombineMode
122 EmfPlusCombineModeReplace
= 0x00000000,
123 EmfPlusCombineModeIntersect
= 0x00000001,
124 EmfPlusCombineModeUnion
= 0x00000002,
125 EmfPlusCombineModeXOR
= 0x00000003,
126 EmfPlusCombineModeExclude
= 0x00000004,
127 EmfPlusCombineModeComplement
= 0x00000005
130 enum EmfPlusHatchStyle
132 HatchStyleHorizontal
= 0x00000000,
133 HatchStyleVertical
= 0x00000001,
134 HatchStyleForwardDiagonal
= 0x00000002,
135 HatchStyleBackwardDiagonal
= 0x00000003,
136 HatchStyleLargeGrid
= 0x00000004,
137 HatchStyleDiagonalCross
= 0x00000005,
138 HatchStyle05Percent
= 0x00000006,
139 HatchStyle10Percent
= 0x00000007,
140 HatchStyle20Percent
= 0x00000008,
141 HatchStyle25Percent
= 0x00000009,
142 HatchStyle30Percent
= 0x0000000A,
143 HatchStyle40Percent
= 0x0000000B,
144 HatchStyle50Percent
= 0x0000000C,
145 HatchStyle60Percent
= 0x0000000D,
146 HatchStyle70Percent
= 0x0000000E,
147 HatchStyle75Percent
= 0x0000000F,
148 HatchStyle80Percent
= 0x00000010,
149 HatchStyle90Percent
= 0x00000011,
150 HatchStyleLightDownwardDiagonal
= 0x00000012,
151 HatchStyleLightUpwardDiagonal
= 0x00000013,
152 HatchStyleDarkDownwardDiagonal
= 0x00000014,
153 HatchStyleDarkUpwardDiagonal
= 0x00000015,
154 HatchStyleWideDownwardDiagonal
= 0x00000016,
155 HatchStyleWideUpwardDiagonal
= 0x00000017,
156 HatchStyleLightVertical
= 0x00000018,
157 HatchStyleLightHorizontal
= 0x00000019,
158 HatchStyleNarrowVertical
= 0x0000001A,
159 HatchStyleNarrowHorizontal
= 0x0000001B,
160 HatchStyleDarkVertical
= 0x0000001C,
161 HatchStyleDarkHorizontal
= 0x0000001D,
162 HatchStyleDashedDownwardDiagonal
= 0x0000001E,
163 HatchStyleDashedUpwardDiagonal
= 0x0000001F,
164 HatchStyleDashedHorizontal
= 0x00000020,
165 HatchStyleDashedVertical
= 0x00000021,
166 HatchStyleSmallConfetti
= 0x00000022,
167 HatchStyleLargeConfetti
= 0x00000023,
168 HatchStyleZigZag
= 0x00000024,
169 HatchStyleWave
= 0x00000025,
170 HatchStyleDiagonalBrick
= 0x00000026,
171 HatchStyleHorizontalBrick
= 0x00000027,
172 HatchStyleWeave
= 0x00000028,
173 HatchStylePlaid
= 0x00000029,
174 HatchStyleDivot
= 0x0000002A,
175 HatchStyleDottedGrid
= 0x0000002B,
176 HatchStyleDottedDiamond
= 0x0000002C,
177 HatchStyleShingle
= 0x0000002D,
178 HatchStyleTrellis
= 0x0000002E,
179 HatchStyleSphere
= 0x0000002F,
180 HatchStyleSmallGrid
= 0x00000030,
181 HatchStyleSmallCheckerBoard
= 0x00000031,
182 HatchStyleLargeCheckerBoard
= 0x00000032,
183 HatchStyleOutlinedDiamond
= 0x00000033,
184 HatchStyleSolidDiamond
= 0x00000034
187 const char* emfTypeToName(sal_uInt16 type
)
191 case EmfPlusRecordTypeHeader
: return "EmfPlusRecordTypeHeader";
192 case EmfPlusRecordTypeEndOfFile
: return "EmfPlusRecordTypeEndOfFile";
193 case EmfPlusRecordTypeGetDC
: return "EmfPlusRecordTypeGetDC";
194 case EmfPlusRecordTypeObject
: return "EmfPlusRecordTypeObject";
195 case EmfPlusRecordTypeFillRects
: return "EmfPlusRecordTypeFillRects";
196 case EmfPlusRecordTypeFillPolygon
: return "EmfPlusRecordTypeFillPolygon";
197 case EmfPlusRecordTypeDrawLines
: return "EmfPlusRecordTypeDrawLines";
198 case EmfPlusRecordTypeFillEllipse
: return "EmfPlusRecordTypeFillEllipse";
199 case EmfPlusRecordTypeDrawEllipse
: return "EmfPlusRecordTypeDrawEllipse";
200 case EmfPlusRecordTypeFillPie
: return "EmfPlusRecordTypeFillPie";
201 case EmfPlusRecordTypeFillPath
: return "EmfPlusRecordTypeFillPath";
202 case EmfPlusRecordTypeDrawPath
: return "EmfPlusRecordTypeDrawPath";
203 case EmfPlusRecordTypeDrawImage
: return "EmfPlusRecordTypeDrawImage";
204 case EmfPlusRecordTypeDrawImagePoints
: return "EmfPlusRecordTypeDrawImagePoints";
205 case EmfPlusRecordTypeDrawString
: return "EmfPlusRecordTypeDrawString";
206 case EmfPlusRecordTypeSetRenderingOrigin
: return "EmfPlusRecordTypeSetRenderingOrigin";
207 case EmfPlusRecordTypeSetAntiAliasMode
: return "EmfPlusRecordTypeSetAntiAliasMode";
208 case EmfPlusRecordTypeSetTextRenderingHint
: return "EmfPlusRecordTypeSetTextRenderingHint";
209 case EmfPlusRecordTypeSetInterpolationMode
: return "EmfPlusRecordTypeSetInterpolationMode";
210 case EmfPlusRecordTypeSetPixelOffsetMode
: return "EmfPlusRecordTypeSetPixelOffsetMode";
211 case EmfPlusRecordTypeSetCompositingQuality
: return "EmfPlusRecordTypeSetCompositingQuality";
212 case EmfPlusRecordTypeSave
: return "EmfPlusRecordTypeSave";
213 case EmfPlusRecordTypeRestore
: return "EmfPlusRecordTypeRestore";
214 case EmfPlusRecordTypeBeginContainerNoParams
: return "EmfPlusRecordTypeBeginContainerNoParams";
215 case EmfPlusRecordTypeEndContainer
: return "EmfPlusRecordTypeEndContainer";
216 case EmfPlusRecordTypeSetWorldTransform
: return "EmfPlusRecordTypeSetWorldTransform";
217 case EmfPlusRecordTypeResetWorldTransform
: return "EmfPlusRecordTypeResetWorldTransform";
218 case EmfPlusRecordTypeMultiplyWorldTransform
: return "EmfPlusRecordTypeMultiplyWorldTransform";
219 case EmfPlusRecordTypeSetPageTransform
: return "EmfPlusRecordTypeSetPageTransform";
220 case EmfPlusRecordTypeSetClipRect
: return "EmfPlusRecordTypeSetClipRect";
221 case EmfPlusRecordTypeSetClipPath
: return "EmfPlusRecordTypeSetClipPath";
222 case EmfPlusRecordTypeSetClipRegion
: return "EmfPlusRecordTypeSetClipRegion";
223 case EmfPlusRecordTypeDrawDriverString
: return "EmfPlusRecordTypeDrawDriverString";
228 } // anonymous namespace
230 using namespace ::com::sun::star
;
231 using namespace ::basegfx
;
237 struct EMFPPath
: public EMFPObject
239 ::basegfx::B2DPolyPolygon aPolygon
;
242 sal_uInt8
* pPointTypes
;
245 EMFPPath (sal_Int32 _nPoints
, bool bLines
= false)
247 if( _nPoints
<0 || sal_uInt32(_nPoints
)>SAL_MAX_INT32
/(2*sizeof(float)) )
248 _nPoints
= SAL_MAX_INT32
/(2*sizeof(float));
250 pPoints
= new float [nPoints
*2];
252 pPointTypes
= new sal_uInt8
[_nPoints
];
254 pPointTypes
= nullptr;
260 delete [] pPointTypes
;
263 // TODO: remove rR argument when debug code is not longer needed
264 void Read (SvStream
& s
, sal_uInt32 pathFlags
, ImplRenderer
& rR
)
266 for (int i
= 0; i
< nPoints
; i
++) {
267 if (pathFlags
& 0x4000) {
268 // EMFPlusPoint: stored in signed short 16bit integer format
271 s
.ReadInt16( x
).ReadInt16( y
);
272 SAL_INFO ("cppcanvas.emf", "EMF+\tEMFPlusPoint [x,y]: " << x
<< "," << y
);
274 pPoints
[i
*2 + 1] = y
;
275 } else if (!(pathFlags
& 0xC000)) {
276 // EMFPlusPointF: stored in Single (float) format
277 s
.ReadFloat( pPoints
[i
*2] ).ReadFloat( pPoints
[i
*2 + 1] );
278 SAL_INFO ("cppcanvas.emf", "EMF+\tEMFPlusPointF [x,y]: " << pPoints
[i
*2] << "," << pPoints
[i
*2 + 1]);
279 } else { //if (pathFlags & 0x8000)
280 // EMFPlusPointR: points are stored in EMFPlusInteger7 or
281 // EMFPlusInteger15 objects, see section 2.2.2.21/22
282 SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - parse EMFPlusPointR object (section 2.2.1.6)");
288 for (int i
= 0; i
< nPoints
; i
++) {
289 s
.ReadUChar( pPointTypes
[i
] );
290 SAL_INFO ("cppcanvas.emf", "EMF+\tpoint type: " << (int)pPointTypes
[i
]);
295 #if OSL_DEBUG_LEVEL > 1
296 const ::basegfx::B2DRectangle
aBounds (::basegfx::tools::getRange (GetPolygon (rR
)));
298 SAL_INFO ("cppcanvas.emf",
299 "EMF+\tpolygon bounding box: " << aBounds
.getMinX () << "," << aBounds
.getMinY () << aBounds
.getWidth () << "x" << aBounds
.getHeight () << " (mapped)");
301 (void) rR
; // avoid warnings
305 ::basegfx::B2DPolyPolygon
& GetPolygon (ImplRenderer
& rR
, bool bMapIt
= true)
307 ::basegfx::B2DPolygon polygon
;
311 int last_normal
= 0, p
= 0;
312 ::basegfx::B2DPoint prev
, mapped
;
313 bool hasPrev
= false;
314 for (int i
= 0; i
< nPoints
; i
++) {
315 if (p
&& pPointTypes
&& (pPointTypes
[i
] == 0)) {
316 aPolygon
.append (polygon
);
323 mapped
= rR
.Map (pPoints
[i
*2], pPoints
[i
*2 + 1]);
325 mapped
= ::basegfx::B2DPoint (pPoints
[i
*2], pPoints
[i
*2 + 1]);
327 if ((pPointTypes
[i
] & 0x07) == 3) {
328 if (((i
- last_normal
)% 3) == 1) {
329 polygon
.setNextControlPoint (p
- 1, mapped
);
330 SAL_INFO ("cppcanvas.emf", "polygon append next: " << p
- 1 << " mapped: " << mapped
.getX () << "," << mapped
.getY ());
332 } else if (((i
- last_normal
) % 3) == 2) {
340 polygon
.append (mapped
);
341 SAL_INFO ("cppcanvas.emf", "polygon append point: " << pPoints
[i
*2] << "," << pPoints
[i
*2 + 1] << " mapped: " << mapped
.getX () << ":" << mapped
.getY ());
343 polygon
.setPrevControlPoint (p
, prev
);
344 SAL_INFO ("cppcanvas.emf", "polygon append prev: " << p
<< " mapped: " << prev
.getX () << "," << prev
.getY ());
348 if (pPointTypes
&& (pPointTypes
[i
] & 0x80)) { // closed polygon
349 polygon
.setClosed (true);
350 aPolygon
.append (polygon
);
351 SAL_INFO ("cppcanvas.emf", "close polygon");
358 if (polygon
.count ()) {
359 aPolygon
.append (polygon
);
361 #if OSL_DEBUG_LEVEL > 1
362 for (unsigned int i
=0; i
<aPolygon
.count(); i
++) {
363 polygon
= aPolygon
.getB2DPolygon(i
);
364 SAL_INFO ("cppcanvas.emf", "polygon: " << i
);
365 for (unsigned int j
=0; j
<polygon
.count(); j
++) {
366 ::basegfx::B2DPoint point
= polygon
.getB2DPoint(j
);
367 SAL_INFO ("cppcanvas.emf", "point: " << point
.getX() << "," << point
.getY());
368 if (polygon
.isPrevControlPointUsed(j
)) {
369 point
= polygon
.getPrevControlPoint(j
);
370 SAL_INFO ("cppcanvas.emf", "prev: " << point
.getX() << "," << point
.getY());
372 if (polygon
.isNextControlPointUsed(j
)) {
373 point
= polygon
.getNextControlPoint(j
);
374 SAL_INFO ("cppcanvas.emf", "next: " << point
.getX() << "," << point
.getY());
385 struct EMFPRegion
: public EMFPObject
388 sal_Int32
*combineMode
;
389 sal_Int32 initialState
;
390 EMFPPath
*initialPath
;
391 float ix
, iy
, iw
, ih
;
395 , combineMode(nullptr)
397 , initialPath(nullptr)
405 virtual ~EMFPRegion ()
408 delete [] combineMode
;
409 combineMode
= nullptr;
413 initialPath
= nullptr;
417 void Read (SvStream
& s
)
421 s
.ReadUInt32( header
).ReadInt32( parts
);
423 SAL_INFO ("cppcanvas.emf", "EMF+\tregion");
424 SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " parts: " << parts
<< std::dec
);
427 if( parts
<0 || sal_uInt32(parts
)>SAL_MAX_INT32
/sizeof(sal_Int32
) )
428 parts
= SAL_MAX_INT32
/sizeof(sal_Int32
);
430 combineMode
= new sal_Int32
[parts
];
432 for (int i
= 0; i
< parts
; i
++) {
433 s
.ReadInt32( combineMode
[i
] );
434 SAL_INFO ("cppcanvas.emf", "EMF+\tcombine mode [" << i
<< "]: 0x" << std::hex
<< combineMode
[i
] << std::dec
);
438 s
.ReadInt32( initialState
);
439 SAL_INFO ("cppcanvas.emf", "EMF+\tinitial state: 0x" << std::hex
<< initialState
<< std::dec
);
443 struct EMFPBrush
: public EMFPObject
447 sal_uInt32 additionalFlags
;
449 /* linear gradient */
451 float areaX
, areaY
, areaWidth
, areaHeight
;
452 ::Color secondColor
; // first color is stored in solidColor;
453 XForm transformation
;
454 bool hasTransformation
;
455 sal_Int32 blendPoints
;
456 float* blendPositions
;
458 sal_Int32 colorblendPoints
;
459 float* colorblendPositions
;
460 ::Color
* colorblendColors
;
461 sal_Int32 surroundColorsNumber
;
462 ::Color
* surroundColors
;
464 EmfPlusHatchStyle hatchStyle
;
475 , hasTransformation(false)
477 , blendPositions(nullptr)
478 , blendFactors(nullptr)
479 , colorblendPoints(0)
480 , colorblendPositions(nullptr)
481 , colorblendColors(nullptr)
482 , surroundColorsNumber(0)
483 , surroundColors(nullptr)
485 , hatchStyle(HatchStyleHorizontal
)
489 virtual ~EMFPBrush ()
491 if (blendPositions
!= nullptr) {
492 delete[] blendPositions
;
493 blendPositions
= nullptr;
495 if (colorblendPositions
!= nullptr) {
496 delete[] colorblendPositions
;
497 colorblendPositions
= nullptr;
499 if (colorblendColors
!= nullptr) {
500 delete[] colorblendColors
;
501 colorblendColors
= nullptr;
503 if (surroundColors
!= nullptr) {
504 delete[] surroundColors
;
505 surroundColors
= nullptr;
513 sal_uInt32
GetType() const { return type
; }
514 const ::Color
& GetColor() const { return solidColor
; }
516 void Read (SvStream
& s
, ImplRenderer
& rR
)
520 s
.ReadUInt32( header
).ReadUInt32( type
);
522 SAL_INFO ("cppcanvas.emf", "EMF+\tbrush");
523 SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " type: " << type
<< std::dec
);
530 s
.ReadUInt32( color
);
531 solidColor
= ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
532 SAL_INFO ("cppcanvas.emf", "EMF+\tsolid color: 0x" << std::hex
<< color
<< std::dec
);
538 sal_uInt32 foregroundColor
;
539 sal_uInt32 backgroundColor
;
540 s
.ReadUInt32( style
);
541 s
.ReadUInt32( foregroundColor
);
542 s
.ReadUInt32( backgroundColor
);
544 hatchStyle
= static_cast<EmfPlusHatchStyle
>(style
);
545 solidColor
= ::Color(0xff - (foregroundColor
>> 24), (foregroundColor
>> 16) & 0xff, (foregroundColor
>> 8) & 0xff, foregroundColor
& 0xff);
546 secondColor
= ::Color(0xff - (backgroundColor
>> 24), (backgroundColor
>> 16) & 0xff, (backgroundColor
>> 8) & 0xff, backgroundColor
& 0xff);
547 SAL_INFO ("cppcanvas.emf", "EMF+\thatch style " << style
<< " foregroundcolor: 0x" << solidColor
.AsRGBHexString() << " background 0x" << secondColor
.AsRGBHexString());
553 s
.ReadUInt32( additionalFlags
).ReadInt32( wrapMode
);
555 SAL_INFO ("cppcanvas.emf", "EMF+\tpath gradient, additional flags: 0x" << std::hex
<< additionalFlags
<< std::dec
);
559 s
.ReadUInt32( color
);
560 solidColor
= ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
561 SAL_INFO("cppcanvas.emf", "EMF+\tcenter color: 0x" << std::hex
<< color
<< std::dec
);
563 s
.ReadFloat( areaX
).ReadFloat( areaY
);
564 SAL_INFO("cppcanvas.emf", "EMF+\tcenter point: " << areaX
<< "," << areaY
);
566 s
.ReadInt32( surroundColorsNumber
);
567 SAL_INFO("cppcanvas.emf", "EMF+\tsurround colors: " << surroundColorsNumber
);
569 if( surroundColorsNumber
<0 || sal_uInt32(surroundColorsNumber
)>SAL_MAX_INT32
/sizeof(::Color
) )
570 surroundColorsNumber
= SAL_MAX_INT32
/sizeof(::Color
);
572 surroundColors
= new ::Color
[surroundColorsNumber
];
573 for (int i
= 0; i
< surroundColorsNumber
; i
++) {
574 s
.ReadUInt32( color
);
575 surroundColors
[i
] = ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
577 secondColor
= surroundColors
[0];
578 SAL_INFO("cppcanvas.emf", "EMF+\tsurround color[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
581 if (additionalFlags
& 0x01) {
582 sal_Int32 pathLength
;
584 s
.ReadInt32( pathLength
);
585 SAL_INFO("cppcanvas.emf", "EMF+\tpath length: " << pathLength
);
587 sal_Size pos
= s
.Tell ();
589 sal_uInt32 pathHeader
;
590 sal_Int32 pathPoints
, pathFlags
;
591 s
.ReadUInt32( pathHeader
).ReadInt32( pathPoints
).ReadInt32( pathFlags
);
593 SAL_INFO("cppcanvas.emf", "EMF+\tpath (brush path gradient)");
594 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< pathHeader
<< " points: " << std::dec
<< pathPoints
<< " additional flags: 0x" << std::hex
<< pathFlags
<< std::dec
);
596 path
= new EMFPPath (pathPoints
);
597 path
->Read (s
, pathFlags
, rR
);
599 s
.Seek (pos
+ pathLength
);
601 const ::basegfx::B2DRectangle
aBounds (::basegfx::tools::getRange (path
->GetPolygon (rR
, false)));
602 areaWidth
= aBounds
.getWidth ();
603 areaHeight
= aBounds
.getHeight ();
605 SAL_INFO("cppcanvas.emf", "EMF+\tpolygon bounding box: " << aBounds
.getMinX () << "," << aBounds
.getMinY () << " " << aBounds
.getWidth () << "x" << aBounds
.getHeight ());
608 if (additionalFlags
& 0x02) {
609 SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
610 ReadXForm( s
, transformation
);
611 hasTransformation
= true;
612 SAL_INFO("cppcanvas.emf",
613 "EMF+\tm11: " << transformation
.eM11
<< " m12: " << transformation
.eM12
<<
614 "\nEMF+\tm21: " << transformation
.eM21
<< " m22: " << transformation
.eM22
<<
615 "\nEMF+\tdx: " << transformation
.eDx
<< " dy: " << transformation
.eDy
);
618 if (additionalFlags
& 0x08) {
619 s
.ReadInt32( blendPoints
);
620 SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints
);
621 if( blendPoints
<0 || sal_uInt32(blendPoints
)>SAL_MAX_INT32
/(2*sizeof(float)) )
622 blendPoints
= SAL_MAX_INT32
/(2*sizeof(float));
623 blendPositions
= new float [2*blendPoints
];
624 blendFactors
= blendPositions
+ blendPoints
;
625 for (int i
=0; i
< blendPoints
; i
++) {
626 s
.ReadFloat( blendPositions
[i
] );
627 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i
<< "]: " << blendPositions
[i
]);
629 for (int i
=0; i
< blendPoints
; i
++) {
630 s
.ReadFloat( blendFactors
[i
] );
631 SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i
<< "]: " << blendFactors
[i
]);
635 if (additionalFlags
& 0x04) {
636 s
.ReadInt32( colorblendPoints
);
637 SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints
);
638 if( colorblendPoints
<0 || sal_uInt32(colorblendPoints
)>SAL_MAX_INT32
/sizeof(float) )
639 colorblendPoints
= SAL_MAX_INT32
/sizeof(float);
640 if( sal_uInt32(colorblendPoints
)>SAL_MAX_INT32
/sizeof(::Color
) )
641 colorblendPoints
= SAL_MAX_INT32
/sizeof(::Color
);
642 colorblendPositions
= new float [colorblendPoints
];
643 colorblendColors
= new ::Color
[colorblendPoints
];
644 for (int i
=0; i
< colorblendPoints
; i
++) {
645 s
.ReadFloat( colorblendPositions
[i
] );
646 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i
<< "]: " << colorblendPositions
[i
]);
648 for (int i
=0; i
< colorblendPoints
; i
++) {
649 s
.ReadUInt32( color
);
650 colorblendColors
[i
] = ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
651 SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
660 s
.ReadUInt32( additionalFlags
).ReadInt32( wrapMode
);
662 SAL_INFO("cppcanvas.emf", "EMF+\tlinear gradient, additional flags: 0x" << std::hex
<< additionalFlags
<< std::dec
);
664 s
.ReadFloat( areaX
).ReadFloat( areaY
).ReadFloat( areaWidth
).ReadFloat( areaHeight
);
666 SAL_INFO("cppcanvas.emf", "EMF+\tarea: " << areaX
<< "," << areaY
<< " - " << areaWidth
<< "x" << areaHeight
);
670 s
.ReadUInt32( color
);
671 solidColor
= ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
672 SAL_INFO("cppcanvas.emf", "EMF+\tfirst color: 0x" << std::hex
<< color
<< std::dec
);
674 s
.ReadUInt32( color
);
675 secondColor
= ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
676 SAL_INFO("cppcanvas.emf", "EMF+\tsecond color: 0x" << std::hex
<< color
<< std::dec
);
678 // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
679 s
.ReadUInt32( color
);
680 s
.ReadUInt32( color
);
682 if (additionalFlags
& 0x02) {
683 SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
684 ReadXForm( s
, transformation
);
685 hasTransformation
= true;
686 SAL_INFO("cppcanvas.emf",
687 "EMF+\tm11: " << transformation
.eM11
<< " m12: " << transformation
.eM12
<<
688 "\nEMF+\tm21: " << transformation
.eM21
<< " m22: " << transformation
.eM22
<<
689 "\nEMF+\tdx: " << transformation
.eDx
<< " dy: " << transformation
.eDy
);
691 if (additionalFlags
& 0x08) {
692 s
.ReadInt32( blendPoints
);
693 SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints
);
694 if( blendPoints
<0 || sal_uInt32(blendPoints
)>SAL_MAX_INT32
/(2*sizeof(float)) )
695 blendPoints
= SAL_MAX_INT32
/(2*sizeof(float));
696 blendPositions
= new float [2*blendPoints
];
697 blendFactors
= blendPositions
+ blendPoints
;
698 for (int i
=0; i
< blendPoints
; i
++) {
699 s
.ReadFloat( blendPositions
[i
] );
700 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i
<< "]: " << blendPositions
[i
]);
702 for (int i
=0; i
< blendPoints
; i
++) {
703 s
.ReadFloat( blendFactors
[i
] );
704 SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i
<< "]: " << blendFactors
[i
]);
708 if (additionalFlags
& 0x04) {
709 s
.ReadInt32( colorblendPoints
);
710 SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints
);
711 if( colorblendPoints
<0 || sal_uInt32(colorblendPoints
)>SAL_MAX_INT32
/sizeof(float) )
712 colorblendPoints
= SAL_MAX_INT32
/sizeof(float);
713 if( sal_uInt32(colorblendPoints
)>SAL_MAX_INT32
/sizeof(::Color
) )
714 colorblendPoints
= sal_uInt32(SAL_MAX_INT32
)/sizeof(::Color
);
715 colorblendPositions
= new float [colorblendPoints
];
716 colorblendColors
= new ::Color
[colorblendPoints
];
717 for (int i
=0; i
< colorblendPoints
; i
++) {
718 s
.ReadFloat( colorblendPositions
[i
] );
719 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i
<< "]: " << colorblendPositions
[i
]);
721 for (int i
=0; i
< colorblendPoints
; i
++) {
722 s
.ReadUInt32( color
);
723 colorblendColors
[i
] = ::Color (0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
724 SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
731 SAL_INFO("cppcanvas.emf", "EMF+\tunhandled brush type: " << std::hex
<< type
<< std::dec
);
736 /// Convert stroke caps between EMF+ and rendering API
737 sal_Int8
lcl_convertStrokeCap(sal_uInt32 nEmfStroke
)
741 case EmfPlusLineCapTypeSquare
: return rendering::PathCapType::SQUARE
;
742 case EmfPlusLineCapTypeRound
: return rendering::PathCapType::ROUND
;
745 // we have no mapping for EmfPlusLineCapTypeTriangle = 0x00000003,
746 // so return BUTT always
747 return rendering::PathCapType::BUTT
;
750 sal_Int8
lcl_convertLineJoinType(sal_uInt32 nEmfLineJoin
)
752 switch (nEmfLineJoin
)
754 case EmfPlusLineJoinTypeMiter
: // fall-through
755 case EmfPlusLineJoinTypeMiterClipped
: return rendering::PathJoinType::MITER
;
756 case EmfPlusLineJoinTypeBevel
: return rendering::PathJoinType::BEVEL
;
757 case EmfPlusLineJoinTypeRound
: return rendering::PathJoinType::ROUND
;
759 assert(false); // Line Join type isn't in specification.
763 struct EMFPCustomLineCap
: public EMFPObject
766 sal_uInt32 strokeStartCap
, strokeEndCap
, strokeJoin
;
768 basegfx::B2DPolyPolygon polygon
;
783 virtual ~EMFPCustomLineCap()
787 void SetAttributes(rendering::StrokeAttributes
& aAttributes
)
789 aAttributes
.StartCapType
= lcl_convertStrokeCap(strokeStartCap
);
790 aAttributes
.EndCapType
= lcl_convertStrokeCap(strokeEndCap
);
791 aAttributes
.JoinType
= lcl_convertLineJoinType(strokeJoin
);
793 aAttributes
.MiterLimit
= miterLimit
;
796 void ReadPath(SvStream
& s
, ImplRenderer
& rR
, bool bFill
)
798 sal_Int32 pathLength
;
799 s
.ReadInt32( pathLength
);
800 SAL_INFO("cppcanvas.emf", "EMF+\t\tpath length: " << pathLength
);
802 sal_uInt32 pathHeader
;
803 sal_Int32 pathPoints
, pathFlags
;
804 s
.ReadUInt32( pathHeader
).ReadInt32( pathPoints
).ReadInt32( pathFlags
);
806 SAL_INFO("cppcanvas.emf", "EMF+\t\tpath (custom cap line path)");
807 SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex
<< pathHeader
<< " points: " << std::dec
<< pathPoints
<< " additional flags: 0x" << std::hex
<< pathFlags
<< std::dec
);
809 EMFPPath
path(pathPoints
);
810 path
.Read(s
, pathFlags
, rR
);
812 polygon
= path
.GetPolygon(rR
, false);
815 // transformation to convert the path to what LibreOffice
817 B2DHomMatrix aMatrix
;
818 aMatrix
.scale(1.0, -1.0);
820 polygon
.transform(aMatrix
);
823 void Read (SvStream
& s
, ImplRenderer
& rR
)
827 s
.ReadUInt32( header
).ReadUInt32( type
);
829 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustom cap");
830 SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex
<< header
<< " type: " << type
<< std::dec
);
832 if (type
== EmfPlusCustomLineCapDataTypeDefault
)
834 sal_uInt32 customLineCapDataFlags
, baseCap
;
837 float fillHotSpotX
, fillHotSpotY
, strokeHotSpotX
, strokeHotSpotY
;
839 s
.ReadUInt32( customLineCapDataFlags
).ReadUInt32( baseCap
).ReadFloat( baseInset
)
840 .ReadUInt32( strokeStartCap
).ReadUInt32( strokeEndCap
).ReadUInt32( strokeJoin
)
841 .ReadFloat( miterLimit
).ReadFloat( widthScale
)
842 .ReadFloat( fillHotSpotX
).ReadFloat( fillHotSpotY
).ReadFloat( strokeHotSpotX
).ReadFloat( strokeHotSpotY
);
844 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomLineCapDataFlags: 0x" << std::hex
<< customLineCapDataFlags
);
845 SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseCap: 0x" << std::hex
<< baseCap
);
846 SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseInset: " << baseInset
);
847 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeStartCap: 0x" << std::hex
<< strokeStartCap
);
848 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeEndCap: 0x" << std::hex
<< strokeEndCap
);
849 SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeJoin: 0x" << std::hex
<< strokeJoin
);
850 SAL_INFO("cppcanvas.emf", "EMF+\t\tmiterLimit: " << miterLimit
);
851 SAL_INFO("cppcanvas.emf", "EMF+\t\twidthScale: " << widthScale
);
853 if (customLineCapDataFlags
& EmfPlusCustomLineCapDataFillPath
)
855 ReadPath(s
, rR
, true);
858 if (customLineCapDataFlags
& EmfPlusCustomLineCapDataLinePath
)
860 ReadPath(s
, rR
, false);
863 else if (type
== EmfPlusCustomLineCapDataTypeAdjustableArrow
)
865 // TODO only reads the data, does not use them [I've had
866 // no test document to be able to implement it]
868 sal_Int32 width
, height
, middleInset
, fillState
, lineStartCap
;
869 sal_Int32 lineEndCap
, lineJoin
, widthScale
;
870 float fillHotSpotX
, fillHotSpotY
, lineHotSpotX
, lineHotSpotY
;
872 s
.ReadInt32( width
).ReadInt32( height
).ReadInt32( middleInset
).ReadInt32( fillState
).ReadInt32( lineStartCap
)
873 .ReadInt32( lineEndCap
).ReadInt32( lineJoin
).ReadFloat( miterLimit
).ReadInt32( widthScale
)
874 .ReadFloat( fillHotSpotX
).ReadFloat( fillHotSpotY
).ReadFloat( lineHotSpotX
).ReadFloat( lineHotSpotY
);
876 SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - actually read EmfPlusCustomLineCapArrowData object (section 2.2.2.12)");
881 struct EMFPPen
: public EMFPBrush
883 XForm transformation
;
892 sal_Int32 dashPatternLen
;
895 sal_Int32 compoundArrayLen
;
896 float *compoundArray
;
897 sal_Int32 customStartCapLen
;
898 EMFPCustomLineCap
*customStartCap
;
899 sal_Int32 customEndCapLen
;
900 EMFPCustomLineCap
*customEndCap
;
914 , dashPattern(nullptr)
916 , compoundArrayLen(0)
917 , compoundArray(nullptr)
918 , customStartCapLen(0)
919 , customStartCap(nullptr)
921 , customEndCap(nullptr)
927 delete[] dashPattern
;
928 delete[] compoundArray
;
929 delete customStartCap
;
933 void SetStrokeWidth(rendering::StrokeAttributes
& rStrokeAttributes
, ImplRenderer
& rR
, const OutDevState
& rState
)
935 #if OSL_DEBUG_LEVEL > 1
937 SAL_INFO ("cppcanvas.emf", "TODO: pen with zero width - using minimal which might not be correct\n");
940 rStrokeAttributes
.StrokeWidth
= fabs((rState
.mapModeTransform
* rR
.MapSize (width
== 0.0 ? 0.05 : width
, 0)).getLength());
943 void SetStrokeAttributes(rendering::StrokeAttributes
& rStrokeAttributes
)
945 rStrokeAttributes
.JoinType
= lcl_convertLineJoinType(lineJoin
);
947 if (dashStyle
!= EmfPlusLineStyleSolid
)
949 const float dash
[] = {3, 3};
950 const float dot
[] = {1, 3};
951 const float dashdot
[] = {3, 3, 1, 3};
952 const float dashdotdot
[] = {3, 3, 1, 3, 1, 3};
955 const float *pPattern
= nullptr;
958 case EmfPlusLineStyleDash
: nLen
= SAL_N_ELEMENTS(dash
); pPattern
= dash
; break;
959 case EmfPlusLineStyleDot
: nLen
= SAL_N_ELEMENTS(dot
); pPattern
= dot
; break;
960 case EmfPlusLineStyleDashDot
: nLen
= SAL_N_ELEMENTS(dashdot
); pPattern
= dashdot
; break;
961 case EmfPlusLineStyleDashDotDot
: nLen
= SAL_N_ELEMENTS(dashdotdot
); pPattern
= dashdotdot
; break;
962 case EmfPlusLineStyleCustom
: nLen
= dashPatternLen
; pPattern
= dashPattern
; break;
966 uno::Sequence
<double> aDashArray(nLen
);
967 for (int i
= 0; i
< nLen
; ++i
)
968 aDashArray
[i
] = pPattern
[i
];
970 rStrokeAttributes
.DashArray
= aDashArray
;
975 void Read (SvStream
& s
, ImplRenderer
& rR
, sal_Int32
, sal_Int32
)
977 sal_uInt32 header
, unknown
, penFlags
, unknown2
;
980 s
.ReadUInt32( header
).ReadUInt32( unknown
).ReadUInt32( penFlags
).ReadUInt32( unknown2
).ReadFloat( width
);
982 SAL_INFO("cppcanvas.emf", "EMF+\tpen");
983 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " unknown: 0x" << unknown
<<
984 " additional flags: 0x" << penFlags
<< " unknown: 0x" << unknown2
<< " width: " << std::dec
<< width
);
987 ReadXForm( s
, transformation
);
991 s
.ReadInt32( startCap
);
992 SAL_INFO("cppcanvas.emf", "EMF+\t\tstartCap: 0x" << std::hex
<< startCap
);
999 s
.ReadInt32( endCap
);
1000 SAL_INFO("cppcanvas.emf", "EMF+\t\tendCap: 0x" << std::hex
<< endCap
);
1006 s
.ReadInt32( lineJoin
);
1011 s
.ReadFloat( mitterLimit
);
1017 s
.ReadInt32( dashStyle
);
1018 SAL_INFO("cppcanvas.emf", "EMF+\t\tdashStyle: 0x" << std::hex
<< dashStyle
);
1024 s
.ReadInt32( dashCap
);
1029 s
.ReadFloat( dashOffset
);
1035 dashStyle
= EmfPlusLineStyleCustom
;
1037 s
.ReadInt32( dashPatternLen
);
1038 SAL_INFO("cppcanvas.emf", "EMF+\t\tdashPatternLen: " << dashPatternLen
);
1040 if( dashPatternLen
<0 || sal_uInt32(dashPatternLen
)>SAL_MAX_INT32
/sizeof(float) )
1041 dashPatternLen
= SAL_MAX_INT32
/sizeof(float);
1042 dashPattern
= new float [dashPatternLen
];
1043 for (i
= 0; i
< dashPatternLen
; i
++)
1045 s
.ReadFloat( dashPattern
[i
] );
1046 SAL_INFO("cppcanvas.emf", "EMF+\t\t\tdashPattern[" << i
<< "]: " << dashPattern
[i
]);
1053 s
.ReadInt32( alignment
);
1057 if (penFlags
& 1024) {
1058 s
.ReadInt32( compoundArrayLen
);
1059 if( compoundArrayLen
<0 || sal_uInt32(compoundArrayLen
)>SAL_MAX_INT32
/sizeof(float) )
1060 compoundArrayLen
= SAL_MAX_INT32
/sizeof(float);
1061 compoundArray
= new float [compoundArrayLen
];
1062 for (i
= 0; i
< compoundArrayLen
; i
++)
1063 s
.ReadFloat( compoundArray
[i
] );
1065 compoundArrayLen
= 0;
1067 if (penFlags
& 2048)
1069 s
.ReadInt32( customStartCapLen
);
1070 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomStartCapLen: " << customStartCapLen
);
1071 sal_Size pos
= s
.Tell();
1073 customStartCap
= new EMFPCustomLineCap();
1074 customStartCap
->Read(s
, rR
);
1076 // maybe we don't read everything yet, play it safe ;-)
1077 s
.Seek(pos
+ customStartCapLen
);
1080 customStartCapLen
= 0;
1082 if (penFlags
& 4096)
1084 s
.ReadInt32( customEndCapLen
);
1085 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomEndCapLen: " << customEndCapLen
);
1086 sal_Size pos
= s
.Tell();
1088 customEndCap
= new EMFPCustomLineCap();
1089 customEndCap
->Read(s
, rR
);
1091 // maybe we don't read everything yet, play it safe ;-)
1092 s
.Seek(pos
+ customEndCapLen
);
1095 customEndCapLen
= 0;
1097 EMFPBrush::Read (s
, rR
);
1101 struct EMFPImage
: public EMFPObject
1107 sal_Int32 pixelFormat
;
1111 void Read (SvMemoryStream
&s
, sal_uInt32 dataSize
, bool bUseWholeStream
)
1113 sal_uInt32 header
, bitmapType
;
1115 s
.ReadUInt32( header
).ReadUInt32( type
);
1117 SAL_INFO("cppcanvas.emf", "EMF+\timage\nEMF+\theader: 0x" << std::hex
<< header
<< " type: " << type
<< std::dec
);
1119 if (type
== 1) { // bitmap
1120 s
.ReadInt32( width
).ReadInt32( height
).ReadInt32( stride
).ReadInt32( pixelFormat
).ReadUInt32( bitmapType
);
1121 SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << width
<< " height: " << height
<< " stride: " << stride
<< " pixelFormat: 0x" << std::hex
<< pixelFormat
<< std::dec
);
1122 if ((bitmapType
!= 0) || (width
== 0)) { // non native formats
1123 GraphicFilter filter
;
1125 filter
.ImportGraphic (graphic
, OUString(), s
);
1126 SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << graphic
.GetBitmap().GetSizePixel().Width() << " height: " << graphic
.GetBitmap().GetSizePixel().Height());
1129 } else if (type
== 2) { // metafile
1130 sal_Int32 mfType
, mfSize
;
1132 s
.ReadInt32( mfType
).ReadInt32( mfSize
);
1133 if (bUseWholeStream
)
1134 dataSize
= s
.remainingSize();
1137 SAL_INFO("cppcanvas.emf", "EMF+\tmetafile type: " << mfType
<< " dataSize: " << mfSize
<< " real size calculated from record dataSize: " << dataSize
);
1139 GraphicFilter filter
;
1140 // workaround buggy metafiles, which have wrong mfSize set (n#705956 for example)
1141 SvMemoryStream
mfStream (const_cast<char *>(static_cast<char const *>(s
.GetData()) + s
.Tell()), dataSize
, StreamMode::READ
);
1143 filter
.ImportGraphic (graphic
, OUString(), mfStream
);
1145 // debug code - write the stream to debug file /tmp/emf-stream.emf
1146 #if OSL_DEBUG_LEVEL > 1
1148 static sal_Int32 emfp_debug_stream_number
= 0;
1149 OUString emfp_debug_filename
= "/tmp/emf-embedded-stream" +
1150 OUString::number(emfp_debug_stream_number
++) + ".emf";
1152 SvFileStream
file( emfp_debug_filename
, StreamMode::WRITE
| StreamMode::TRUNC
);
1154 mfStream
.WriteStream(file
);
1162 struct EMFPFont
: public EMFPObject
1165 sal_uInt32 sizeUnit
;
1166 sal_Int32 fontFlags
;
1169 void Read (SvMemoryStream
&s
)
1172 sal_uInt32 reserved
;
1175 s
.ReadUInt32( header
).ReadFloat( emSize
).ReadUInt32( sizeUnit
).ReadInt32( fontFlags
).ReadUInt32( reserved
).ReadUInt32( length
);
1177 OSL_ASSERT( ( header
>> 12 ) == 0xdbc01 );
1179 SAL_INFO("cppcanvas.emf", "EMF+\tfont\nEMF+\theader: 0x" << std::hex
<< (header
>> 12) << " version: 0x" << (header
& 0x1fff) << " size: " << std::dec
<< emSize
<< " unit: 0x" << std::hex
<< sizeUnit
<< std::dec
);
1180 SAL_INFO("cppcanvas.emf", "EMF+\tflags: 0x" << std::hex
<< fontFlags
<< " reserved: 0x" << reserved
<< " length: 0x" << std::hex
<< length
<< std::dec
);
1182 if (length
> 0 && length
< 0x4000)
1184 rtl_uString
*pStr
= rtl_uString_alloc(length
);
1185 sal_Unicode
*chars
= pStr
->buffer
;
1187 for (sal_uInt32 i
= 0; i
< length
; ++i
)
1188 s
.ReadUtf16(chars
[i
]);
1190 family
= OUString(pStr
, SAL_NO_ACQUIRE
);
1191 SAL_INFO("cppcanvas.emf", "EMF+\tfamily: " << family
);
1196 void ImplRenderer::ReadRectangle (SvStream
& s
, float& x
, float& y
, float &width
, float& height
, bool bCompressed
)
1199 sal_Int16 ix
, iy
, iw
, ih
;
1201 s
.ReadInt16( ix
).ReadInt16( iy
).ReadInt16( iw
).ReadInt16( ih
);
1208 s
.ReadFloat( x
).ReadFloat( y
).ReadFloat( width
).ReadFloat( height
);
1211 void ImplRenderer::ReadPoint (SvStream
& s
, float& x
, float& y
, sal_uInt32 flags
)
1213 if (flags
& 0x4000) {
1216 s
.ReadInt16( ix
).ReadInt16( iy
);
1221 s
.ReadFloat( x
).ReadFloat( y
);
1224 void ImplRenderer::MapToDevice (double& x
, double& y
)
1226 // TODO: other units
1227 x
= 100*nMmX
*x
/nPixX
;
1228 y
= 100*nMmY
*y
/nPixY
;
1231 ::basegfx::B2DPoint
ImplRenderer::Map (double ix
, double iy
)
1235 x
= ix
*aWorldTransform
.eM11
+ iy
*aWorldTransform
.eM21
+ aWorldTransform
.eDx
;
1236 y
= ix
*aWorldTransform
.eM12
+ iy
*aWorldTransform
.eM22
+ aWorldTransform
.eDy
;
1243 x
*= aBaseTransform
.eM11
;
1244 y
*= aBaseTransform
.eM22
;
1246 return ::basegfx::B2DPoint (x
, y
);
1249 ::basegfx::B2DSize
ImplRenderer::MapSize (double iwidth
, double iheight
)
1253 w
= iwidth
*aWorldTransform
.eM11
+ iheight
*aWorldTransform
.eM21
;
1254 h
= iwidth
*aWorldTransform
.eM12
+ iheight
*aWorldTransform
.eM22
;
1258 w
*= aBaseTransform
.eM11
;
1259 h
*= aBaseTransform
.eM22
;
1261 return ::basegfx::B2DSize (w
, h
);
1265 vcl::unotools::colorToDoubleSequence( ::Color (0xff - (x >> 24), \
1269 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
1271 void ImplRenderer::EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon
& polygon
, const ActionFactoryParameters
& rParms
,
1272 OutDevState
& rState
, const CanvasSharedPtr
& rCanvas
, bool isColor
, sal_uInt32 brushIndexOrColor
)
1274 ::basegfx::B2DPolyPolygon
localPolygon (polygon
);
1276 SAL_INFO("cppcanvas.emf", "EMF+\tfill polygon");
1278 localPolygon
.transform( rState
.mapModeTransform
);
1280 ActionSharedPtr pPolyAction
;
1283 SAL_INFO("cppcanvas.emf", "EMF+\t\tcolor fill:0x" << std::hex
<< brushIndexOrColor
<< std::dec
);
1284 rState
.isFillColorSet
= true;
1285 rState
.isLineColorSet
= false;
1287 rState
.fillColor
= COLOR(brushIndexOrColor
);
1289 pPolyAction
= ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon
, rParms
.mrCanvas
, rState
) );
1292 rState
.isFillColorSet
= true;
1294 EMFPBrush
* brush
= static_cast<EMFPBrush
*>( aObjects
[brushIndexOrColor
& 0xff] );
1295 SAL_INFO("cppcanvas.emf", "EMF+\tbrush fill slot: " << brushIndexOrColor
<< " (type: " << (brush
? brush
->GetType() : -1) << ")");
1297 // give up in case something wrong happened
1301 rState
.isFillColorSet
= false;
1302 rState
.isLineColorSet
= false;
1304 if (brush
->type
== 1)
1306 // EMF+ like hatching is currently not supported. These are just color blends which serve as an approximation for some of them
1307 // for the others the hatch "background" color (secondColor in brush) is used.
1309 bool isHatchBlend
= true;
1310 double blendFactor
= 0.0;
1312 switch (brush
->hatchStyle
)
1314 case HatchStyle05Percent
: blendFactor
= 0.05; break;
1315 case HatchStyle10Percent
: blendFactor
= 0.10; break;
1316 case HatchStyle20Percent
: blendFactor
= 0.20; break;
1317 case HatchStyle25Percent
: blendFactor
= 0.25; break;
1318 case HatchStyle30Percent
: blendFactor
= 0.30; break;
1319 case HatchStyle40Percent
: blendFactor
= 0.40; break;
1320 case HatchStyle50Percent
: blendFactor
= 0.50; break;
1321 case HatchStyle60Percent
: blendFactor
= 0.60; break;
1322 case HatchStyle70Percent
: blendFactor
= 0.70; break;
1323 case HatchStyle75Percent
: blendFactor
= 0.75; break;
1324 case HatchStyle80Percent
: blendFactor
= 0.80; break;
1325 case HatchStyle90Percent
: blendFactor
= 0.90; break;
1327 isHatchBlend
= false;
1330 rState
.isFillColorSet
= true;
1331 rState
.isLineColorSet
= false;
1335 fillColor
= brush
->solidColor
;
1336 fillColor
.Merge(brush
->secondColor
, static_cast<sal_uInt8
>(255 * blendFactor
));
1340 fillColor
= brush
->secondColor
;
1342 rState
.fillColor
= vcl::unotools::colorToDoubleSequence(fillColor
, rCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace());
1343 pPolyAction
= ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon
, rParms
.mrCanvas
, rState
) );
1345 else if (brush
->type
== 3 || brush
->type
== 4)
1347 if (brush
->type
== 3 && !(brush
->additionalFlags
& 0x1))
1348 return; // we are unable to parse these brushes yet
1350 ::basegfx::B2DHomMatrix aTextureTransformation
;
1351 ::basegfx::B2DHomMatrix aWorldTransformation
;
1352 ::basegfx::B2DHomMatrix aBaseTransformation
;
1353 rendering::Texture aTexture
;
1355 aWorldTransformation
.set (0, 0, aWorldTransform
.eM11
);
1356 aWorldTransformation
.set (0, 1, aWorldTransform
.eM21
);
1357 aWorldTransformation
.set (0, 2, aWorldTransform
.eDx
);
1358 aWorldTransformation
.set (1, 0, aWorldTransform
.eM12
);
1359 aWorldTransformation
.set (1, 1, aWorldTransform
.eM22
);
1360 aWorldTransformation
.set (1, 2, aWorldTransform
.eDy
);
1362 aBaseTransformation
.set (0, 0, aBaseTransform
.eM11
);
1363 aBaseTransformation
.set (0, 1, aBaseTransform
.eM21
);
1364 aBaseTransformation
.set (0, 2, aBaseTransform
.eDx
);
1365 aBaseTransformation
.set (1, 0, aBaseTransform
.eM12
);
1366 aBaseTransformation
.set (1, 1, aBaseTransform
.eM22
);
1367 aBaseTransformation
.set (1, 2, aBaseTransform
.eDy
);
1369 if (brush
->type
== 4) {
1370 aTextureTransformation
.scale (brush
->areaWidth
, brush
->areaHeight
);
1371 aTextureTransformation
.translate (brush
->areaX
, brush
->areaY
);
1373 aTextureTransformation
.translate (-0.5, -0.5);
1374 aTextureTransformation
.scale (brush
->areaWidth
, brush
->areaHeight
);
1375 aTextureTransformation
.translate (brush
->areaX
,brush
->areaY
);
1378 if (brush
->hasTransformation
) {
1379 ::basegfx::B2DHomMatrix aTransformation
;
1381 aTransformation
.set (0, 0, brush
->transformation
.eM11
);
1382 aTransformation
.set (0, 1, brush
->transformation
.eM21
);
1383 aTransformation
.set (0, 2, brush
->transformation
.eDx
);
1384 aTransformation
.set (1, 0, brush
->transformation
.eM12
);
1385 aTransformation
.set (1, 1, brush
->transformation
.eM22
);
1386 aTransformation
.set (1, 2, brush
->transformation
.eDy
);
1388 aTextureTransformation
*= aTransformation
;
1391 aTextureTransformation
*= aWorldTransformation
;
1392 aTextureTransformation
.scale (100.0*nMmX
/nPixX
, 100.0*nMmY
/nPixY
);
1393 aTextureTransformation
.translate (-nFrameLeft
, -nFrameTop
);
1394 aTextureTransformation
*= rState
.mapModeTransform
;
1395 aTextureTransformation
*= aBaseTransformation
;
1397 aTexture
.RepeatModeX
= rendering::TexturingMode::CLAMP
;
1398 aTexture
.RepeatModeY
= rendering::TexturingMode::CLAMP
;
1399 aTexture
.Alpha
= 1.0;
1401 basegfx::ODFGradientInfo aGradInfo
;
1402 OUString aGradientService
;
1404 const uno::Sequence
< double > aStartColor(
1405 vcl::unotools::colorToDoubleSequence( brush
->solidColor
,
1406 rParms
.mrCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
1407 const uno::Sequence
< double > aEndColor(
1408 vcl::unotools::colorToDoubleSequence( brush
->secondColor
,
1409 rParms
.mrCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
1410 uno::Sequence
< uno::Sequence
< double > > aColors (2);
1411 uno::Sequence
< double > aStops (2);
1413 if (brush
->blendPositions
) {
1414 SAL_INFO("cppcanvas.emf", "EMF+\t\tuse blend");
1415 aColors
.realloc (brush
->blendPoints
);
1416 aStops
.realloc (brush
->blendPoints
);
1417 int length
= aStartColor
.getLength ();
1418 uno::Sequence
< double > aColor (length
);
1420 OSL_ASSERT (length
== aEndColor
.getLength());
1422 for (int i
= 0; i
< brush
->blendPoints
; i
++) {
1423 aStops
[i
] = brush
->blendPositions
[i
];
1425 for (int j
= 0; j
< length
; j
++) {
1426 if (brush
->type
== 4) {
1427 aColor
[j
] = aStartColor
[j
]*(1 - brush
->blendFactors
[i
]) + aEndColor
[j
]*brush
->blendFactors
[i
];
1429 aColor
[j
] = aStartColor
[j
]*brush
->blendFactors
[i
] + aEndColor
[j
]*(1 - brush
->blendFactors
[i
]);
1432 aColors
[i
] = aColor
;
1434 } else if (brush
->colorblendPositions
) {
1435 SAL_INFO("cppcanvas.emf", "EMF+\t\tuse color blend");
1436 aColors
.realloc (brush
->colorblendPoints
);
1437 aStops
.realloc (brush
->colorblendPoints
);
1439 for (int i
= 0; i
< brush
->colorblendPoints
; i
++) {
1440 aStops
[i
] = brush
->colorblendPositions
[i
];
1441 aColors
[(brush
->type
== 4) ? i
: brush
->colorblendPoints
- 1 - i
] = vcl::unotools::colorToDoubleSequence( brush
->colorblendColors
[i
],
1442 rParms
.mrCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
1448 if (brush
->type
== 4) {
1449 aColors
[0] = aStartColor
;
1450 aColors
[1] = aEndColor
;
1452 aColors
[1] = aStartColor
;
1453 aColors
[0] = aEndColor
;
1457 SAL_INFO("cppcanvas.emf", "EMF+\t\tset gradient");
1458 basegfx::B2DRange
aBoundsRectangle (0, 0, 1, 1);
1459 if (brush
->type
== 4) {
1460 aGradientService
= "LinearGradient";
1461 aGradInfo
= basegfx::tools::createLinearODFGradientInfo(
1468 aGradientService
= "EllipticalGradient";
1469 aGradInfo
= basegfx::tools::createEllipticalODFGradientInfo(
1471 ::basegfx::B2DVector( 0, 0 ),
1477 uno::Reference
< lang::XMultiServiceFactory
> xFactory(
1478 rParms
.mrCanvas
->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
1480 if( xFactory
.is() ) {
1481 uno::Sequence
<uno::Any
> args( 3 );
1482 beans::PropertyValue aProp
;
1483 aProp
.Name
= "Colors";
1484 aProp
.Value
<<= aColors
;
1486 aProp
.Name
= "Stops";
1487 aProp
.Value
<<= aStops
;
1489 aProp
.Name
= "AspectRatio";
1490 aProp
.Value
<<= static_cast<sal_Int32
>(1);
1493 aTexture
.Gradient
.set(
1494 xFactory
->createInstanceWithArguments( aGradientService
,
1499 ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture
.AffineTransform
,
1500 aTextureTransformation
);
1502 if( aTexture
.Gradient
.is() )
1504 ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon
,
1513 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd poly action");
1515 maActions
.push_back(
1518 rParms
.mrCurrActionIndex
) );
1520 rParms
.mrCurrActionIndex
+= pPolyAction
->getActionCount()-1;
1524 double ImplRenderer::EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon
& rPolygon
, double fPolyLength
,
1525 const ::basegfx::B2DPolyPolygon
& rLineCap
, bool bIsFilled
, bool bStart
, const rendering::StrokeAttributes
& rAttributes
,
1526 const ActionFactoryParameters
& rParms
, OutDevState
& rState
)
1528 if (!rLineCap
.count())
1531 // createAreaGeometryForLineStartEnd normalises the arrows height
1532 // before scaling (i.e. scales down by rPolygon.height), hence
1533 // we pre-scale it (which means we can avoid changing the logic
1534 // that would affect arrows rendered outside of EMF+).
1535 const double fWidth
= rAttributes
.StrokeWidth
*rLineCap
.getB2DRange().getWidth();
1537 // When drawing an outline (as opposed to a filled endCap), we also
1538 // need to take account that the brush width also adds to the area
1540 const double fShift
= bIsFilled
? 0 : rAttributes
.StrokeWidth
;
1541 double fConsumed
= 0;
1542 basegfx::B2DPolyPolygon
aArrow(basegfx::tools::createAreaGeometryForLineStartEnd(
1543 rPolygon
, rLineCap
, bStart
,
1544 fWidth
, fPolyLength
, 0, &fConsumed
, fShift
));
1546 // createAreaGeometryForLineStartEnd from some reason always sets
1547 // the path as closed, correct it
1548 aArrow
.setClosed(rLineCap
.isClosed());
1550 // If the endcap is filled, we draw ONLY the filling, if it isn't
1551 // filled we draw ONLY the outline, but never both.
1554 bool bWasFillColorSet
= rState
.isFillColorSet
;
1555 rState
.isFillColorSet
= true;
1556 rState
.fillColor
= rState
.lineColor
;
1557 ActionSharedPtr
pAction2(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow
, rParms
.mrCanvas
, rState
));
1560 maActions
.push_back(MtfAction(pAction2
, rParms
.mrCurrActionIndex
));
1561 rParms
.mrCurrActionIndex
+= pAction2
->getActionCount()-1;
1563 rState
.isFillColorSet
= bWasFillColorSet
;
1567 ActionSharedPtr
pAction(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow
, rParms
.mrCanvas
, rState
, rAttributes
));
1570 maActions
.push_back(MtfAction(pAction
, rParms
.mrCurrActionIndex
));
1571 rParms
.mrCurrActionIndex
+= pAction
->getActionCount()-1;
1575 // There isn't any clear definition of how far the line should extend
1576 // for arrows, however the following values seem to give best results
1577 // (fConsumed/2 draws the line to the center-point of the endcap
1578 // for filled caps -- however it is likely this will need to be
1579 // changed once we start taking baseInset into account).
1583 return rAttributes
.StrokeWidth
;
1586 void ImplRenderer::EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon
& polygon
, const ActionFactoryParameters
& rParms
,
1587 OutDevState
& rState
, const CanvasSharedPtr
& rCanvas
, sal_uInt32 penIndex
)
1589 EMFPPen
* pen
= static_cast<EMFPPen
*>( aObjects
[penIndex
& 0xff] );
1591 SAL_WARN_IF( !pen
, "cppcanvas.emf", "emf+ missing pen" );
1595 rState
.isFillColorSet
= false;
1596 rState
.isLineColorSet
= true;
1597 rState
.lineColor
= vcl::unotools::colorToDoubleSequence (pen
->GetColor (),
1598 rCanvas
->getUNOCanvas ()->getDevice()->getDeviceColorSpace());
1600 basegfx::B2DPolyPolygon
aPolyPolygon(polygon
);
1601 aPolyPolygon
.transform(rState
.mapModeTransform
);
1602 rendering::StrokeAttributes aCommonAttributes
;
1604 // some attributes are common for the polygon, and the line
1605 // starts & ends - like the stroke width
1606 pen
->SetStrokeWidth(aCommonAttributes
, *this, rState
);
1608 // but eg. dashing has to be additionally set only on the
1610 rendering::StrokeAttributes
aPolygonAttributes(aCommonAttributes
);
1611 pen
->SetStrokeAttributes(aPolygonAttributes
);
1613 basegfx::B2DPolyPolygon aFinalPolyPolygon
;
1615 // render line starts & ends if present
1616 if (!pen
->customStartCap
&& !pen
->customEndCap
)
1617 aFinalPolyPolygon
= aPolyPolygon
;
1620 for (sal_uInt32 i
= 0; i
< aPolyPolygon
.count(); ++i
)
1622 basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(i
));
1624 if (!aPolygon
.isClosed())
1626 double fStart
= 0.0;
1628 double fPolyLength
= basegfx::tools::getLength(aPolygon
);
1631 if (pen
->customStartCap
)
1633 rendering::StrokeAttributes
aAttributes(aCommonAttributes
);
1634 pen
->customStartCap
->SetAttributes(aAttributes
);
1636 fStart
= EMFPPlusDrawLineCap(aPolygon
, fPolyLength
, pen
->customStartCap
->polygon
,
1637 pen
->customStartCap
->mbIsFilled
,
1638 true, aAttributes
, rParms
, rState
);
1642 if (pen
->customEndCap
)
1644 rendering::StrokeAttributes
aAttributes(aCommonAttributes
);
1645 pen
->customEndCap
->SetAttributes(aAttributes
);
1647 fEnd
= EMFPPlusDrawLineCap(aPolygon
, fPolyLength
, pen
->customEndCap
->polygon
,
1648 pen
->customEndCap
->mbIsFilled
,
1649 false, aAttributes
, rParms
, rState
);
1652 // build new poly, consume something from the old poly
1653 if (fStart
!= 0.0 || fEnd
!= 0.0)
1654 aPolygon
= basegfx::tools::getSnippetAbsolute(aPolygon
, fStart
, fPolyLength
- fEnd
, fPolyLength
);
1657 aFinalPolyPolygon
.append(aPolygon
);
1661 // finally render the polygon
1662 ActionSharedPtr
pPolyAction(internal::PolyPolyActionFactory::createPolyPolyAction(aFinalPolyPolygon
, rParms
.mrCanvas
, rState
, aPolygonAttributes
));
1665 maActions
.push_back(MtfAction(pPolyAction
, rParms
.mrCurrActionIndex
));
1666 rParms
.mrCurrActionIndex
+= pPolyAction
->getActionCount()-1;
1671 void ImplRenderer::processObjectRecord(SvMemoryStream
& rObjectStream
, sal_uInt16 flags
, sal_uInt32 dataSize
, bool bUseWholeStream
)
1675 SAL_INFO("cppcanvas.emf", "EMF+ Object slot: " << (flags
& 0xff) << " flags: " << (flags
& 0xff00));
1677 index
= flags
& 0xff;
1678 if (aObjects
[index
] != nullptr) {
1679 delete aObjects
[index
];
1680 aObjects
[index
] = nullptr;
1683 switch (flags
& 0x7f00) {
1684 case EmfPlusObjectTypeBrush
:
1687 aObjects
[index
] = brush
= new EMFPBrush ();
1688 brush
->Read (rObjectStream
, *this);
1692 case EmfPlusObjectTypePen
:
1695 aObjects
[index
] = pen
= new EMFPPen ();
1696 pen
->Read (rObjectStream
, *this, nHDPI
, nVDPI
);
1700 case EmfPlusObjectTypePath
:
1701 sal_uInt32 header
, pathFlags
;
1704 rObjectStream
.ReadUInt32( header
).ReadInt32( points
).ReadUInt32( pathFlags
);
1706 SAL_INFO("cppcanvas.emf", "EMF+\tpath");
1707 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " points: " << std::dec
<< points
<< " additional flags: 0x" << std::hex
<< pathFlags
<< std::dec
);
1710 aObjects
[index
] = path
= new EMFPPath (points
);
1711 path
->Read (rObjectStream
, pathFlags
, *this);
1714 case EmfPlusObjectTypeRegion
: {
1717 aObjects
[index
] = region
= new EMFPRegion ();
1718 region
->Read (rObjectStream
);
1722 case EmfPlusObjectTypeImage
:
1725 aObjects
[index
] = image
= new EMFPImage ();
1726 image
->Read (rObjectStream
, dataSize
, bUseWholeStream
);
1730 case EmfPlusObjectTypeFont
:
1733 aObjects
[index
] = font
= new EMFPFont ();
1734 font
->Read (rObjectStream
);
1738 case EmfPlusObjectTypeStringFormat
:
1740 SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'string format' not yet implemented");
1743 case EmfPlusObjectTypeImageAttributes
:
1745 SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'image attributes' not yet implemented");
1748 case EmfPlusObjectTypeCustomLineCap
:
1750 SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'custom line cap' not yet implemented");
1754 SAL_INFO("cppcanvas.emf", "EMF+\tObject unhandled flags: 0x" << std::hex
<< (flags
& 0xff00) << std::dec
);
1759 double ImplRenderer::setFont (sal_uInt8 objectId
, const ActionFactoryParameters
& rParms
, OutDevState
& rState
)
1761 EMFPFont
*font
= static_cast<EMFPFont
*>( aObjects
[ objectId
] );
1763 rendering::FontRequest aFontRequest
;
1764 aFontRequest
.FontDescription
.FamilyName
= font
->family
;
1765 double cellSize
= font
->emSize
;
1766 aFontRequest
.CellSize
= (rState
.mapModeTransform
*MapSize( cellSize
, 0 )).getX();
1767 rState
.xFont
= rParms
.mrCanvas
->getUNOCanvas()->createFont( aFontRequest
,
1768 uno::Sequence
< beans::PropertyValue
>(),
1769 geometry::Matrix2D() );
1774 void ImplRenderer::GraphicStatePush(GraphicStateMap
& map
, sal_Int32 index
, OutDevState
& rState
)
1776 GraphicStateMap::iterator iter
= map
.find( index
);
1778 if ( iter
!= map
.end() )
1780 EmfPlusGraphicState state
= iter
->second
;
1783 SAL_INFO("cppcanvas.emf", "stack index: " << index
<< " found and erased");
1786 EmfPlusGraphicState state
;
1788 state
.aWorldTransform
= aWorldTransform
;
1789 state
.aDevState
= rState
;
1791 map
[ index
] = state
;
1794 void ImplRenderer::GraphicStatePop(GraphicStateMap
& map
, sal_Int32 index
, OutDevState
& rState
)
1796 GraphicStateMap::iterator iter
= map
.find( index
);
1798 if ( iter
!= map
.end() )
1800 SAL_INFO("cppcanvas.emf", "stack index: " << index
<< " found");
1802 EmfPlusGraphicState state
= iter
->second
;
1804 aWorldTransform
= state
.aWorldTransform
;
1805 rState
.clip
= state
.aDevState
.clip
;
1806 rState
.clipRect
= state
.aDevState
.clipRect
;
1807 rState
.xClipPoly
= state
.aDevState
.xClipPoly
;
1811 void ImplRenderer::processEMFPlus( MetaCommentAction
* pAct
, const ActionFactoryParameters
& rFactoryParms
,
1812 OutDevState
& rState
, const CanvasSharedPtr
& rCanvas
)
1814 sal_uInt32 length
= pAct
->GetDataSize ();
1815 SvMemoryStream
rMF (const_cast<sal_uInt8
*>(pAct
->GetData ()), length
, StreamMode::READ
);
1818 SAL_INFO("cppcanvas.emf", "length is less than required header size");
1821 // 12 is minimal valid EMF+ record size; remaining bytes are padding
1822 while (length
>= 12) {
1823 sal_uInt16 type
, flags
;
1824 sal_uInt32 size
, dataSize
;
1827 rMF
.ReadUInt16( type
).ReadUInt16( flags
).ReadUInt32( size
).ReadUInt32( dataSize
);
1829 next
= rMF
.Tell() + ( size
- 12 );
1832 SAL_INFO("cppcanvas.emf", "Size field is less than 12 bytes");
1833 } else if (size
> length
) {
1834 SAL_INFO("cppcanvas.emf", "Size field is greater than bytes left");
1836 if (dataSize
> (size
-12)) {
1837 SAL_INFO("cppcanvas.emf", "DataSize field is greater than Size-12");
1840 SAL_INFO("cppcanvas.emf", "EMF+ record size: " << size
<< " type: " << emfTypeToName(type
) << " flags: " << flags
<< " data size: " << dataSize
);
1842 if (type
== EmfPlusRecordTypeObject
&& ((mbMultipart
&& (flags
& 0x7fff) == (mMFlags
& 0x7fff)) || (flags
& 0x8000))) {
1849 OSL_ENSURE(dataSize
>= 4, "No room for TotalObjectSize in EmfPlusContinuedObjectRecord");
1850 // 1st 4 bytes are TotalObjectSize
1851 mMStream
.Write (static_cast<const char *>(rMF
.GetData()) + rMF
.Tell() + 4, dataSize
- 4);
1852 SAL_INFO("cppcanvas.emf", "EMF+ read next object part size: " << size
<< " type: " << type
<< " flags: " << flags
<< " data size: " << dataSize
);
1855 SAL_INFO("cppcanvas.emf", "EMF+ multipart record flags: " << mMFlags
);
1857 processObjectRecord (mMStream
, mMFlags
, 0, true);
1859 mbMultipart
= false;
1862 if (type
!= EmfPlusRecordTypeObject
|| !(flags
& 0x8000))
1865 case EmfPlusRecordTypeHeader
:
1866 sal_uInt32 header
, version
;
1868 rMF
.ReadUInt32( header
).ReadUInt32( version
).ReadInt32( nHDPI
).ReadInt32( nVDPI
);
1870 SAL_INFO("cppcanvas.emf", "EMF+ Header");
1871 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex
<< header
<< " version: " << std::dec
<< version
<< " horizontal DPI: " << nHDPI
<< " vertical DPI: " << nVDPI
<< " dual: " << (flags
& 1));
1874 case EmfPlusRecordTypeEndOfFile
:
1875 SAL_INFO("cppcanvas.emf", "EMF+ EndOfFile");
1877 case EmfPlusRecordTypeGetDC
:
1878 SAL_INFO("cppcanvas.emf", "EMF+ GetDC");
1879 SAL_INFO("cppcanvas.emf", "EMF+\talready used in svtools wmf/emf filter parser");
1881 case EmfPlusRecordTypeObject
:
1882 processObjectRecord (rMF
, flags
, dataSize
);
1884 case EmfPlusRecordTypeFillPie
:
1886 sal_uInt32 brushIndexOrColor
;
1887 float startAngle
, sweepAngle
;
1889 rMF
.ReadUInt32( brushIndexOrColor
).ReadFloat( startAngle
).ReadFloat( sweepAngle
);
1891 SAL_INFO("cppcanvas.emf", "EMF+ FillPie colorOrIndex: " << brushIndexOrColor
<< " startAngle: " << startAngle
<< " sweepAngle: " << sweepAngle
);
1893 float dx
, dy
, dw
, dh
;
1895 ReadRectangle (rMF
, dx
, dy
, dw
, dh
, bool(flags
& 0x4000));
1897 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx
<< "," << dy
<< " " << dw
<< "x" << dh
);
1899 startAngle
= 2*M_PI
*startAngle
/360;
1900 sweepAngle
= 2*M_PI
*sweepAngle
/360;
1902 B2DPoint
mappedCenter (Map (dx
+ dw
/2, dy
+ dh
/2));
1903 B2DSize
mappedSize( MapSize (dw
/2, dh
/2));
1905 float endAngle
= startAngle
+ sweepAngle
;
1906 startAngle
= fmodf(startAngle
, static_cast<float>(M_PI
*2));
1908 startAngle
+= static_cast<float>(M_PI
*2);
1909 endAngle
= fmodf(endAngle
, static_cast<float>(M_PI
*2));
1911 endAngle
+= static_cast<float>(M_PI
*2);
1914 std::swap (endAngle
, startAngle
);
1916 SAL_INFO("cppcanvas.emf", "EMF+ adjusted angles: start " <<
1917 (360.0*startAngle
/M_PI
) << ", end: " << (360.0*endAngle
/M_PI
));
1919 B2DPolygon polygon
= basegfx::tools::createPolygonFromEllipseSegment (mappedCenter
, mappedSize
.getX (), mappedSize
.getY (), startAngle
, endAngle
);
1920 polygon
.append (mappedCenter
);
1921 polygon
.setClosed (true);
1923 B2DPolyPolygon
polyPolygon (polygon
);
1924 EMFPPlusFillPolygon (polyPolygon
, rFactoryParms
, rState
, rCanvas
, flags
& 0x8000, brushIndexOrColor
);
1927 case EmfPlusRecordTypeFillPath
:
1929 sal_uInt32 index
= flags
& 0xff;
1930 sal_uInt32 brushIndexOrColor
;
1932 rMF
.ReadUInt32( brushIndexOrColor
);
1934 SAL_INFO("cppcanvas.emf", "EMF+ FillPath slot: " << index
);
1936 EMFPPlusFillPolygon( static_cast<EMFPPath
*>( aObjects
[index
])->GetPolygon (*this), rFactoryParms
, rState
, rCanvas
, flags
& 0x8000, brushIndexOrColor
);
1939 case EmfPlusRecordTypeDrawEllipse
:
1940 case EmfPlusRecordTypeFillEllipse
:
1942 // Intentionally very bogus initial value to avoid MSVC complaining about potentially uninitialized local
1943 // variable. As long as the code stays as intended, this variable will be assigned a (real) value in the case
1944 // when it is later used.
1945 sal_uInt32 brushIndexOrColor
= 1234567;
1947 if ( type
== EmfPlusRecordTypeFillEllipse
)
1948 rMF
.ReadUInt32( brushIndexOrColor
);
1950 SAL_INFO("cppcanvas.emf", "EMF+ " << (type
== EmfPlusRecordTypeFillEllipse
? "Fill" : "Draw") << "Ellipse slot: " << (flags
& 0xff));
1952 float dx
, dy
, dw
, dh
;
1954 ReadRectangle (rMF
, dx
, dy
, dw
, dh
, bool(flags
& 0x4000));
1956 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx
<< "," << dy
<< " " << dw
<< "x" << dh
);
1958 B2DPoint
mappedCenter (Map (dx
+ dw
/2, dy
+ dh
/2));
1959 B2DSize
mappedSize( MapSize (dw
/2, dh
/2));
1961 ::basegfx::B2DPolyPolygon
polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromEllipse( mappedCenter
, mappedSize
.getX (), mappedSize
.getY () ) ) );
1963 if ( type
== EmfPlusRecordTypeFillEllipse
)
1964 EMFPPlusFillPolygon( polyPolygon
,
1965 rFactoryParms
, rState
, rCanvas
, flags
& 0x8000, brushIndexOrColor
);
1967 EMFPPlusDrawPolygon( polyPolygon
,
1968 rFactoryParms
, rState
, rCanvas
, flags
& 0xff );
1971 case EmfPlusRecordTypeFillRects
:
1973 SAL_INFO("cppcanvas.emf", "EMF+ FillRects");
1975 sal_uInt32 brushIndexOrColor
;
1976 sal_Int32 rectangles
;
1977 bool isColor
= (flags
& 0x8000);
1978 ::basegfx::B2DPolygon polygon
;
1980 rMF
.ReadUInt32( brushIndexOrColor
).ReadInt32( rectangles
);
1982 SAL_INFO("cppcanvas.emf", "EMF+\t" << ((flags
& 0x8000) ? "color" : "brush index") << ": 0x" << std::hex
<< brushIndexOrColor
<< std::dec
);
1984 for (int i
=0; i
< rectangles
; i
++) {
1985 if (flags
& 0x4000) {
1986 /* 16bit integers */
1987 sal_Int16 x
, y
, width
, height
;
1989 rMF
.ReadInt16( x
).ReadInt16( y
).ReadInt16( width
).ReadInt16( height
);
1991 polygon
.append (Map (x
, y
));
1992 polygon
.append (Map (x
+ width
, y
));
1993 polygon
.append (Map (x
+ width
, y
+ height
));
1994 polygon
.append (Map (x
, y
+ height
));
1996 SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x
<< ", " << width
<< "x" << height
);
1999 float x
, y
, width
, height
;
2001 rMF
.ReadFloat( x
).ReadFloat( y
).ReadFloat( width
).ReadFloat( height
);
2003 polygon
.append (Map (x
, y
));
2004 polygon
.append (Map (x
+ width
, y
));
2005 polygon
.append (Map (x
+ width
, y
+ height
));
2006 polygon
.append (Map (x
, y
+ height
));
2008 SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x
<< ", " << width
<< "x" << height
);
2011 ::basegfx::B2DPolyPolygon
polyPolygon (polygon
);
2013 EMFPPlusFillPolygon (polyPolygon
, rFactoryParms
, rState
, rCanvas
, isColor
, brushIndexOrColor
);
2017 case EmfPlusRecordTypeFillPolygon
:
2019 sal_uInt8 index
= flags
& 0xff;
2020 sal_uInt32 brushIndexOrColor
;
2023 rMF
.ReadUInt32( brushIndexOrColor
);
2024 rMF
.ReadInt32( points
);
2026 SAL_INFO("cppcanvas.emf", "EMF+ FillPolygon in slot: " << +index
<< " points: " << points
);
2027 SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags
& 0x8000) ? "color" : "brush index") << " 0x" << std::hex
<< brushIndexOrColor
<< std::dec
);
2029 EMFPPath
path (points
, true);
2030 path
.Read (rMF
, flags
, *this);
2032 EMFPPlusFillPolygon (path
.GetPolygon (*this), rFactoryParms
, rState
, rCanvas
, flags
& 0x8000, brushIndexOrColor
);
2036 case EmfPlusRecordTypeDrawLines
:
2040 rMF
.ReadUInt32( points
);
2042 SAL_INFO("cppcanvas.emf", "EMF+ DrawLines in slot: " << (flags
& 0xff) << " points: " << points
);
2044 EMFPPath
path (points
, true);
2045 path
.Read (rMF
, flags
, *this);
2047 EMFPPlusDrawPolygon (path
.GetPolygon (*this), rFactoryParms
, rState
, rCanvas
, flags
);
2051 case EmfPlusRecordTypeDrawPath
:
2053 sal_uInt32 penIndex
;
2055 rMF
.ReadUInt32( penIndex
);
2057 SAL_INFO("cppcanvas.emf", "EMF+ DrawPath");
2058 SAL_INFO("cppcanvas.emf", "EMF+\tpen: " << penIndex
);
2060 EMFPPath
* path
= static_cast<EMFPPath
*>( aObjects
[flags
& 0xff] );
2061 SAL_WARN_IF( !path
, "cppcanvas.emf", "EmfPlusRecordTypeDrawPath missing path" );
2063 EMFPPlusDrawPolygon (path
->GetPolygon (*this), rFactoryParms
, rState
, rCanvas
, penIndex
);
2067 case EmfPlusRecordTypeDrawImage
:
2068 case EmfPlusRecordTypeDrawImagePoints
:
2070 sal_uInt32 attrIndex
;
2071 sal_Int32 sourceUnit
;
2073 rMF
.ReadUInt32( attrIndex
).ReadInt32( sourceUnit
);
2075 SAL_INFO("cppcanvas.emf", "EMF+ " << (type
== EmfPlusRecordTypeDrawImagePoints
? "DrawImagePoints" : "DrawImage") << "attributes index: " << attrIndex
<< "source unit: " << sourceUnit
);
2076 SAL_INFO("cppcanvas.emf", "EMF+\tTODO: use image attributes");
2078 if (sourceUnit
== 2 && aObjects
[flags
& 0xff]) { // we handle only GraphicsUnit.Pixel now
2079 EMFPImage
& image
= *static_cast<EMFPImage
*>( aObjects
[flags
& 0xff]);
2080 float sx
, sy
, sw
, sh
;
2083 ReadRectangle (rMF
, sx
, sy
, sw
, sh
);
2084 Rectangle
aSource(Point(sx
, sy
), Size(sw
, sh
));
2086 SAL_INFO("cppcanvas.emf", "EMF+ " << (type
== EmfPlusRecordTypeDrawImagePoints
? "DrawImagePoints" : "DrawImage") << " source rectangle: " << sx
<< "," << sy
<< " " << sw
<< "x" << sh
);
2088 ::basegfx::B2DPoint aDstPoint
;
2089 ::basegfx::B2DSize aDstSize
;
2090 bool bValid
= false;
2092 if (type
== EmfPlusRecordTypeDrawImagePoints
) {
2093 rMF
.ReadInt32( aCount
);
2095 if( aCount
== 3) { // TODO: now that we now that this value is count we should support it better
2096 float x1
, y1
, x2
, y2
, x3
, y3
;
2098 ReadPoint (rMF
, x1
, y1
, flags
);
2099 ReadPoint (rMF
, x2
, y2
, flags
);
2100 ReadPoint (rMF
, x3
, y3
, flags
);
2102 SAL_INFO("cppcanvas.emf", "EMF+ destination points: " << x1
<< "," << y1
<< " " << x2
<< "," << y2
<< " " << x3
<< "," << y3
);
2103 SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << x1
<< "," << y1
<< " " << x2
- x1
<< "x" << y3
- y1
);
2105 aDstPoint
= Map (x1
, y1
);
2106 aDstSize
= MapSize(x2
- x1
, y3
- y1
);
2110 } else if (type
== EmfPlusRecordTypeDrawImage
) {
2111 float dx
, dy
, dw
, dh
;
2113 ReadRectangle (rMF
, dx
, dy
, dw
, dh
, bool(flags
& 0x4000));
2115 SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << dx
<< "," << dy
<< " " << dw
<< "x" << dh
);
2117 aDstPoint
= Map (dx
, dy
);
2118 aDstSize
= MapSize(dw
, dh
);
2124 BitmapEx
aBmp( image
.graphic
.GetBitmapEx () );
2125 aBmp
.Crop( aSource
);
2127 Size
aSize( aBmp
.GetSizePixel() );
2128 SAL_INFO("cppcanvas.emf", "EMF+ bitmap size: " << aSize
.Width() << "x" << aSize
.Height());
2129 if( aSize
.Width() > 0 && aSize
.Height() > 0 ) {
2130 ActionSharedPtr
pBmpAction (
2131 internal::BitmapActionFactory::createBitmapAction (
2133 rState
.mapModeTransform
* aDstPoint
,
2134 rState
.mapModeTransform
* aDstSize
,
2139 maActions
.push_back( MtfAction( pBmpAction
,
2140 rFactoryParms
.mrCurrActionIndex
) );
2142 rFactoryParms
.mrCurrActionIndex
+= pBmpAction
->getActionCount()-1;
2145 SAL_INFO("cppcanvas.emf", "EMF+ warning: empty bitmap");
2148 SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme)");
2151 SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme) - possibly unsupported source units for crop rectangle");
2155 case EmfPlusRecordTypeDrawString
:
2157 SAL_INFO("cppcanvas.emf", "EMF+ DrawString");
2160 sal_uInt32 formatId
;
2161 sal_uInt32 stringLength
;
2163 rMF
.ReadUInt32( brushId
).ReadUInt32( formatId
).ReadUInt32( stringLength
);
2164 SAL_INFO("cppcanvas.emf", "EMF+ DrawString brushId: " << brushId
<< " formatId: " << formatId
<< " length: " << stringLength
);
2166 if (flags
& 0x8000) {
2167 float lx
, ly
, lw
, lh
;
2169 rMF
.ReadFloat( lx
).ReadFloat( ly
).ReadFloat( lw
).ReadFloat( lh
);
2171 SAL_INFO("cppcanvas.emf", "EMF+ DrawString layoutRect: " << lx
<< "," << ly
<< " - " << lw
<< "x" << lh
);
2173 OUString text
= read_uInt16s_ToOUString(rMF
, stringLength
);
2175 double cellSize
= setFont (flags
& 0xff, rFactoryParms
, rState
);
2176 rState
.textColor
= COLOR( brushId
);
2178 ::basegfx::B2DPoint
point( Map( lx
+ 0.15*cellSize
, ly
+ cellSize
) );
2180 ActionSharedPtr
pTextAction(
2181 TextActionFactory::createTextAction(
2182 // position is just rough guess for now
2183 // we should calculate it exactly from layoutRect or font
2184 vcl::unotools::pointFromB2DPoint ( point
),
2193 rFactoryParms
.mrVDev
,
2194 rFactoryParms
.mrCanvas
,
2196 rFactoryParms
.mrParms
,
2200 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
2202 maActions
.push_back(
2205 rFactoryParms
.mrCurrActionIndex
) );
2207 rFactoryParms
.mrCurrActionIndex
+= pTextAction
->getActionCount()-1;
2210 SAL_INFO("cppcanvas.emf", "EMF+ DrawString TODO - drawing with brush not yet supported");
2214 case EmfPlusRecordTypeSetPageTransform
:
2215 rMF
.ReadFloat( fPageScale
);
2217 SAL_INFO("cppcanvas.emf", "EMF+ SetPageTransform");
2218 SAL_INFO("cppcanvas.emf", "EMF+\tscale: " << fPageScale
<< " unit: " << flags
);
2219 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2221 case EmfPlusRecordTypeSetRenderingOrigin
:
2222 rMF
.ReadInt32( nOriginX
).ReadInt32( nOriginY
);
2223 SAL_INFO("cppcanvas.emf", "EMF+ SetRenderingOrigin");
2224 SAL_INFO("cppcanvas.emf", "EMF+\torigin [x,y]: " << nOriginX
<< "," << nOriginY
);
2226 case EmfPlusRecordTypeSetTextRenderingHint
:
2227 SAL_INFO("cppcanvas.emf", "EMF+ SetTextRenderingHint");
2228 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2230 case EmfPlusRecordTypeSetAntiAliasMode
:
2231 SAL_INFO("cppcanvas.emf", "EMF+ SetAntiAliasMode");
2232 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2234 case EmfPlusRecordTypeSetInterpolationMode
:
2235 SAL_INFO("cppcanvas.emf", "EMF+ InterpolationMode");
2236 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2238 case EmfPlusRecordTypeSetPixelOffsetMode
:
2239 SAL_INFO("cppcanvas.emf", "EMF+ SetPixelOffsetMode");
2240 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2242 case EmfPlusRecordTypeSetCompositingQuality
:
2243 SAL_INFO("cppcanvas.emf", "EMF+ SetCompositingQuality");
2244 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2246 case EmfPlusRecordTypeSave
:
2248 sal_uInt32 stackIndex
;
2250 rMF
.ReadUInt32( stackIndex
);
2252 SAL_INFO("cppcanvas.emf", "EMF+ Save stack index: " << stackIndex
);
2254 GraphicStatePush( mGSStack
, stackIndex
, rState
);
2258 case EmfPlusRecordTypeRestore
:
2260 sal_uInt32 stackIndex
;
2262 rMF
.ReadUInt32( stackIndex
);
2264 SAL_INFO("cppcanvas.emf", "EMF+ Restore stack index: " << stackIndex
);
2266 GraphicStatePop( mGSStack
, stackIndex
, rState
);
2270 case EmfPlusRecordTypeBeginContainerNoParams
:
2272 sal_uInt32 stackIndex
;
2274 rMF
.ReadUInt32( stackIndex
);
2276 SAL_INFO("cppcanvas.emf", "EMF+ Begin Container No Params stack index: " << stackIndex
);
2278 GraphicStatePush( mGSContainerStack
, stackIndex
, rState
);
2281 case EmfPlusRecordTypeEndContainer
:
2283 sal_uInt32 stackIndex
;
2285 rMF
.ReadUInt32( stackIndex
);
2287 SAL_INFO("cppcanvas.emf", "EMF+ End Container stack index: " << stackIndex
);
2289 GraphicStatePop( mGSContainerStack
, stackIndex
, rState
);
2292 case EmfPlusRecordTypeSetWorldTransform
: {
2293 SAL_INFO("cppcanvas.emf", "EMF+ SetWorldTransform");
2295 ReadXForm( rMF
, transform
);
2296 aWorldTransform
.Set (transform
);
2297 SAL_INFO("cppcanvas.emf",
2298 "EMF+\tm11: " << aWorldTransform
.eM11
<< "\tm12: " << aWorldTransform
.eM12
<<
2299 "\tm21: " << aWorldTransform
.eM21
<< "\tm22: " << aWorldTransform
.eM22
<<
2300 "\tdx: " << aWorldTransform
.eDx
<< "\tdy: " << aWorldTransform
.eDy
);
2303 case EmfPlusRecordTypeResetWorldTransform
:
2304 SAL_INFO("cppcanvas.emf", "EMF+ ResetWorldTransform");
2305 aWorldTransform
.SetIdentity ();
2307 case EmfPlusRecordTypeMultiplyWorldTransform
: {
2308 SAL_INFO("cppcanvas.emf", "EMF+ MultiplyWorldTransform");
2310 ReadXForm( rMF
, transform
);
2312 SAL_INFO("cppcanvas.emf",
2313 "EMF+\tmatrix m11: " << transform
.eM11
<< "m12: " << transform
.eM12
<<
2314 "EMF+\tm21: " << transform
.eM21
<< "m22: " << transform
.eM22
<<
2315 "EMF+\tdx: " << transform
.eDx
<< "dy: " << transform
.eDy
);
2317 if (flags
& 0x2000) // post multiply
2318 aWorldTransform
.Multiply (transform
);
2319 else { // pre multiply
2320 transform
.Multiply (aWorldTransform
);
2321 aWorldTransform
.Set (transform
);
2323 SAL_INFO("cppcanvas.emf",
2324 "EMF+\tm11: " << aWorldTransform
.eM11
<< "m12: " << aWorldTransform
.eM12
<<
2325 "EMF+\tm21: " << aWorldTransform
.eM21
<< "m22: " << aWorldTransform
.eM22
<<
2326 "EMF+\tdx: " << aWorldTransform
.eDx
<< "dy: " << aWorldTransform
.eDy
);
2329 case EmfPlusRecordTypeSetClipRect
:
2331 int combineMode
= (flags
>> 8) & 0xf;
2333 SAL_INFO("cppcanvas.emf", "EMF+ SetClipRect combine mode: " << combineMode
);
2334 #if OSL_DEBUG_LEVEL > 1
2335 if (combineMode
> 1) {
2336 SAL_INFO ("cppcanvas.emf", "EMF+ TODO combine mode > 1");
2340 float dx
, dy
, dw
, dh
;
2342 ReadRectangle (rMF
, dx
, dy
, dw
, dh
);
2344 SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx
<< "," << dy
<< " " << dw
<< "x" << dh
);
2346 B2DPoint
mappedPoint (Map (dx
, dy
));
2347 B2DSize
mappedSize( MapSize (dw
, dh
));
2349 ::basegfx::B2DPolyPolygon
polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromRect( ::basegfx::B2DRectangle( mappedPoint
.getX(), mappedPoint
.getY(),
2350 mappedPoint
.getX() + mappedSize
.getX(),
2351 mappedPoint
.getY() + mappedSize
.getY() ) ) ) );
2352 polyPolygon
.transform(rState
.mapModeTransform
);
2354 updateClipping (polyPolygon
, rFactoryParms
, combineMode
== 1);
2358 case EmfPlusRecordTypeSetClipPath
:
2360 int combineMode
= (flags
>> 8) & 0xf;
2362 SAL_INFO("cppcanvas.emf", "EMF+ SetClipPath combine mode: " << combineMode
);
2363 SAL_INFO("cppcanvas.emf", "EMF+\tpath in slot: " << (flags
& 0xff));
2365 EMFPPath
& path
= *static_cast<EMFPPath
*>( aObjects
[flags
& 0xff] );
2366 ::basegfx::B2DPolyPolygon
& clipPoly (path
.GetPolygon (*this));
2368 clipPoly
.transform (rState
.mapModeTransform
);
2369 switch (combineMode
)
2371 case EmfPlusCombineModeReplace
:
2372 case EmfPlusCombineModeIntersect
:
2373 case EmfPlusCombineModeUnion
: // Is this, EmfPlusCombineModeXOR and EmfPlusCombineModeComplement correct?
2374 case EmfPlusCombineModeXOR
:
2375 case EmfPlusCombineModeComplement
:
2376 updateClipping (clipPoly
, rFactoryParms
, combineMode
== 1);
2378 case EmfPlusCombineModeExclude
:
2379 // Not doing anything is better then including exactly what we wanted to exclude.
2385 case EmfPlusRecordTypeSetClipRegion
: {
2386 int combineMode
= (flags
>> 8) & 0xf;
2388 SAL_INFO("cppcanvas.emf", "EMF+ SetClipRegion");
2389 SAL_INFO("cppcanvas.emf", "EMF+\tregion in slot: " << (flags
& 0xff) << " combine mode: " << combineMode
);
2390 EMFPRegion
*region
= static_cast<EMFPRegion
*>(aObjects
[flags
& 0xff]);
2393 if (region
&& region
->parts
== 0 && region
->initialState
== EmfPlusRegionInitialStateInfinite
) {
2394 updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms
, combineMode
== 1);
2396 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2400 case EmfPlusRecordTypeDrawDriverString
: {
2401 SAL_INFO("cppcanvas.emf", "EMF+ DrawDriverString, flags: 0x" << std::hex
<< flags
<< std::dec
);
2402 sal_uInt32 brushIndexOrColor
;
2403 sal_uInt32 optionFlags
;
2404 sal_uInt32 hasMatrix
;
2405 sal_uInt32 glyphsCount
;
2407 rMF
.ReadUInt32( brushIndexOrColor
).ReadUInt32( optionFlags
).ReadUInt32( hasMatrix
).ReadUInt32( glyphsCount
);
2409 SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags
& 0x8000) ? "color" : "brush index") << " 0x" << std::hex
<< brushIndexOrColor
<< std::dec
);
2410 SAL_INFO("cppcanvas.emf", "EMF+\toption flags: 0x" << std::hex
<< optionFlags
<< std::dec
);
2411 SAL_INFO("cppcanvas.emf", "EMF+\thas matrix: " << hasMatrix
);
2412 SAL_INFO("cppcanvas.emf", "EMF+\tglyphs: " << glyphsCount
);
2414 if( ( optionFlags
& 1 ) && glyphsCount
> 0 ) {
2415 float *charsPosX
= new float[glyphsCount
];
2416 float *charsPosY
= new float[glyphsCount
];
2418 OUString text
= read_uInt16s_ToOUString(rMF
, glyphsCount
);
2420 for( sal_uInt32 i
=0; i
<glyphsCount
; i
++) {
2421 rMF
.ReadFloat( charsPosX
[i
] ).ReadFloat( charsPosY
[i
] );
2422 SAL_INFO("cppcanvas.emf", "EMF+\tglyphPosition[" << i
<< "]: " << charsPosX
[i
] << "," << charsPosY
[i
]);
2427 ReadXForm( rMF
, transform
);
2428 SAL_INFO("cppcanvas.emf", "EMF+\tmatrix: " << transform
.eM11
<< ", " << transform
.eM12
<< ", " << transform
.eM21
<< ", " << transform
.eM22
<< ", " << transform
.eDx
<< ", " << transform
.eDy
);
2431 // add the text action
2432 setFont (flags
& 0xff, rFactoryParms
, rState
);
2434 if( flags
& 0x8000 )
2435 rState
.textColor
= COLOR( brushIndexOrColor
);
2437 ::basegfx::B2DPoint
point( Map( charsPosX
[0], charsPosY
[0] ) );
2439 ActionSharedPtr
pTextAction(
2440 TextActionFactory::createTextAction(
2441 vcl::unotools::pointFromB2DPoint ( point
),
2450 rFactoryParms
.mrVDev
,
2451 rFactoryParms
.mrCanvas
,
2453 rFactoryParms
.mrParms
,
2458 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
2460 maActions
.push_back(
2463 rFactoryParms
.mrCurrActionIndex
) );
2465 rFactoryParms
.mrCurrActionIndex
+= pTextAction
->getActionCount()-1;
2471 SAL_INFO("cppcanvas.emf", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
2477 SAL_INFO("cppcanvas.emf", "EMF+ unhandled record type: " << type
);
2478 SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
2490 SAL_WARN("cppcanvas.emf", "ImplRenderer::processEMFPlus: "
2491 "size " << size
<< " > length " << length
);
2499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */