LibreOffice Module drawinglayer (master) 1
emfppen.cxx
Go to the documentation of this file.
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 <com/sun/star/rendering/PathCapType.hpp>
21#include <o3tl/safeint.hxx>
22#include <sal/log.hxx>
23#include <rtl/ustrbuf.hxx>
24
25#include "emfppen.hxx"
26#include "emfpcustomlinecap.hxx"
27
28using namespace ::com::sun::star;
29using namespace ::basegfx;
30
31namespace emfplushelper
32{
33
35 : penDataFlags(0)
36 , penUnit(0)
37 , penWidth(0.0)
38 , startCap(0)
39 , endCap(0)
40 , maLineJoin(basegfx::B2DLineJoin::Miter)
41 , fMiterMinimumAngle(basegfx::deg2rad(5.0))
42 , dashStyle(0)
43 , dashCap(0)
44 , dashOffset(0.0)
45 , alignment(0)
46 , customStartCapLen(0)
47 , customEndCapLen(0)
48 {
49 }
50
52 {
53 }
54
55 static OUString PenDataFlagsToString(sal_uInt32 flags)
56 {
57 rtl::OUStringBuffer sFlags;
58
59 if (flags & EmfPlusPenDataTransform)
60 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataTransform");
61
62 if (flags & EmfPlusPenDataStartCap)
63 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataStartCap");
64
65 if (flags & EmfPlusPenDataEndCap)
66 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataEndCap");
67
68 if (flags & EmfPlusPenDataJoin)
69 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataJoin");
70
71 if (flags & EmfPlusPenDataMiterLimit)
72 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataMiterLimit");
73
74 if (flags & EmfPlusPenDataLineStyle)
75 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataLineStyle");
76
78 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLineCap");
79
81 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLineOffset");
82
83 if (flags & EmfPlusPenDataDashedLine)
84 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLine");
85
86 if (flags & EmfPlusPenDataAlignment)
87 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataAlignment");
88
90 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCompoundLine");
91
93 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCustomStartCap");
94
96 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCustomEndCap");
97
98 return sFlags.makeStringAndClear();
99 }
100
101 static OUString LineCapTypeToString(sal_uInt32 linecap)
102 {
103 switch (linecap)
104 {
105 case LineCapTypeFlat: return "LineCapTypeFlat";
106 case LineCapTypeSquare: return "LineCapTypeSquare";
107 case LineCapTypeRound: return "LineCapTypeRound";
108 case LineCapTypeTriangle: return "LineCapTypeTriangle";
109 case LineCapTypeNoAnchor: return "LineCapTypeNoAnchor";
110 case LineCapTypeSquareAnchor: return "LineCapTypeSquareAnchor";
111 case LineCapTypeRoundAnchor: return "LineCapTypeRoundAchor";
112 case LineCapTypeDiamondAnchor: return "LineCapTypeDiamondAnchor";
113 case LineCapTypeArrowAnchor: return "LineCapTypeArrowAnchor";
114 case LineCapTypeAnchorMask: return "LineCapTypeAnchorMask";
115 case LineCapTypeCustom: return "LineCapTypeCustom";
116 }
117 return "";
118 }
119
120 static OUString DashedLineCapTypeToString(sal_uInt32 dashedlinecaptype)
121 {
122 switch (dashedlinecaptype)
123 {
124 case DashedLineCapTypeFlat: return "DashedLineCapTypeFlat";
125 case DashedLineCapTypeRound: return "DashedLineCapTypeRound";
126 case DashedLineCapTypeTriangle: return "DashedLineCapTypeTriangle";
127 }
128 return "";
129 }
130
131 static OUString PenAlignmentToString(sal_uInt32 alignment)
132 {
133 switch (alignment)
134 {
135 case PenAlignmentCenter: return "PenAlignmentCenter";
136 case PenAlignmentInset: return "PenAlignmentInset";
137 case PenAlignmentLeft: return "PenAlignmentLeft";
138 case PenAlignmentOutset: return "PenAlignmentOutset";
139 case PenAlignmentRight: return "PenAlignmentRight";
140 }
141 return "";
142 }
143
145 EMFPPen::GetStrokeAttribute(const double aTransformation) const
146 {
147 if (penDataFlags & EmfPlusPenDataLineStyle // pen has a predefined line style
149 {
150 const double pw = aTransformation * penWidth;
151 switch (dashStyle)
152 {
154 // [-loplugin:redundantfcast] false positive:
155 return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw });
157 // [-loplugin:redundantfcast] false positive:
160 // [-loplugin:redundantfcast] false positive:
161 return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw, pw, pw });
163 // [-loplugin:redundantfcast] false positive:
164 return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw, pw, pw, pw, pw });
165 }
166 }
167 else if (penDataFlags & EmfPlusPenDataDashedLine) // pen has a custom dash line
168 {
169 const double pw = aTransformation * penWidth;
170 // StrokeAttribute needs a double vector while the pen provides a float vector
171 std::vector<double> aPattern(dashPattern.size());
172 for (size_t i = 0; i < aPattern.size(); i++)
173 {
174 // convert from float to double and multiply with the adjusted pen width
175 aPattern[i] = pw * dashPattern[i];
176 }
177 return drawinglayer::attribute::StrokeAttribute(std::move(aPattern));
178 }
179 // EmfPlusLineStyleSolid: - do nothing special, use default stroke attribute
181 }
182
184 {
185 sal_Int32 lineJoin = EmfPlusLineJoinTypeMiter;
186 sal_uInt32 graphicsVersion, penType;
188 SAL_INFO("drawinglayer.emf", "EMF+\t\tGraphics version: 0x" << std::hex << graphicsVersion);
189 SAL_INFO("drawinglayer.emf", "EMF+\t\tType: " << penType);
190 SAL_INFO("drawinglayer.emf", "EMF+\t\tPen data flags: 0x" << penDataFlags << PenDataFlagsToString(penDataFlags));
191 SAL_INFO("drawinglayer.emf", "EMF+\t\tUnit: " << UnitTypeToString(penUnit));
192 SAL_INFO("drawinglayer.emf", "EMF+\t\tWidth: " << std::dec << penWidth);
193
194 // If a zero width is specified, a minimum value must be used, which is determined by the units
195 if (penWidth == 0.0)
196 { //TODO Check if these values is correct
197 penWidth = penUnit == 0 ? 0.18f
198 : 0.05f; // 0.05f is taken from old EMF+ implementation (case of Unit == Pixel etc.)
199 }
200
202 {
204 SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataTransform: " << pen_transformation);
205 }
206
208 {
210 SAL_INFO("drawinglayer.emf", "EMF+\t\tstartCap: " << LineCapTypeToString(startCap) << " (0x" << std::hex << startCap << ")");
211 }
212 else
213 {
214 startCap = 0;
215 }
216
218 {
219 s.ReadInt32(endCap);
220 SAL_INFO("drawinglayer.emf", "EMF+\t\tendCap: " << LineCapTypeToString(endCap) << " (0x" << std::hex << startCap << ")");
221 }
222 else
223 {
224 endCap = 0;
225 }
226
228 {
229 s.ReadInt32(lineJoin);
230 SAL_INFO("drawinglayer.emf", "EMF+\t\t LineJoin: " << lineJoin);
231 switch (lineJoin)
232 {
235 break;
238 break;
241 default: // If nothing set, then apply Miter (based on MS Paint)
243 break;
244 }
245 }
246 else
248
250 {
251 float miterLimit;
252 s.ReadFloat(miterLimit);
253
254 // EMF+ JoinTypeMiterClipped is working as our B2DLineJoin::Miter
255 // For EMF+ LineJoinTypeMiter we are simulating it by changing angle
256 if (lineJoin == EmfPlusLineJoinTypeMiter)
257 miterLimit = 3.0 * miterLimit;
258 // asin angle must be in range [-1, 1]
259 if (abs(miterLimit) > 1.0)
260 fMiterMinimumAngle = 2.0 * asin(1.0 / miterLimit);
261 else
262 // enable miter limit for all angles
264 SAL_INFO("drawinglayer.emf",
265 "EMF+\t\t MiterLimit: " << std::dec << miterLimit
266 << ", Miter minimum angle (rad): " << fMiterMinimumAngle);
267 }
268 else
270
271
273 {
275 SAL_INFO("drawinglayer.emf", "EMF+\t\tdashStyle: " << DashedLineCapTypeToString(dashStyle) << " (0x" << std::hex << dashStyle << ")");
276 }
277 else
278 {
279 dashStyle = 0;
280 }
281
283 {
285 SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataDashedLineCap: 0x" << std::hex << dashCap);
286 }
287 else
288 {
289 dashCap = 0;
290 }
291
293 {
295 SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataDashedLineOffset: 0x" << std::hex << dashOffset);
296 }
297 else
298 {
299 dashOffset = 0;
300 }
301
303 {
305 sal_uInt32 dashPatternLen;
306
307 s.ReadUInt32(dashPatternLen);
308 SAL_INFO("drawinglayer.emf", "EMF+\t\t\tdashPatternLen: " << dashPatternLen);
309
310 dashPattern.resize( dashPatternLen );
311
312 for (sal_uInt32 i = 0; i < dashPatternLen; i++)
313 {
315 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tdashPattern[" << i << "]: " << dashPattern[i]);
316 }
317 }
318
320 {
322 SAL_WARN("drawinglayer.emf", "EMF+\t\t\tTODO PenDataAlignment: " << PenAlignmentToString(alignment) << " (0x" << std::hex << alignment << ")");
323 }
324 else
325 {
326 alignment = 0;
327 }
328
330 {
331 SAL_WARN("drawinglayer.emf", "EMF+\t\t\tTODO PenDataCompoundLine");
332 sal_uInt32 compoundArrayLen;
333 s.ReadUInt32(compoundArrayLen);
334
335 compoundArray.resize(compoundArrayLen);
336
337 for (sal_uInt32 i = 0; i < compoundArrayLen; i++)
338 {
340 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tcompoundArray[" << i << "]: " << compoundArray[i]);
341 }
342 }
343
345 {
347 SAL_INFO("drawinglayer.emf", "EMF+\t\t\tcustomStartCapLen: " << customStartCapLen);
348 sal_uInt64 const pos = s.Tell();
349
350 customStartCap.reset( new EMFPCustomLineCap() );
351 customStartCap->Read(s, rR);
352
353 // maybe we don't read everything yet, play it safe ;-)
355 }
356 else
357 {
359 }
360
362 {
364 SAL_INFO("drawinglayer.emf", "EMF+\t\t\tcustomEndCapLen: " << customEndCapLen);
365 sal_uInt64 const pos = s.Tell();
366
367 customEndCap.reset( new EMFPCustomLineCap() );
368 customEndCap->Read(s, rR);
369
370 // maybe we don't read everything yet, play it safe ;-)
372 }
373 else
374 {
375 customEndCapLen = 0;
376 }
377
378 EMFPBrush::Read(s, rR);
379 }
380}
381
382/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt64 Tell() const
SvStream & ReadFloat(float &rFloat)
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
sal_uInt64 Seek(sal_uInt64 nPos)
SvStream & ReadInt32(sal_Int32 &rInt32)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
B2DLineJoin
constexpr double deg2rad(double v)
const sal_Int32 EmfPlusLineStyleCustom
Definition: emfppen.hxx:42
const sal_uInt32 EmfPlusPenDataCompoundLine
Definition: emfppen.hxx:54
@ DashedLineCapTypeRound
Definition: emfppen.hxx:84
@ DashedLineCapTypeTriangle
Definition: emfppen.hxx:85
@ DashedLineCapTypeFlat
Definition: emfppen.hxx:83
OUString UnitTypeToString(sal_uInt16 nType)
const sal_uInt32 EmfPlusPenDataCustomStartCap
Definition: emfppen.hxx:55
const sal_uInt32 EmfPlusPenDataDashedLineOffset
Definition: emfppen.hxx:51
const sal_uInt32 EmfPlusPenDataTransform
Definition: emfppen.hxx:44
const sal_uInt32 EmfPlusPenDataDashedLine
Definition: emfppen.hxx:52
const sal_uInt32 EmfPlusLineJoinTypeRound
Definition: emfppen.hxx:34
const sal_Int32 EmfPlusLineStyleDash
Definition: emfppen.hxx:38
const sal_uInt32 EmfPlusPenDataEndCap
Definition: emfppen.hxx:46
const sal_uInt32 EmfPlusLineJoinTypeMiter
Definition: emfppen.hxx:32
const sal_uInt32 EmfPlusLineJoinTypeBevel
Definition: emfppen.hxx:33
const sal_uInt32 EmfPlusPenDataDashedLineCap
Definition: emfppen.hxx:50
@ LineCapTypeRound
Definition: emfppen.hxx:62
@ LineCapTypeSquareAnchor
Definition: emfppen.hxx:65
@ LineCapTypeSquare
Definition: emfppen.hxx:61
@ LineCapTypeTriangle
Definition: emfppen.hxx:63
@ LineCapTypeCustom
Definition: emfppen.hxx:70
@ LineCapTypeAnchorMask
Definition: emfppen.hxx:69
@ LineCapTypeDiamondAnchor
Definition: emfppen.hxx:67
@ LineCapTypeArrowAnchor
Definition: emfppen.hxx:68
@ LineCapTypeNoAnchor
Definition: emfppen.hxx:64
@ LineCapTypeRoundAnchor
Definition: emfppen.hxx:66
const sal_uInt32 EmfPlusPenDataStartCap
Definition: emfppen.hxx:45
const sal_uInt32 EmfPlusLineJoinTypeMiterClipped
Definition: emfppen.hxx:35
static OUString PenAlignmentToString(sal_uInt32 alignment)
Definition: emfppen.cxx:131
static OUString PenDataFlagsToString(sal_uInt32 flags)
Definition: emfppen.cxx:55
const sal_Int32 EmfPlusLineStyleDot
Definition: emfppen.hxx:39
const sal_uInt32 EmfPlusPenDataMiterLimit
Definition: emfppen.hxx:48
const sal_uInt32 EmfPlusPenDataJoin
Definition: emfppen.hxx:47
const sal_Int32 EmfPlusLineStyleDashDot
Definition: emfppen.hxx:40
const sal_uInt32 EmfPlusPenDataLineStyle
Definition: emfppen.hxx:49
const sal_uInt32 EmfPlusPenDataAlignment
Definition: emfppen.hxx:53
static OUString DashedLineCapTypeToString(sal_uInt32 dashedlinecaptype)
Definition: emfppen.cxx:120
const sal_uInt32 EmfPlusPenDataCustomEndCap
Definition: emfppen.hxx:56
const sal_Int32 EmfPlusLineStyleDashDotDot
Definition: emfppen.hxx:41
static OUString LineCapTypeToString(sal_uInt32 linecap)
Definition: emfppen.cxx:101
@ PenAlignmentRight
Definition: emfppen.hxx:94
@ PenAlignmentLeft
Definition: emfppen.hxx:92
@ PenAlignmentInset
Definition: emfppen.hxx:91
@ PenAlignmentCenter
Definition: emfppen.hxx:90
@ PenAlignmentOutset
Definition: emfppen.hxx:93
int i
SwNodeOffset abs(const SwNodeOffset &a)
void Read(SvStream &s, EmfPlusHelperData const &rR)
Definition: emfpbrush.cxx:64
virtual ~EMFPPen() override
Definition: emfppen.cxx:51
sal_uInt32 customStartCapLen
Definition: emfppen.hxx:115
sal_uInt32 customEndCapLen
Definition: emfppen.hxx:117
basegfx::B2DLineJoin maLineJoin
Definition: emfppen.hxx:107
std::unique_ptr< EMFPCustomLineCap > customEndCap
Definition: emfppen.hxx:118
std::unique_ptr< EMFPCustomLineCap > customStartCap
Definition: emfppen.hxx:116
std::vector< float > compoundArray
Definition: emfppen.hxx:114
void Read(SvStream &s, EmfPlusHelperData const &rR)
Definition: emfppen.cxx:183
sal_uInt32 penDataFlags
Definition: emfppen.hxx:102
std::vector< float > dashPattern
Definition: emfppen.hxx:112
drawinglayer::attribute::StrokeAttribute GetStrokeAttribute(const double aTransformation) const
Definition: emfppen.cxx:145
basegfx::B2DHomMatrix pen_transformation
Definition: emfppen.hxx:101
static bool readXForm(SvStream &rIn, basegfx::B2DHomMatrix &rTarget)
size_t pos