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", "EMF+\t\t\tHeader: 0x" << std::hex
<< header
);
71 SAL_INFO("drawinglayer.emf", "EMF+\t\t\tType: " << BrushTypeToString(type
) << "(0x" << type
<< ")" << std::dec
);
75 case BrushTypeSolidColor
:
80 solidColor
= ::Color(ColorAlpha
, (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
81 SAL_INFO("drawinglayer.emf", "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(ColorAlpha
, (foregroundColor
>> 24), (foregroundColor
>> 16) & 0xff, (foregroundColor
>> 8) & 0xff, foregroundColor
& 0xff);
95 secondColor
= ::Color(ColorAlpha
, (backgroundColor
>> 24), (backgroundColor
>> 16) & 0xff, (backgroundColor
>> 8) & 0xff, backgroundColor
& 0xff);
96 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tHatch style: 0x" << std::hex
<< style
);
97 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tForeground color: 0x" << solidColor
.AsRGBHexString());
98 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tBackground color: 0x" << secondColor
.AsRGBHexString());
101 case BrushTypeTextureFill
:
103 SAL_WARN("drawinglayer.emf", "EMF+\tTODO: implement BrushTypeTextureFill brush");
106 case BrushTypePathGradient
:
108 s
.ReadUInt32(additionalFlags
).ReadInt32(wrapMode
);
109 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tAdditional flags: 0x" << std::hex
<< additionalFlags
<< std::dec
);
112 solidColor
= ::Color(ColorAlpha
, (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
113 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tCenter color: 0x" << std::hex
<< color
<< std::dec
);
114 s
.ReadFloat(firstPointX
).ReadFloat(firstPointY
);
115 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tCenter point: " << firstPointX
<< "," << firstPointY
);
116 s
.ReadUInt32(surroundColorsNumber
);
117 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\t number of surround colors: " << surroundColorsNumber
);
119 surroundColors
.reset( new ::Color
[surroundColorsNumber
] );
121 for (sal_uInt32 i
= 0; i
< surroundColorsNumber
; i
++)
124 surroundColors
[i
] = ::Color(ColorAlpha
, (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
126 secondColor
= surroundColors
[0];
127 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tSurround color[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
130 if (additionalFlags
& 0x01) // BrushDataPath
132 sal_Int32 pathLength
;
134 s
.ReadInt32(pathLength
);
135 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPath length: " << pathLength
);
137 sal_uInt64
const pos
= s
.Tell();
139 sal_uInt32 pathHeader
;
140 sal_Int32 pathPoints
, pathFlags
;
141 s
.ReadUInt32(pathHeader
).ReadInt32(pathPoints
).ReadInt32(pathFlags
);
143 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPath (brush path gradient)");
144 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\t\tHeader: 0x" << std::hex
<< pathHeader
);
145 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\t\tPoints: " << std::dec
<< pathPoints
);
146 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\t\tAdditional flags: 0x" << std::hex
<< pathFlags
<< std::dec
);
148 path
.reset( new EMFPPath(pathPoints
) );
149 path
->Read(s
, pathFlags
);
151 s
.Seek(pos
+ pathLength
);
153 const ::basegfx::B2DRectangle
aBounds(::basegfx::utils::getRange(path
->GetPolygon(rR
, false)));
154 aWidth
= aBounds
.getWidth();
155 aHeight
= aBounds
.getHeight();
156 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPolygon bounding box: " << aBounds
.getMinX() << "," << aBounds
.getMinY() << " "
157 << aBounds
.getWidth() << "x" << aBounds
.getHeight());
161 sal_Int32 boundaryPointCount
;
162 s
.ReadInt32(boundaryPointCount
);
164 sal_uInt64
const pos
= s
.Tell();
165 SAL_INFO("drawinglayer.emf", "EMF+\t use boundary, points: " << boundaryPointCount
);
166 path
.reset( new EMFPPath(boundaryPointCount
) );
169 s
.Seek(pos
+ 8 * boundaryPointCount
);
171 const ::basegfx::B2DRectangle
aBounds(::basegfx::utils::getRange(path
->GetPolygon(rR
, false)));
172 aWidth
= aBounds
.getWidth();
173 aHeight
= aBounds
.getHeight();
174 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPolygon bounding box: " << aBounds
.getMinX() << "," << aBounds
.getMinY() << " "
175 << aBounds
.getWidth() << "x" << aBounds
.getHeight());
178 if (additionalFlags
& 0x02) // BrushDataTransform
180 EmfPlusHelperData::readXForm(s
, brush_transformation
);
181 hasTransformation
= true;
182 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse brush transformation: " << brush_transformation
);
185 // BrushDataPresetColors and BrushDataBlendFactorsH
186 if ((additionalFlags
& 0x04) && (additionalFlags
& 0x08))
188 SAL_WARN("drawinglayer.emf", "EMF+\t Brush must not contain both BrushDataPresetColors and BrushDataBlendFactorsH");
191 if (additionalFlags
& 0x08) // BrushDataBlendFactorsH
193 s
.ReadUInt32(blendPoints
);
194 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tuse blend, points: " << blendPoints
);
195 blendPositions
.reset( new float[2 * blendPoints
] );
196 blendFactors
= blendPositions
.get() + blendPoints
;
198 for (sal_uInt32 i
= 0; i
< blendPoints
; i
++)
200 s
.ReadFloat(blendPositions
[i
]);
201 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tposition[" << i
<< "]: " << blendPositions
[i
]);
204 for (sal_uInt32 i
= 0; i
< blendPoints
; i
++)
206 s
.ReadFloat(blendFactors
[i
]);
207 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tFactor[" << i
<< "]: " << blendFactors
[i
]);
211 if (additionalFlags
& 0x04) // BrushDataPresetColors
213 s
.ReadUInt32(colorblendPoints
);
214 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse color blend, points: " << colorblendPoints
);
215 colorblendPositions
.reset( new float[colorblendPoints
] );
216 colorblendColors
.reset( new ::Color
[colorblendPoints
] );
218 for (sal_uInt32 i
= 0; i
< colorblendPoints
; i
++)
220 s
.ReadFloat(colorblendPositions
[i
]);
221 SAL_INFO("drawinglayer.emf", "EMF+\tposition[" << i
<< "]: " << colorblendPositions
[i
]);
224 for (sal_uInt32 i
= 0; i
< colorblendPoints
; i
++)
227 colorblendColors
[i
] = ::Color(ColorAlpha
, (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
228 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tColor[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
234 case BrushTypeLinearGradient
:
236 s
.ReadUInt32(additionalFlags
).ReadInt32(wrapMode
);
237 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tLinear gradient, additional flags: 0x" << std::hex
<< additionalFlags
<< std::dec
<< ", wrapMode: " << wrapMode
);
238 s
.ReadFloat(firstPointX
).ReadFloat(firstPointY
).ReadFloat(aWidth
).ReadFloat(aHeight
);
239 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tFirst gradient point: " << firstPointX
<< ":" << firstPointY
240 << ", size " << aWidth
<< "x" << aHeight
);
243 solidColor
= ::Color(ColorAlpha
, (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
244 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tfirst color: 0x" << std::hex
<< color
<< std::dec
);
246 secondColor
= ::Color(ColorAlpha
, (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
247 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tsecond color: 0x" << std::hex
<< color
<< std::dec
);
249 // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
253 if (additionalFlags
& 0x02) //BrushDataTransform
255 EmfPlusHelperData::readXForm(s
, brush_transformation
);
256 hasTransformation
= true;
257 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse brush transformation: " << brush_transformation
);
259 // BrushDataPresetColors and BrushDataBlendFactorsH
260 if ((additionalFlags
& 0x04) && (additionalFlags
& 0x08))
262 SAL_WARN("drawinglayer.emf", "EMF+\t Brush must not contain both BrushDataPresetColors and BrushDataBlendFactorsH");
266 if (additionalFlags
& 0x08) // BrushDataBlendFactorsH
268 s
.ReadUInt32(blendPoints
);
269 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse blend, points: " << blendPoints
);
270 blendPositions
.reset( new float[2 * blendPoints
] );
271 blendFactors
= blendPositions
.get() + blendPoints
;
273 for (sal_uInt32 i
= 0; i
< blendPoints
; i
++)
275 s
.ReadFloat(blendPositions
[i
]);
276 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPosition[" << i
<< "]: " << blendPositions
[i
]);
279 for (sal_uInt32 i
= 0; i
< blendPoints
; i
++)
281 s
.ReadFloat(blendFactors
[i
]);
282 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tFactor[" << i
<< "]: " << blendFactors
[i
]);
286 if (additionalFlags
& 0x04)
288 s
.ReadUInt32(colorblendPoints
);
289 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse color blend, points: " << colorblendPoints
);
290 colorblendPositions
.reset( new float[colorblendPoints
] );
291 colorblendColors
.reset( new ::Color
[colorblendPoints
] );
293 for (sal_uInt32 i
= 0; i
< colorblendPoints
; i
++)
295 s
.ReadFloat(colorblendPositions
[i
]);
296 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPosition[" << i
<< "]: " << colorblendPositions
[i
]);
299 for (sal_uInt32 i
= 0; i
< colorblendPoints
; i
++)
302 colorblendColors
[i
] = ::Color(ColorAlpha
, (color
>> 24), (color
>> 16) & 0xff, (color
>> 8) & 0xff, color
& 0xff);
303 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tColor[" << i
<< "]: 0x" << std::hex
<< color
<< std::dec
);
311 SAL_WARN("drawinglayer.emf", "EMF+\tunhandled brush type: " << std::hex
<< type
<< std::dec
);
317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */