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 <basegfx/range/b2drange.hxx>
21 #include <basegfx/range/b2drectangle.hxx>
22 #include <basegfx/polygon/b2dpolypolygontools.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <sal/log.hxx>
25 #include "emfpbrush.hxx"
26 #include "emfppath.hxx"
28 namespace emfplushelper
30 EMFPBrush::EMFPBrush()
38 , hasTransformation(false)
40 , blendFactors(nullptr)
42 , surroundColorsNumber(0)
43 , hatchStyle(HatchStyleHorizontal
)
47 EMFPBrush::~EMFPBrush()
51 static OUString
BrushTypeToString(sal_uInt32 type
)
55 case BrushTypeSolidColor
: return "BrushTypeSolidColor";
56 case BrushTypeHatchFill
: return "BrushTypeHatchFill";
57 case BrushTypeTextureFill
: return "BrushTypeTextureFill";
58 case BrushTypePathGradient
: return "BrushTypePathGradient";
59 case BrushTypeLinearGradient
: return "BrushTypeLinearGradient";
64 void EMFPBrush::Read(SvStream
& s
, EmfPlusHelperData
const & rR
)
68 s
.ReadUInt32(header
).ReadUInt32(type
);
70 SAL_INFO("drawinglayer", "EMF+\t\t\tHeader: 0x" << std::hex
<< header
);
71 SAL_INFO("drawinglayer", "EMF+\t\t\tType: " << BrushTypeToString(type
) << "(0x" << type
<< ")" << std::dec
);
75 case BrushTypeSolidColor
:
80 solidColor
= ::Color(0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
81 SAL_INFO("drawinglayer", "EMF+\t\t\t\tSolid color: 0x" << std::hex
<< color
<< std::dec
);
84 case BrushTypeHatchFill
:
87 sal_uInt32 foregroundColor
;
88 sal_uInt32 backgroundColor
;
90 s
.ReadUInt32(foregroundColor
);
91 s
.ReadUInt32(backgroundColor
);
93 hatchStyle
= static_cast<EmfPlusHatchStyle
>(style
);
94 solidColor
= ::Color(0xff - (foregroundColor
>> 24), (foregroundColor
>> 16) & 0xff, (foregroundColor
>> 8) & 0xff, foregroundColor
& 0xff);
95 secondColor
= ::Color(0xff - (backgroundColor
>> 24), (backgroundColor
>> 16) & 0xff, (backgroundColor
>> 8) & 0xff, backgroundColor
& 0xff);
96 SAL_INFO("drawinglayer", "EMF+\t\t\t\tHatch style: 0x" << std::hex
<< style
);
97 SAL_INFO("drawinglayer", "EMF+\t\t\t\tForeground color: 0x" << solidColor
.AsRGBHexString());
98 SAL_INFO("drawinglayer", "EMF+\t\t\t\tBackground color: 0x" << secondColor
.AsRGBHexString());
101 case BrushTypeTextureFill
:
103 SAL_WARN("drawinglayer", "EMF+\tTODO: implement BrushTypeTextureFill brush");
106 case BrushTypePathGradient
:
108 s
.ReadUInt32(additionalFlags
).ReadInt32(wrapMode
);
109 SAL_INFO("drawinglayer", "EMF+\t\t\t\tAdditional flags: 0x" << std::hex
<< additionalFlags
<< std::dec
);
112 solidColor
= ::Color(0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
113 SAL_INFO("drawinglayer", "EMF+\t\t\t\tCenter color: 0x" << std::hex
<< color
<< std::dec
);
114 s
.ReadFloat(firstPointX
).ReadFloat(firstPointY
);
115 SAL_INFO("drawinglayer", "EMF+\t\t\t\tCenter point: " << firstPointX
<< "," << firstPointY
);
116 s
.ReadInt32(surroundColorsNumber
);
117 SAL_INFO("drawinglayer", "EMF+\t\t\t\t number of surround colors: " << surroundColorsNumber
);
119 if (surroundColorsNumber
<0 || o3tl::make_unsigned(surroundColorsNumber
)>SAL_MAX_INT32
/ sizeof(::Color
))
121 surroundColorsNumber
= SAL_MAX_INT32
/ sizeof(::Color
);
124 surroundColors
.reset( new ::Color
[surroundColorsNumber
] );
126 for (int i
= 0; i
< surroundColorsNumber
; i
++)
129 surroundColors
[i
] = ::Color(0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
131 secondColor
= surroundColors
[0];
132 SAL_INFO("drawinglayer", "EMF+\t\t\t\tSurround color[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
135 if (additionalFlags
& 0x01)
137 sal_Int32 pathLength
;
139 s
.ReadInt32(pathLength
);
140 SAL_INFO("drawinglayer", "EMF+\t\t\t\tPath length: " << pathLength
);
142 sal_uInt64
const pos
= s
.Tell();
144 sal_uInt32 pathHeader
;
145 sal_Int32 pathPoints
, pathFlags
;
146 s
.ReadUInt32(pathHeader
).ReadInt32(pathPoints
).ReadInt32(pathFlags
);
148 SAL_INFO("drawinglayer", "EMF+\t\t\t\tPath (brush path gradient)");
149 SAL_INFO("drawinglayer", "EMF+\t\t\t\t\tHeader: 0x" << std::hex
<< pathHeader
);
150 SAL_INFO("drawinglayer", "EMF+\t\t\t\t\tPoints: " << std::dec
<< pathPoints
);
151 SAL_INFO("drawinglayer", "EMF+\t\t\t\t\tAdditional flags: 0x" << std::hex
<< pathFlags
<< std::dec
);
153 path
.reset( new EMFPPath(pathPoints
) );
154 path
->Read(s
, pathFlags
);
156 s
.Seek(pos
+ pathLength
);
158 const ::basegfx::B2DRectangle
aBounds(::basegfx::utils::getRange(path
->GetPolygon(rR
, false)));
159 aWidth
= aBounds
.getWidth();
160 aHeight
= aBounds
.getHeight();
161 SAL_INFO("drawinglayer", "EMF+\t\t\t\tPolygon bounding box: " << aBounds
.getMinX() << "," << aBounds
.getMinY() << " "
162 << aBounds
.getWidth() << "x" << aBounds
.getHeight());
166 sal_Int32 boundaryPointCount
;
167 s
.ReadInt32(boundaryPointCount
);
169 sal_uInt64
const pos
= s
.Tell();
170 SAL_INFO("drawinglayer", "EMF+\t use boundary, points: " << boundaryPointCount
);
171 path
.reset( new EMFPPath(boundaryPointCount
) );
174 s
.Seek(pos
+ 8 * boundaryPointCount
);
176 const ::basegfx::B2DRectangle
aBounds(::basegfx::utils::getRange(path
->GetPolygon(rR
, false)));
177 aWidth
= aBounds
.getWidth();
178 aHeight
= aBounds
.getHeight();
179 SAL_INFO("drawinglayer", "EMF+\t\t\t\tPolygon bounding box: " << aBounds
.getMinX() << "," << aBounds
.getMinY() << " "
180 << aBounds
.getWidth() << "x" << aBounds
.getHeight());
183 if (additionalFlags
& 0x02)
185 EmfPlusHelperData::readXForm(s
, brush_transformation
);
186 hasTransformation
= true;
187 SAL_INFO("drawinglayer", "EMF+\t\t\t\tUse brush transformation: " << brush_transformation
);
190 if (additionalFlags
& 0x08)
192 s
.ReadInt32(blendPoints
);
193 SAL_INFO("drawinglayer", "EMF+\t\t\t\tuse blend, points: " << blendPoints
);
194 if (blendPoints
<0 || o3tl::make_unsigned(blendPoints
)>SAL_MAX_INT32
/ (2 * sizeof(float)))
195 blendPoints
= SAL_MAX_INT32
/ (2 * sizeof(float));
196 blendPositions
.reset( new float[2 * blendPoints
] );
197 blendFactors
= blendPositions
.get() + blendPoints
;
199 for (int i
= 0; i
< blendPoints
; i
++)
201 s
.ReadFloat(blendPositions
[i
]);
202 SAL_INFO("drawinglayer", "EMF+\t\t\t\tposition[" << i
<< "]: " << blendPositions
[i
]);
205 for (int i
= 0; i
< blendPoints
; i
++)
207 s
.ReadFloat(blendFactors
[i
]);
208 SAL_INFO("drawinglayer", "EMF+\t\t\t\tFactor[" << i
<< "]: " << blendFactors
[i
]);
212 if (additionalFlags
& 0x04)
214 s
.ReadInt32(colorblendPoints
);
215 SAL_INFO("drawinglayer", "EMF+\t\t\t\tUse color blend, points: " << colorblendPoints
);
217 if (colorblendPoints
<0 || o3tl::make_unsigned(colorblendPoints
)>SAL_MAX_INT32
/ sizeof(float))
219 colorblendPoints
= SAL_MAX_INT32
/ sizeof(float);
222 if (o3tl::make_unsigned(colorblendPoints
) > SAL_MAX_INT32
/ sizeof(::Color
))
224 colorblendPoints
= SAL_MAX_INT32
/ sizeof(::Color
);
227 colorblendPositions
.reset( new float[colorblendPoints
] );
228 colorblendColors
.reset( new ::Color
[colorblendPoints
] );
230 for (int i
= 0; i
< colorblendPoints
; i
++)
232 s
.ReadFloat(colorblendPositions
[i
]);
233 SAL_INFO("drawinglayer", "EMF+\tposition[" << i
<< "]: " << colorblendPositions
[i
]);
236 for (int i
= 0; i
< colorblendPoints
; i
++)
239 colorblendColors
[i
] = ::Color(0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
240 SAL_INFO("drawinglayer", "EMF+\t\t\t\tColor[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
246 case BrushTypeLinearGradient
:
248 s
.ReadUInt32(additionalFlags
).ReadInt32(wrapMode
);
249 SAL_INFO("drawinglayer", "EMF+\t\t\t\tLinear gradient, additional flags: 0x" << std::hex
<< additionalFlags
<< std::dec
<< ", wrapMode: " << wrapMode
);
250 s
.ReadFloat(firstPointX
).ReadFloat(firstPointY
).ReadFloat(aWidth
).ReadFloat(aHeight
);
251 SAL_INFO("drawinglayer", "EMF+\t\t\t\tFirst gradient point: " << firstPointX
<< ":" << firstPointY
252 << ", size " << aWidth
<< "x" << aHeight
);
255 solidColor
= ::Color(0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
256 SAL_INFO("drawinglayer", "EMF+\t\t\t\tfirst color: 0x" << std::hex
<< color
<< std::dec
);
258 secondColor
= ::Color(0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
259 SAL_INFO("drawinglayer", "EMF+\t\t\t\tsecond color: 0x" << std::hex
<< color
<< std::dec
);
261 // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
265 if (additionalFlags
& 0x02)
267 EmfPlusHelperData::readXForm(s
, brush_transformation
);
268 hasTransformation
= true;
269 SAL_INFO("drawinglayer", "EMF+\t\t\t\tUse brush transformation: " << brush_transformation
);
272 if (additionalFlags
& 0x08)
274 s
.ReadInt32(blendPoints
);
275 SAL_INFO("drawinglayer", "EMF+\t\t\t\tUse blend, points: " << blendPoints
);
276 if (blendPoints
<0 || o3tl::make_unsigned(blendPoints
)>SAL_MAX_INT32
/ (2 * sizeof(float)))
277 blendPoints
= SAL_MAX_INT32
/ (2 * sizeof(float));
278 blendPositions
.reset( new float[2 * blendPoints
] );
279 blendFactors
= blendPositions
.get() + blendPoints
;
281 for (int i
= 0; i
< blendPoints
; i
++)
283 s
.ReadFloat(blendPositions
[i
]);
284 SAL_INFO("drawinglayer", "EMF+\t\t\t\tPosition[" << i
<< "]: " << blendPositions
[i
]);
287 for (int i
= 0; i
< blendPoints
; i
++)
289 s
.ReadFloat(blendFactors
[i
]);
290 SAL_INFO("drawinglayer", "EMF+\t\t\t\tFactor[" << i
<< "]: " << blendFactors
[i
]);
294 if (additionalFlags
& 0x04)
296 s
.ReadInt32(colorblendPoints
);
297 SAL_INFO("drawinglayer", "EMF+\t\t\t\tUse color blend, points: " << colorblendPoints
);
299 if (colorblendPoints
<0 || o3tl::make_unsigned(colorblendPoints
)>SAL_MAX_INT32
/ sizeof(float))
301 colorblendPoints
= SAL_MAX_INT32
/ sizeof(float);
304 if (o3tl::make_unsigned(colorblendPoints
) > SAL_MAX_INT32
/ sizeof(::Color
))
306 colorblendPoints
= sal_uInt32(SAL_MAX_INT32
) / sizeof(::Color
);
309 colorblendPositions
.reset( new float[colorblendPoints
] );
310 colorblendColors
.reset( new ::Color
[colorblendPoints
] );
312 for (int i
= 0; i
< colorblendPoints
; i
++)
314 s
.ReadFloat(colorblendPositions
[i
]);
315 SAL_INFO("drawinglayer", "EMF+\t\t\t\tPosition[" << i
<< "]: " << colorblendPositions
[i
]);
318 for (int i
= 0; i
< colorblendPoints
; i
++)
321 colorblendColors
[i
] = ::Color(0xff - (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
322 SAL_INFO("drawinglayer", "EMF+\t\t\t\tColor[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
330 SAL_WARN("drawinglayer", "EMF+\tunhandled brush type: " << std::hex
<< type
<< std::dec
);
336 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */