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