LibreOffice Module oox (master) 1
lineproperties.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 <sal/config.h>
21
24#include <rtl/ustrbuf.hxx>
25#include <osl/diagnose.h>
26#include <com/sun/star/beans/NamedValue.hpp>
27#include <com/sun/star/drawing/LineCap.hpp>
28#include <com/sun/star/drawing/LineDash.hpp>
29#include <com/sun/star/drawing/LineJoint.hpp>
30#include <com/sun/star/drawing/LineStyle.hpp>
31#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
35#include <oox/token/tokens.hxx>
36
37using namespace ::com::sun::star;
38using namespace ::com::sun::star::beans;
39using namespace ::com::sun::star::drawing;
40
41
42namespace oox::drawingml {
43
44namespace {
45
46void lclSetDashData( LineDash& orLineDash, sal_Int16 nDots, sal_Int32 nDotLen,
47 sal_Int16 nDashes, sal_Int32 nDashLen, sal_Int32 nDistance )
48{
49 orLineDash.Dots = nDots;
50 orLineDash.DotLen = nDotLen;
51 orLineDash.Dashes = nDashes;
52 orLineDash.DashLen = nDashLen;
53 orLineDash.Distance = nDistance;
54}
55
58void lclConvertPresetDash(LineDash& orLineDash, sal_Int32 nPresetDash)
59{
60 switch( nPresetDash )
61 {
62 case XML_dot: lclSetDashData( orLineDash, 1, 1, 0, 0, 3 ); break;
63 case XML_dash: lclSetDashData( orLineDash, 1, 4, 0, 0, 3 ); break;
64 case XML_dashDot: lclSetDashData( orLineDash, 1, 4, 1, 1, 3 ); break;
65
66 case XML_lgDash: lclSetDashData( orLineDash, 1, 8, 0, 0, 3 ); break;
67 case XML_lgDashDot: lclSetDashData( orLineDash, 1, 8, 1, 1, 3 ); break;
68 case XML_lgDashDotDot: lclSetDashData( orLineDash, 1, 8, 2, 1, 3 ); break;
69
70 case XML_sysDot: lclSetDashData( orLineDash, 1, 1, 0, 0, 1 ); break;
71 case XML_sysDash: lclSetDashData( orLineDash, 1, 3, 0, 0, 1 ); break;
72 case XML_sysDashDot: lclSetDashData( orLineDash, 1, 3, 1, 1, 1 ); break;
73 case XML_sysDashDotDot: lclSetDashData( orLineDash, 1, 3, 2, 1, 1 ); break;
74
75 default:
76 OSL_FAIL( "lclConvertPresetDash - unsupported preset dash" );
77 lclSetDashData( orLineDash, 1, 4, 0, 0, 3 );
78 }
79 orLineDash.DotLen *= 100;
80 orLineDash.DashLen *= 100;
81 orLineDash.Distance *= 100;
82}
83
89void lclConvertCustomDash(LineDash& orLineDash, const LineProperties::DashStopVector& rCustomDash)
90{
91 OSL_ASSERT(!rCustomDash.empty());
92 // Assume all dash stops have the same sp values.
93 orLineDash.Distance = rCustomDash[0].second;
94 // First kind of dashes go to "Dots"
95 orLineDash.DotLen = rCustomDash[0].first;
96 orLineDash.Dots = 0;
97 for(const auto& rIt : rCustomDash)
98 {
99 if (rIt.first != orLineDash.DotLen)
100 break;
101 ++orLineDash.Dots;
102 }
103 // All others go to "Dashes", we cannot handle more than two kinds.
104 orLineDash.Dashes = rCustomDash.size() - orLineDash.Dots;
105 if (orLineDash.Dashes > 0)
106 orLineDash.DashLen = rCustomDash[orLineDash.Dots].first;
107 else
108 orLineDash.DashLen = 0;
109
110 // convert to API, e.g. 123% is 123000 in MS Office and 123 in our API
111 orLineDash.DotLen = orLineDash.DotLen / 1000;
112 orLineDash.DashLen = orLineDash.DashLen / 1000;
113 orLineDash.Distance = orLineDash.Distance / 1000;
114}
115
121void lclRecoverStandardDashStyles(LineDash& orLineDash, sal_Int32 nLineWidth)
122{
123 sal_uInt16 nDots = orLineDash.Dots;
124 sal_uInt16 nDashes = orLineDash.Dashes;
125 sal_uInt32 nDotLen = orLineDash.DotLen;
126 sal_uInt32 nDashLen = orLineDash.DashLen;
127 sal_uInt32 nDistance = orLineDash.Distance;
128 // Use same ersatz for hairline as in export.
129 double fWidthHelp = nLineWidth == 0 ? 26.95/100.0 : nLineWidth / 100.0;
130 // start with (var) cases, because they have no rounding problems
131 // "Fine Dashed", "Line Style 9" and "Dashed (var)" need no recover
132 if (nDots == 3 && nDotLen == 197 &&nDashes == 3 && nDashLen == 100 && nDistance == 100)
133 { // "3 Dashes 3 Dots (var)"
134 orLineDash.DashLen = 0;
135 }
136 else if (nDots == 1 && nDotLen == 100 && nDashes == 0 && nDistance == 50)
137 { // "Ultrafine Dotted (var)"
138 orLineDash.DotLen = 0;
139 }
140 else if (nDots == 2 && nDashes == 0 && nDotLen == nDistance
141 && std::abs(nDistance * fWidthHelp - 51.0) < fWidthHelp)
142 { // "Ultrafine Dashed"
143 orLineDash.Dots = 1;
144 orLineDash.DotLen = 51;
145 orLineDash.Dashes = 1;
146 orLineDash.DashLen = 51;
147 orLineDash.Distance = 51;
148 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
149 }
150 else if (nDots == 2 && nDashes == 3 && std::abs(nDotLen * fWidthHelp - 51.0) < fWidthHelp
151 && std::abs(nDashLen * fWidthHelp - 254.0) < fWidthHelp
152 && std::abs(nDistance * fWidthHelp - 127.0) < fWidthHelp)
153 { // "Ultrafine 2 Dots 3 Dashes"
154 orLineDash.DotLen = 51;
155 orLineDash.DashLen = 254;
156 orLineDash.Distance = 127;
157 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
158 }
159 else if (nDots == 1 && nDotLen == 100 && nDashes == 0
160 && std::abs(nDistance * fWidthHelp - 457.0) < fWidthHelp)
161 { // "Fine Dotted"
162 orLineDash.DotLen = 0;
163 orLineDash.Distance = 457;
164 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
165 }
166 else if (nDots == 1 && nDashes == 10 && nDashLen == 100
167 && std::abs(nDistance * fWidthHelp - 152.0) < fWidthHelp)
168 { // "Line with Fine Dots"
169 orLineDash.DotLen = 2007;
170 orLineDash.DashLen = 0;
171 orLineDash.Distance = 152;
172 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
173 }
174 else if (nDots == 2 && nDotLen == 100 && nDashes == 1 && nDashLen == nDistance
175 && std::abs(nDistance * fWidthHelp - 203.0) < fWidthHelp)
176 { // "2 Dots 1 Dash"
177 orLineDash.DotLen = 0;
178 orLineDash.DashLen = 203;
179 orLineDash.Distance = 203;
180 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
181 }
182}
183
184DashStyle lclGetDashStyle( sal_Int32 nToken )
185{
186 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
187 // MS Office dashing is always relative to line width
188 switch( nToken )
189 {
190 case XML_rnd: return DashStyle_ROUNDRELATIVE;
191 case XML_sq: return DashStyle_RECTRELATIVE; // default in OOXML
192 case XML_flat: return DashStyle_RECTRELATIVE; // default in MS Office
193 }
194 return DashStyle_RECTRELATIVE;
195}
196
197LineCap lclGetLineCap( sal_Int32 nToken )
198{
199 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
200 switch( nToken )
201 {
202 case XML_rnd: return LineCap_ROUND;
203 case XML_sq: return LineCap_SQUARE; // default in OOXML
204 case XML_flat: return LineCap_BUTT; // default in MS Office
205 }
206 return LineCap_BUTT;
207}
208
209LineJoint lclGetLineJoint( sal_Int32 nToken )
210{
211 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
212 switch( nToken )
213 {
214 case XML_round: return LineJoint_ROUND;
215 case XML_bevel: return LineJoint_BEVEL;
216 case XML_miter: return LineJoint_MITER;
217 }
218 return LineJoint_ROUND;
219}
220
221const sal_Int32 OOX_ARROWSIZE_SMALL = 0;
222const sal_Int32 OOX_ARROWSIZE_MEDIUM = 1;
223const sal_Int32 OOX_ARROWSIZE_LARGE = 2;
224
225sal_Int32 lclGetArrowSize( sal_Int32 nToken )
226{
227 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
228 switch( nToken )
229 {
230 case XML_sm: return OOX_ARROWSIZE_SMALL;
231 case XML_med: return OOX_ARROWSIZE_MEDIUM;
232 case XML_lg: return OOX_ARROWSIZE_LARGE;
233 }
234 return OOX_ARROWSIZE_MEDIUM;
235}
236
237void lclPushMarkerProperties( ShapePropertyMap& rPropMap,
238 const LineArrowProperties& rArrowProps, sal_Int32 nLineWidth, bool bLineEnd )
239{
240 /* Store the marker polygon and the marker name in a single value, to be
241 able to pass both to the ShapePropertyMap::setProperty() function. */
242 NamedValue aNamedMarker;
243
244 OUStringBuffer aBuffer;
245 sal_Int32 nMarkerWidth = 0;
246 bool bMarkerCenter = false;
247 sal_Int32 nArrowType = rArrowProps.moArrowType.value_or( XML_none );
248 OSL_ASSERT((nArrowType & sal_Int32(0xFFFF0000))==0);
249 switch( nArrowType )
250 {
251 case XML_triangle:
252 aBuffer.append( "msArrowEnd" );
253 break;
254 case XML_arrow:
255 aBuffer.append( "msArrowOpenEnd" );
256 break;
257 case XML_stealth:
258 aBuffer.append( "msArrowStealthEnd" );
259 break;
260 case XML_diamond:
261 aBuffer.append( "msArrowDiamondEnd" );
262 bMarkerCenter = true;
263 break;
264 case XML_oval:
265 aBuffer.append( "msArrowOvalEnd" );
266 bMarkerCenter = true;
267 break;
268 }
269
270 if( !aBuffer.isEmpty() )
271 {
272 bool bIsArrow = nArrowType == XML_arrow;
273 sal_Int32 nLength = lclGetArrowSize( rArrowProps.moArrowLength.value_or( XML_med ) );
274 sal_Int32 nWidth = lclGetArrowSize( rArrowProps.moArrowWidth.value_or( XML_med ) );
275
276 sal_Int32 nNameIndex = nWidth * 3 + nLength + 1;
277 aBuffer.append( ' ' ).append( nNameIndex );
278 if (bIsArrow)
279 {
280 // Arrow marker form depends also on line width
281 aBuffer.append(' ').append(nLineWidth);
282 }
283 OUString aMarkerName = aBuffer.makeStringAndClear();
284
285 double fArrowLength = 1.0;
286 switch( nLength )
287 {
288 case OOX_ARROWSIZE_SMALL: fArrowLength = (bIsArrow ? 2.5 : 2.0); break;
289 case OOX_ARROWSIZE_MEDIUM: fArrowLength = (bIsArrow ? 3.5 : 3.0); break;
290 case OOX_ARROWSIZE_LARGE: fArrowLength = (bIsArrow ? 5.5 : 5.0); break;
291 }
292 double fArrowWidth = 1.0;
293 switch( nWidth )
294 {
295 case OOX_ARROWSIZE_SMALL: fArrowWidth = (bIsArrow ? 2.5 : 2.0); break;
296 case OOX_ARROWSIZE_MEDIUM: fArrowWidth = (bIsArrow ? 3.5 : 3.0); break;
297 case OOX_ARROWSIZE_LARGE: fArrowWidth = (bIsArrow ? 5.5 : 5.0); break;
298 }
299 // set arrow width relative to line width
300 sal_Int32 nBaseLineWidth = ::std::max< sal_Int32 >( nLineWidth, 70 );
301 nMarkerWidth = static_cast<sal_Int32>( fArrowWidth * nBaseLineWidth );
302
303 /* Test if the marker already exists in the marker table, do not
304 create it again in this case. If markers are inserted explicitly
305 instead by their name, the polygon will be created always.
306 TODO: this can be optimized by using a map. */
307 if( !rPropMap.hasNamedLineMarkerInTable( aMarkerName ) )
308 {
309 // pass X and Y as percentage to OOX_ARROW_POINT
310 auto OOX_ARROW_POINT = [fArrowLength, fArrowWidth]( double x, double y ) { return awt::Point( static_cast< sal_Int32 >( fArrowWidth * x ), static_cast< sal_Int32 >( fArrowLength * y ) ); };
311 // tdf#100491 Arrow line marker, unlike other markers, depends on line width.
312 // So calculate width of half line (more convenient during drawing) taking into account
313 // further conversions/scaling done in OOX_ARROW_POINT and scaling to nMarkerWidth.
314 const double fArrowLineHalfWidth = ::std::max< double >( 100.0 * 0.5 * nLineWidth / nMarkerWidth, 1 );
315
316 ::std::vector< awt::Point > aPoints;
317 OSL_ASSERT((rArrowProps.moArrowType.value() & sal_Int32(0xFFFF0000))==0);
318 switch( rArrowProps.moArrowType.value() )
319 {
320 case XML_triangle:
321 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
322 aPoints.push_back( OOX_ARROW_POINT( 100, 100 ) );
323 aPoints.push_back( OOX_ARROW_POINT( 0, 100 ) );
324 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
325 break;
326 case XML_arrow:
327 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
328 aPoints.push_back( OOX_ARROW_POINT( 100, 100 - fArrowLineHalfWidth * 1.5) );
329 aPoints.push_back( OOX_ARROW_POINT( 100 - fArrowLineHalfWidth * 1.5, 100 ) );
330 aPoints.push_back( OOX_ARROW_POINT( 50.0 + fArrowLineHalfWidth, 5.5 * fArrowLineHalfWidth) );
331 aPoints.push_back( OOX_ARROW_POINT( 50.0 + fArrowLineHalfWidth, 100 ) );
332 aPoints.push_back( OOX_ARROW_POINT( 50.0 - fArrowLineHalfWidth, 100 ) );
333 aPoints.push_back( OOX_ARROW_POINT( 50.0 - fArrowLineHalfWidth, 5.5 * fArrowLineHalfWidth) );
334 aPoints.push_back( OOX_ARROW_POINT( fArrowLineHalfWidth * 1.5, 100 ) );
335 aPoints.push_back( OOX_ARROW_POINT( 0, 100 - fArrowLineHalfWidth * 1.5) );
336 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
337 break;
338 case XML_stealth:
339 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
340 aPoints.push_back( OOX_ARROW_POINT( 100, 100 ) );
341 aPoints.push_back( OOX_ARROW_POINT( 50, 60 ) );
342 aPoints.push_back( OOX_ARROW_POINT( 0, 100 ) );
343 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
344 break;
345 case XML_diamond:
346 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
347 aPoints.push_back( OOX_ARROW_POINT( 100, 50 ) );
348 aPoints.push_back( OOX_ARROW_POINT( 50, 100 ) );
349 aPoints.push_back( OOX_ARROW_POINT( 0, 50 ) );
350 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
351 break;
352 case XML_oval:
353 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
354 aPoints.push_back( OOX_ARROW_POINT( 75, 7 ) );
355 aPoints.push_back( OOX_ARROW_POINT( 93, 25 ) );
356 aPoints.push_back( OOX_ARROW_POINT( 100, 50 ) );
357 aPoints.push_back( OOX_ARROW_POINT( 93, 75 ) );
358 aPoints.push_back( OOX_ARROW_POINT( 75, 93 ) );
359 aPoints.push_back( OOX_ARROW_POINT( 50, 100 ) );
360 aPoints.push_back( OOX_ARROW_POINT( 25, 93 ) );
361 aPoints.push_back( OOX_ARROW_POINT( 7, 75 ) );
362 aPoints.push_back( OOX_ARROW_POINT( 0, 50 ) );
363 aPoints.push_back( OOX_ARROW_POINT( 7, 25 ) );
364 aPoints.push_back( OOX_ARROW_POINT( 25, 7 ) );
365 aPoints.push_back( OOX_ARROW_POINT( 50, 0 ) );
366 break;
367 }
368
369 OSL_ENSURE( !aPoints.empty(), "lclPushMarkerProperties - missing arrow coordinates" );
370 if( !aPoints.empty() )
371 {
372 PolyPolygonBezierCoords aMarkerCoords;
373 aMarkerCoords.Coordinates = { comphelper::containerToSequence( aPoints ) };
374
375 ::std::vector< PolygonFlags > aFlags( aPoints.size(), PolygonFlags_NORMAL );
376 aMarkerCoords.Flags = { comphelper::containerToSequence( aFlags ) };
377
378 aNamedMarker.Name = aMarkerName;
379 aNamedMarker.Value <<= aMarkerCoords;
380 }
381 }
382 else
383 {
384 /* Named marker object exists already in the marker table, pass
385 its name only. This will set the name as property value, but
386 does not create a new object in the marker table. */
387 aNamedMarker.Name = aMarkerName;
388 }
389 }
390
391 // push the properties (filled aNamedMarker.Name indicates valid marker)
392 if( aNamedMarker.Name.isEmpty() )
393 return;
394
395 if( bLineEnd )
396 {
397 rPropMap.setProperty( ShapeProperty::LineEnd, aNamedMarker );
398 rPropMap.setProperty( ShapeProperty::LineEndWidth, nMarkerWidth );
399 rPropMap.setProperty( ShapeProperty::LineEndCenter, bMarkerCenter );
400 }
401 else
402 {
403 rPropMap.setProperty( ShapeProperty::LineStart, aNamedMarker );
404 rPropMap.setProperty( ShapeProperty::LineStartWidth, nMarkerWidth );
405 rPropMap.setProperty( ShapeProperty::LineStartCenter, bMarkerCenter );
406 }
407}
408
409} // namespace
410
412{
413 assignIfUsed( moArrowType, rSourceProps.moArrowType );
414 assignIfUsed( moArrowWidth, rSourceProps.moArrowWidth );
416}
417
419{
420 maStartArrow.assignUsed( rSourceProps.maStartArrow );
421 maEndArrow.assignUsed( rSourceProps.maEndArrow );
422 maLineFill.assignUsed( rSourceProps.maLineFill );
423 if( !rSourceProps.maCustomDash.empty() )
424 maCustomDash = rSourceProps.maCustomDash;
425 assignIfUsed( moLineWidth, rSourceProps.moLineWidth );
426 assignIfUsed( moPresetDash, rSourceProps.moPresetDash );
428 assignIfUsed( moLineCap, rSourceProps.moLineCap );
429 assignIfUsed( moLineJoint, rSourceProps.moLineJoint );
430}
431
433 const GraphicHelper& rGraphicHelper, ::Color nPhClr ) const
434{
435 // line fill type must exist, otherwise ignore other properties
436 if( !maLineFill.moFillType.has_value() )
437 return;
438
439 // line style (our core only supports none and solid)
440 drawing::LineStyle eLineStyle = (maLineFill.moFillType.value() == XML_noFill) ? drawing::LineStyle_NONE : drawing::LineStyle_SOLID;
441
442 // line width in 1/100mm
443 sal_Int32 nLineWidth = getLineWidth(); // includes conversion from EMUs to 1/100mm
445
446 // line cap type
447 LineCap eLineCap = moLineCap.has_value() ? lclGetLineCap( moLineCap.value() ) : LineCap_BUTT;
448 if( moLineCap.has_value() )
449 rPropMap.setProperty( ShapeProperty::LineCap, eLineCap );
450
451 // create line dash from preset dash token or dash stop vector (not for invisible line)
452 if( (eLineStyle != drawing::LineStyle_NONE) &&
453 ((moPresetDash.has_value() && moPresetDash.value() != XML_solid) || !maCustomDash.empty()) )
454 {
455 LineDash aLineDash;
456 aLineDash.Style = lclGetDashStyle( moLineCap.value_or( XML_flat ) );
457
458 if(moPresetDash.has_value() && moPresetDash.value() != XML_solid)
459 lclConvertPresetDash(aLineDash, moPresetDash.value_or(XML_dash));
460 else // !maCustomDash.empty()
461 {
462 lclConvertCustomDash(aLineDash, maCustomDash);
463 lclRecoverStandardDashStyles(aLineDash, nLineWidth);
464 }
465
466 // In MS Office (2020) for preset dash style line caps round and square are included in dash length.
467 // For custom dash style round line cap is included, square line cap is added. In ODF line caps are
468 // always added to dash length. Tweak the length accordingly.
469 if (eLineCap == LineCap_ROUND || (eLineCap == LineCap_SQUARE && maCustomDash.empty()))
470 {
471 // Cannot use -100 because that results in 0 length in some cases and
472 // LibreOffice interprets 0 length as 100%.
473 if (aLineDash.DotLen >= 100 || aLineDash.DashLen >= 100)
474 aLineDash.Distance += 99;
475 if (aLineDash.DotLen >= 100)
476 aLineDash.DotLen -= 99;
477 if (aLineDash.DashLen >= 100)
478 aLineDash.DashLen -= 99;
479 }
480
481 if( rPropMap.setProperty( ShapeProperty::LineDash, aLineDash ) )
482 eLineStyle = drawing::LineStyle_DASH;
483 }
484
485 // set final line style property
486 rPropMap.setProperty( ShapeProperty::LineStyle, eLineStyle );
487
488 // line joint type
489 if( moLineJoint.has_value() )
490 rPropMap.setProperty( ShapeProperty::LineJoint, lclGetLineJoint( moLineJoint.value() ) );
491
492 // line color and transparence
493 Color aLineColor = maLineFill.getBestSolidColor();
494 if( aLineColor.isUsed() )
495 {
496 rPropMap.setProperty( ShapeProperty::LineColor, aLineColor.getColor( rGraphicHelper, nPhClr ) );
497 if( aLineColor.hasTransparency() )
499 }
500
501 // line markers
502 lclPushMarkerProperties( rPropMap, maStartArrow, nLineWidth, false );
503 lclPushMarkerProperties( rPropMap, maEndArrow, nLineWidth, true );
504}
505
506drawing::LineStyle LineProperties::getLineStyle() const
507{
508 // rules to calculate the line style inferred from the code in LineProperties::pushToPropMap
509 if (maLineFill.moFillType.value() == XML_noFill)
510 return drawing::LineStyle_NONE;
511 if ((moPresetDash.has_value() && moPresetDash.value() != XML_solid) ||
512 (!moPresetDash && !maCustomDash.empty()))
513 return drawing::LineStyle_DASH;
514 return drawing::LineStyle_SOLID;
515}
516
517drawing::LineCap LineProperties::getLineCap() const
518{
519 if( moLineCap.has_value() )
520 return lclGetLineCap( moLineCap.value() );
521
522 return drawing::LineCap_BUTT;
523}
524
525drawing::LineJoint LineProperties::getLineJoint() const
526{
527 if( moLineJoint.has_value() )
528 return lclGetLineJoint( moLineJoint.value() );
529
530 return drawing::LineJoint_NONE;
531}
532
534{
535 return convertEmuToHmm( moLineWidth.value_or( 0 ) );
536}
537
538} // namespace oox
539
540/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nLineWidth
Provides helper functions for colors, device measurement conversion, graphics, and graphic objects ha...
sal_Int16 getTransparency() const
Returns the transparency of the color (0 = opaque, 100 = full transparent).
Definition: color.cxx:708
bool isUsed() const
Returns true, if the color is initialized.
Definition: color.hxx:87
bool hasTransparency() const
Returns true, if the color is transparent.
Definition: color.cxx:703
::Color getColor(const GraphicHelper &rGraphicHelper, ::Color nPhClr=API_RGB_TRANSPARENT) const
Returns the final RGB color value.
Definition: color.cxx:531
bool setProperty(ShapeProperty ePropId, const Type &rValue)
Sets the specified shape property to the passed value.
float y
float x
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
@ LineStart
Explicit line start marker or name of a line marker stored in a global container.
@ LineEnd
Explicit line end marker or name of a line marker stored in a global container.
@ LineDash
Explicit line dash or name of a line dash stored in a global container.
sal_Int32 convertEmuToHmm(sal_Int64 nValue)
Converts the passed 64-bit integer value from EMUs to 1/100 mm.
void assignIfUsed(std::optional< Type > &rDestValue, const std::optional< Type > &rSourceValue)
Definition: helper.hxx:174
void assignUsed(const FillProperties &rSourceProps)
Properties for bitmap fills.
Color getBestSolidColor() const
Tries to resolve current settings to a solid color, e.g.
std::optional< sal_Int32 > moFillType
std::optional< sal_Int32 > moArrowLength
std::optional< sal_Int32 > moArrowType
void assignUsed(const LineArrowProperties &rSourceProps)
Overwrites all members that are explicitly set in rSourceProps.
std::optional< sal_Int32 > moArrowWidth
void assignUsed(const LineProperties &rSourceProps)
Line joint type (OOXML token).
void pushToPropMap(ShapePropertyMap &rPropMap, const GraphicHelper &rGraphicHelper, ::Color nPhClr=API_RGB_TRANSPARENT) const
Writes the properties to the passed property map.
FillProperties maLineFill
End line arrow style.
std::optional< sal_Int32 > moLineCompound
Preset dash (OOXML token).
sal_Int32 getLineWidth() const
Calculates the line width attribute from the internal state of the object.
std::optional< sal_Int32 > moLineCap
Line compound type (OOXML token).
std::optional< sal_Int32 > moLineWidth
User-defined line dash style.
LineArrowProperties maStartArrow
css::drawing::LineStyle getLineStyle() const
Calculates the line style attribute from the internal state of the object.
::std::vector< DashStop > DashStopVector
std::optional< sal_Int32 > moLineJoint
Line cap (OOXML token).
LineArrowProperties maEndArrow
Start line arrow style.
std::optional< sal_Int32 > moPresetDash
Line width (EMUs).
DashStopVector maCustomDash
Line fill (solid, gradient, ...).
css::drawing::LineCap getLineCap() const
Calculates the line cap attribute from the internal state of the object.
css::drawing::LineJoint getLineJoint() const
Calculates the line joint attribute from the internal state of the object.
std::unique_ptr< char[]> aBuffer
sal_Int32 nLength