calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / drawinglayer / source / tools / emfppen.cxx
blobadfee3bd3706234d5657e391b359bcf4307a5e5d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <com/sun/star/rendering/PathCapType.hpp>
21 #include <o3tl/safeint.hxx>
22 #include <sal/log.hxx>
23 #include <rtl/ustrbuf.hxx>
25 #include "emfppen.hxx"
26 #include "emfpcustomlinecap.hxx"
28 using namespace ::com::sun::star;
29 using namespace ::basegfx;
31 namespace emfplushelper
34 EMFPPen::EMFPPen()
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)
51 EMFPPen::~EMFPPen()
55 static OUString PenDataFlagsToString(sal_uInt32 flags)
57 rtl::OUStringBuffer sFlags;
59 if (flags & EmfPlusPenDataTransform)
60 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataTransform");
62 if (flags & EmfPlusPenDataStartCap)
63 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataStartCap");
65 if (flags & EmfPlusPenDataEndCap)
66 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataEndCap");
68 if (flags & EmfPlusPenDataJoin)
69 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataJoin");
71 if (flags & EmfPlusPenDataMiterLimit)
72 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataMiterLimit");
74 if (flags & EmfPlusPenDataLineStyle)
75 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataLineStyle");
77 if (flags & EmfPlusPenDataDashedLineCap)
78 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLineCap");
80 if (flags & EmfPlusPenDataDashedLineOffset)
81 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLineOffset");
83 if (flags & EmfPlusPenDataDashedLine)
84 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLine");
86 if (flags & EmfPlusPenDataAlignment)
87 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataAlignment");
89 if (flags & EmfPlusPenDataCompoundLine)
90 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCompoundLine");
92 if (flags & EmfPlusPenDataCustomStartCap)
93 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCustomStartCap");
95 if (flags & EmfPlusPenDataCustomEndCap)
96 sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCustomEndCap");
98 return sFlags.makeStringAndClear();
101 static OUString LineCapTypeToString(sal_uInt32 linecap)
103 switch (linecap)
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";
117 return "";
120 static OUString DashedLineCapTypeToString(sal_uInt32 dashedlinecaptype)
122 switch (dashedlinecaptype)
124 case DashedLineCapTypeFlat: return "DashedLineCapTypeFlat";
125 case DashedLineCapTypeRound: return "DashedLineCapTypeRound";
126 case DashedLineCapTypeTriangle: return "DashedLineCapTypeTriangle";
128 return "";
131 static OUString PenAlignmentToString(sal_uInt32 alignment)
133 switch (alignment)
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";
141 return "";
144 drawinglayer::attribute::StrokeAttribute
145 EMFPPen::GetStrokeAttribute(const double aTransformation) const
147 if (penDataFlags & EmfPlusPenDataLineStyle // pen has a predefined line style
148 && dashStyle != EmfPlusLineStyleCustom)
150 const double pw = aTransformation * penWidth;
151 switch (dashStyle)
153 case EmfPlusLineStyleDash:
154 // [-loplugin:redundantfcast] false positive:
155 return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw });
156 case EmfPlusLineStyleDot:
157 // [-loplugin:redundantfcast] false positive:
158 return drawinglayer::attribute::StrokeAttribute({ pw, pw });
159 case EmfPlusLineStyleDashDot:
160 // [-loplugin:redundantfcast] false positive:
161 return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw, pw, pw });
162 case EmfPlusLineStyleDashDotDot:
163 // [-loplugin:redundantfcast] false positive:
164 return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw, pw, pw, pw, pw });
167 else if (penDataFlags & EmfPlusPenDataDashedLine) // pen has a custom dash line
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++)
174 // convert from float to double and multiply with the adjusted pen width
175 aPattern[i] = pw * dashPattern[i];
177 return drawinglayer::attribute::StrokeAttribute(std::move(aPattern));
179 // EmfPlusLineStyleSolid: - do nothing special, use default stroke attribute
180 return drawinglayer::attribute::StrokeAttribute();
183 void EMFPPen::Read(SvStream& s, EmfPlusHelperData const & rR)
185 sal_Int32 lineJoin = EmfPlusLineJoinTypeMiter;
186 sal_uInt32 graphicsVersion, penType;
187 s.ReadUInt32(graphicsVersion).ReadUInt32(penType).ReadUInt32(penDataFlags).ReadUInt32(penUnit).ReadFloat(penWidth);
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);
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.)
201 if (penDataFlags & EmfPlusPenDataTransform)
203 EmfPlusHelperData::readXForm(s, pen_transformation);
204 SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataTransform: " << pen_transformation);
207 if (penDataFlags & EmfPlusPenDataStartCap)
209 s.ReadInt32(startCap);
210 SAL_INFO("drawinglayer.emf", "EMF+\t\tstartCap: " << LineCapTypeToString(startCap) << " (0x" << std::hex << startCap << ")");
212 else
214 startCap = 0;
217 if (penDataFlags & EmfPlusPenDataEndCap)
219 s.ReadInt32(endCap);
220 SAL_INFO("drawinglayer.emf", "EMF+\t\tendCap: " << LineCapTypeToString(endCap) << " (0x" << std::hex << startCap << ")");
222 else
224 endCap = 0;
227 if (penDataFlags & EmfPlusPenDataJoin)
229 s.ReadInt32(lineJoin);
230 SAL_INFO("drawinglayer.emf", "EMF+\t\t LineJoin: " << lineJoin);
231 switch (lineJoin)
233 case EmfPlusLineJoinTypeBevel:
234 maLineJoin = basegfx::B2DLineJoin::Bevel;
235 break;
236 case EmfPlusLineJoinTypeRound:
237 maLineJoin = basegfx::B2DLineJoin::Round;
238 break;
239 case EmfPlusLineJoinTypeMiter:
240 case EmfPlusLineJoinTypeMiterClipped:
241 default: // If nothing set, then apply Miter (based on MS Paint)
242 maLineJoin = basegfx::B2DLineJoin::Miter;
243 break;
246 else
247 maLineJoin = basegfx::B2DLineJoin::Miter;
249 if (penDataFlags & EmfPlusPenDataMiterLimit)
251 float miterLimit;
252 s.ReadFloat(miterLimit);
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
263 fMiterMinimumAngle = basegfx::deg2rad(180.0);
264 SAL_INFO("drawinglayer.emf",
265 "EMF+\t\t MiterLimit: " << std::dec << miterLimit
266 << ", Miter minimum angle (rad): " << fMiterMinimumAngle);
268 else
269 fMiterMinimumAngle = basegfx::deg2rad(5.0);
272 if (penDataFlags & EmfPlusPenDataLineStyle)
274 s.ReadInt32(dashStyle);
275 SAL_INFO("drawinglayer.emf", "EMF+\t\tdashStyle: " << DashedLineCapTypeToString(dashStyle) << " (0x" << std::hex << dashStyle << ")");
277 else
279 dashStyle = 0;
282 if (penDataFlags & EmfPlusPenDataDashedLineCap)
284 s.ReadInt32(dashCap);
285 SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataDashedLineCap: 0x" << std::hex << dashCap);
287 else
289 dashCap = 0;
292 if (penDataFlags & EmfPlusPenDataDashedLineOffset)
294 s.ReadFloat(dashOffset);
295 SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataDashedLineOffset: 0x" << std::hex << dashOffset);
297 else
299 dashOffset = 0;
302 if (penDataFlags & EmfPlusPenDataDashedLine)
304 dashStyle = EmfPlusLineStyleCustom;
305 sal_uInt32 dashPatternLen;
307 s.ReadUInt32(dashPatternLen);
308 SAL_INFO("drawinglayer.emf", "EMF+\t\t\tdashPatternLen: " << dashPatternLen);
310 dashPattern.resize( dashPatternLen );
312 for (sal_uInt32 i = 0; i < dashPatternLen; i++)
314 s.ReadFloat(dashPattern[i]);
315 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tdashPattern[" << i << "]: " << dashPattern[i]);
319 if (penDataFlags & EmfPlusPenDataAlignment)
321 s.ReadInt32(alignment);
322 SAL_WARN("drawinglayer.emf", "EMF+\t\t\tTODO PenDataAlignment: " << PenAlignmentToString(alignment) << " (0x" << std::hex << alignment << ")");
324 else
326 alignment = 0;
329 if (penDataFlags & EmfPlusPenDataCompoundLine)
331 SAL_WARN("drawinglayer.emf", "EMF+\t\t\tTODO PenDataCompoundLine");
332 sal_uInt32 compoundArrayLen;
333 s.ReadUInt32(compoundArrayLen);
335 compoundArray.resize(compoundArrayLen);
337 for (sal_uInt32 i = 0; i < compoundArrayLen; i++)
339 s.ReadFloat(compoundArray[i]);
340 SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tcompoundArray[" << i << "]: " << compoundArray[i]);
344 if (penDataFlags & EmfPlusPenDataCustomStartCap)
346 s.ReadUInt32(customStartCapLen);
347 SAL_INFO("drawinglayer.emf", "EMF+\t\t\tcustomStartCapLen: " << customStartCapLen);
348 sal_uInt64 const pos = s.Tell();
350 customStartCap.reset( new EMFPCustomLineCap() );
351 customStartCap->Read(s, rR);
353 // maybe we don't read everything yet, play it safe ;-)
354 s.Seek(pos + customStartCapLen);
356 else
358 customStartCapLen = 0;
361 if (penDataFlags & EmfPlusPenDataCustomEndCap)
363 s.ReadUInt32(customEndCapLen);
364 SAL_INFO("drawinglayer.emf", "EMF+\t\t\tcustomEndCapLen: " << customEndCapLen);
365 sal_uInt64 const pos = s.Tell();
367 customEndCap.reset( new EMFPCustomLineCap() );
368 customEndCap->Read(s, rR);
370 // maybe we don't read everything yet, play it safe ;-)
371 s.Seek(pos + customEndCapLen);
373 else
375 customEndCapLen = 0;
378 EMFPBrush::Read(s, rR);
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */