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