Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/drawinglayer/source/tools/emfpbrush.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <basegfx/range/b2drange.hxx>
21
#include <basegfx/range/b2drectangle.hxx>
22
#include <basegfx/polygon/b2dpolypolygontools.hxx>
23
#include <sal/log.hxx>
24
#include "emfpbrush.hxx"
25
#include "emfppath.hxx"
26
27
namespace emfplushelper
28
{
29
    EMFPBrush::EMFPBrush()
30
0
        : type(0)
31
0
        , additionalFlags(0)
32
0
        , wrapMode(0)
33
0
        , firstPointX(0.0)
34
0
        , firstPointY(0.0)
35
0
        , aWidth(0.0)
36
0
        , aHeight(0.0)
37
0
        , hasTransformation(false)
38
0
        , blendPoints(0)
39
0
        , blendFactors(nullptr)
40
0
        , colorblendPoints(0)
41
0
        , surroundColorsNumber(0)
42
0
        , hatchStyle(HatchStyleHorizontal)
43
0
    {
44
0
    }
45
46
    EMFPBrush::~EMFPBrush()
47
0
    {
48
0
    }
49
50
    static OUString BrushTypeToString(sal_uInt32 type)
51
0
    {
52
0
        switch (type)
53
0
        {
54
0
            case BrushTypeSolidColor: return u"BrushTypeSolidColor"_ustr;
55
0
            case BrushTypeHatchFill: return u"BrushTypeHatchFill"_ustr;
56
0
            case BrushTypeTextureFill: return u"BrushTypeTextureFill"_ustr;
57
0
            case BrushTypePathGradient: return u"BrushTypePathGradient"_ustr;
58
0
            case BrushTypeLinearGradient: return u"BrushTypeLinearGradient"_ustr;
59
0
        }
60
0
        return u""_ustr;
61
0
    }
62
63
    void EMFPBrush::Read(SvStream& s, EmfPlusHelperData const & rR)
64
0
    {
65
0
        sal_uInt32 header;
66
67
0
        s.ReadUInt32(header).ReadUInt32(type);
68
69
0
        SAL_INFO("drawinglayer.emf", "EMF+\t\t\tHeader: 0x" << std::hex << header);
70
0
        SAL_INFO("drawinglayer.emf", "EMF+\t\t\tType: " << BrushTypeToString(type) << "(0x" << type << ")" << std::dec);
71
72
0
        switch (type)
73
0
        {
74
0
            case BrushTypeSolidColor:
75
0
            {
76
0
                sal_uInt32 color;
77
0
                s.ReadUInt32(color);
78
79
0
                solidColor = ::Color(ColorAlpha, (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
80
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tSolid color: 0x" << std::hex << color << std::dec);
81
0
                break;
82
0
            }
83
0
            case BrushTypeHatchFill:
84
0
            {
85
0
                sal_uInt32 style;
86
0
                sal_uInt32 foregroundColor;
87
0
                sal_uInt32 backgroundColor;
88
0
                s.ReadUInt32(style);
89
0
                s.ReadUInt32(foregroundColor);
90
0
                s.ReadUInt32(backgroundColor);
91
92
0
                hatchStyle = static_cast<EmfPlusHatchStyle>(style);
93
0
                solidColor = ::Color(ColorAlpha, (foregroundColor >> 24), (foregroundColor >> 16) & 0xff, (foregroundColor >> 8) & 0xff, foregroundColor & 0xff);
94
0
                secondColor = ::Color(ColorAlpha, (backgroundColor >> 24), (backgroundColor >> 16) & 0xff, (backgroundColor >> 8) & 0xff, backgroundColor & 0xff);
95
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tHatch style: 0x" << std::hex << style);
96
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tForeground color: 0x" << solidColor.AsRGBHexString());
97
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tBackground color: 0x" << secondColor.AsRGBHexString());
98
0
                break;
99
0
            }
100
0
            case BrushTypeTextureFill:
101
0
            {
102
0
                SAL_WARN("drawinglayer.emf", "EMF+\tTODO: implement BrushTypeTextureFill brush");
103
0
                break;
104
0
            }
105
0
            case BrushTypePathGradient:
106
0
            {
107
0
                s.ReadUInt32(additionalFlags).ReadInt32(wrapMode);
108
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tAdditional flags: 0x" << std::hex << additionalFlags << std::dec);
109
0
                sal_uInt32 color;
110
0
                s.ReadUInt32(color);
111
0
                solidColor = ::Color(ColorAlpha, (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
112
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tCenter color: 0x" << std::hex << color << std::dec);
113
0
                s.ReadFloat(firstPointX).ReadFloat(firstPointY);
114
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tCenter point: " << firstPointX << "," << firstPointY);
115
0
                s.ReadUInt32(surroundColorsNumber);
116
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\t number of surround colors: " << surroundColorsNumber);
117
118
0
                surroundColors.reset( new ::Color[surroundColorsNumber] );
119
120
0
                for (sal_uInt32 i = 0; i < surroundColorsNumber; i++)
121
0
                {
122
0
                    s.ReadUInt32(color);
123
0
                    surroundColors[i] = ::Color(ColorAlpha, (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
124
0
                    if (i == 0)
125
0
                        secondColor = surroundColors[0];
126
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tSurround color[" << i << "]: 0x" << std::hex << color << std::dec);
127
0
                }
128
129
0
                if (additionalFlags & 0x01) // BrushDataPath
130
0
                {
131
0
                    sal_Int32 pathLength;
132
133
0
                    s.ReadInt32(pathLength);
134
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPath length: " << pathLength);
135
136
0
                    sal_uInt64 const pos = s.Tell();
137
138
0
                    sal_uInt32 pathHeader;
139
0
                    sal_Int32 pathPoints, pathFlags;
140
0
                    s.ReadUInt32(pathHeader).ReadInt32(pathPoints).ReadInt32(pathFlags);
141
142
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPath (brush path gradient)");
143
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\t\tHeader: 0x" << std::hex << pathHeader);
144
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\t\tPoints: " << std::dec << pathPoints);
145
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\t\tAdditional flags: 0x" << std::hex << pathFlags << std::dec);
146
147
0
                    path.reset( new EMFPPath(pathPoints) );
148
0
                    path->Read(s, pathFlags);
149
150
0
                    s.Seek(pos + pathLength);
151
152
0
                    const ::basegfx::B2DRectangle aBounds(path->GetPolygon(rR, false).getB2DRange());
153
0
                    aWidth = aBounds.getWidth();
154
0
                    aHeight = aBounds.getHeight();
155
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPolygon bounding box: " << aBounds.getMinX() << "," << aBounds.getMinY() << " "
156
0
                                                                             << aBounds.getWidth() << "x" << aBounds.getHeight());
157
0
                }
158
0
                else
159
0
                {
160
0
                    sal_Int32 boundaryPointCount;
161
0
                    s.ReadInt32(boundaryPointCount);
162
163
0
                    sal_uInt64 const pos = s.Tell();
164
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t use boundary, points: " << boundaryPointCount);
165
0
                    path.reset( new EMFPPath(boundaryPointCount) );
166
0
                    path->Read(s, 0x0);
167
168
0
                    s.Seek(pos + 8 * boundaryPointCount);
169
170
0
                    const ::basegfx::B2DRectangle aBounds(path->GetPolygon(rR, false).getB2DRange());
171
0
                    aWidth = aBounds.getWidth();
172
0
                    aHeight = aBounds.getHeight();
173
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPolygon bounding box: " << aBounds.getMinX() << "," << aBounds.getMinY() << " "
174
0
                                                                             << aBounds.getWidth() << "x" << aBounds.getHeight());
175
0
                }
176
177
0
                if (additionalFlags & 0x02) // BrushDataTransform
178
0
                {
179
0
                    EmfPlusHelperData::readXForm(s, brush_transformation);
180
0
                    hasTransformation = true;
181
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse brush transformation: " << brush_transformation);
182
0
                }
183
184
                // BrushDataPresetColors and BrushDataBlendFactorsH
185
0
                if ((additionalFlags & 0x04) && (additionalFlags & 0x08))
186
0
                {
187
0
                    SAL_WARN("drawinglayer.emf", "EMF+\t Brush must not contain both BrushDataPresetColors and BrushDataBlendFactorsH");
188
0
                    return;
189
0
                }
190
0
                if (additionalFlags & 0x08) // BrushDataBlendFactorsH
191
0
                {
192
0
                    s.ReadUInt32(blendPoints);
193
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tuse blend, points: " << blendPoints);
194
0
                    blendPositions.reset( new float[2 * blendPoints] );
195
0
                    blendFactors = blendPositions.get() + blendPoints;
196
197
0
                    for (sal_uInt32 i = 0; i < blendPoints; i++)
198
0
                    {
199
0
                        s.ReadFloat(blendPositions[i]);
200
0
                        SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tposition[" << i << "]: " << blendPositions[i]);
201
0
                    }
202
203
0
                    for (sal_uInt32 i = 0; i < blendPoints; i++)
204
0
                    {
205
0
                        s.ReadFloat(blendFactors[i]);
206
0
                        SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tFactor[" << i << "]: " << blendFactors[i]);
207
0
                    }
208
0
                }
209
210
0
                if (additionalFlags & 0x04) // BrushDataPresetColors
211
0
                {
212
0
                    s.ReadUInt32(colorblendPoints);
213
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse color blend, points: " << colorblendPoints);
214
0
                    colorblendPositions.reset( new float[colorblendPoints] );
215
0
                    colorblendColors.reset( new ::Color[colorblendPoints] );
216
217
0
                    for (sal_uInt32 i = 0; i < colorblendPoints; i++)
218
0
                    {
219
0
                        s.ReadFloat(colorblendPositions[i]);
220
0
                        SAL_INFO("drawinglayer.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions[i]);
221
0
                    }
222
223
0
                    for (sal_uInt32 i = 0; i < colorblendPoints; i++)
224
0
                    {
225
0
                        s.ReadUInt32(color);
226
0
                        colorblendColors[i] = ::Color(ColorAlpha, (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
227
0
                        SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tColor[" << i << "]: 0x" << std::hex << color << std::dec);
228
0
                    }
229
0
                }
230
231
0
                break;
232
0
            }
233
0
            case BrushTypeLinearGradient:
234
0
            {
235
0
                s.ReadUInt32(additionalFlags).ReadInt32(wrapMode);
236
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tLinear gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec << ", wrapMode: " << wrapMode);
237
0
                s.ReadFloat(firstPointX).ReadFloat(firstPointY).ReadFloat(aWidth).ReadFloat(aHeight);
238
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tFirst gradient point: " << firstPointX << ":" << firstPointY
239
0
                                         << ", size " << aWidth << "x" << aHeight);
240
0
                sal_uInt32 color;
241
0
                s.ReadUInt32(color);
242
0
                solidColor = ::Color(ColorAlpha, (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
243
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tfirst color: 0x" << std::hex << color << std::dec);
244
0
                s.ReadUInt32(color);
245
0
                secondColor = ::Color(ColorAlpha, (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
246
0
                SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tsecond color: 0x" << std::hex << color << std::dec);
247
248
                // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
249
0
                s.ReadUInt32(color);
250
0
                s.ReadUInt32(color);
251
252
0
                if (additionalFlags & 0x02) //BrushDataTransform
253
0
                {
254
0
                    EmfPlusHelperData::readXForm(s, brush_transformation);
255
0
                    hasTransformation = true;
256
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse brush transformation: " << brush_transformation);
257
0
                }
258
                // BrushDataPresetColors and BrushDataBlendFactorsH
259
0
                if ((additionalFlags & 0x04) && (additionalFlags & 0x08))
260
0
                {
261
0
                    SAL_WARN("drawinglayer.emf", "EMF+\t Brush must not contain both BrushDataPresetColors and BrushDataBlendFactorsH");
262
0
                    return;
263
0
                }
264
265
0
                if (additionalFlags & 0x08) // BrushDataBlendFactorsH
266
0
                {
267
0
                    s.ReadUInt32(blendPoints);
268
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse blend, points: " << blendPoints);
269
0
                    blendPositions.reset( new float[2 * blendPoints] );
270
0
                    blendFactors = blendPositions.get() + blendPoints;
271
272
0
                    for (sal_uInt32 i = 0; i < blendPoints; i++)
273
0
                    {
274
0
                        s.ReadFloat(blendPositions[i]);
275
0
                        SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPosition[" << i << "]: " << blendPositions[i]);
276
0
                    }
277
278
0
                    for (sal_uInt32 i = 0; i < blendPoints; i++)
279
0
                    {
280
0
                        s.ReadFloat(blendFactors[i]);
281
0
                        SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tFactor[" << i << "]: " << blendFactors[i]);
282
0
                    }
283
0
                }
284
285
0
                if (additionalFlags & 0x04)
286
0
                {
287
0
                    s.ReadUInt32(colorblendPoints);
288
0
                    SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tUse color blend, points: " << colorblendPoints);
289
0
                    colorblendPositions.reset( new float[colorblendPoints] );
290
0
                    colorblendColors.reset( new ::Color[colorblendPoints] );
291
292
0
                    for (sal_uInt32 i = 0; i < colorblendPoints; i++)
293
0
                    {
294
0
                        s.ReadFloat(colorblendPositions[i]);
295
0
                        SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tPosition[" << i << "]: " << colorblendPositions[i]);
296
0
                    }
297
298
0
                    for (sal_uInt32 i = 0; i < colorblendPoints; i++)
299
0
                    {
300
0
                        s.ReadUInt32(color);
301
0
                        colorblendColors[i] = ::Color(ColorAlpha, (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
302
0
                        SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tColor[" << i << "]: 0x" << std::hex << color << std::dec);
303
0
                    }
304
0
                }
305
306
0
                break;
307
0
            }
308
0
            default:
309
0
            {
310
0
                SAL_WARN("drawinglayer.emf", "EMF+\tunhandled brush type: " << std::hex << type << std::dec);
311
0
            }
312
0
        }
313
0
    }
314
}
315
316
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */