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 
22 #include <comphelper/sequence.hxx>
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 
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::beans;
39 using namespace ::com::sun::star::drawing;
40 
41 
42 namespace oox::drawingml {
43 
44 namespace {
45 
46 void 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 
58 void 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 
89 void 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 
121 void 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 
184 DashStyle 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 
197 LineCap 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 
209 LineJoint 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 
221 const sal_Int32 OOX_ARROWSIZE_SMALL = 0;
222 const sal_Int32 OOX_ARROWSIZE_MEDIUM = 1;
223 const sal_Int32 OOX_ARROWSIZE_LARGE = 2;
224 
225 sal_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 
237 void 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.get( 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.get( XML_med ) );
274  sal_Int32 nWidth = lclGetArrowSize( rArrowProps.moArrowWidth.get( 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.get() & sal_Int32(0xFFFF0000))==0);
318  switch( rArrowProps.moArrowType.get() )
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  moArrowType.assignIfUsed( rSourceProps.moArrowType );
414  moArrowWidth.assignIfUsed( rSourceProps.moArrowWidth );
415  moArrowLength.assignIfUsed( rSourceProps.moArrowLength );
416 }
417 
418 void LineProperties::assignUsed( const LineProperties& rSourceProps )
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  moLineWidth.assignIfUsed( rSourceProps.moLineWidth );
426  moPresetDash.assignIfUsed( rSourceProps.moPresetDash );
428  moLineCap.assignIfUsed( rSourceProps.moLineCap );
429  moLineJoint.assignIfUsed( rSourceProps.moLineJoint );
430 }
431 
433  const GraphicHelper& rGraphicHelper, ::Color nPhClr ) const
434 {
435  // line fill type must exist, otherwise ignore other properties
437  return;
438 
439  // line style (our core only supports none and solid)
440  drawing::LineStyle eLineStyle = (maLineFill.moFillType.get() == 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
444  rPropMap.setProperty( ShapeProperty::LineWidth, nLineWidth );
445 
446  // line cap type
447  LineCap eLineCap = moLineCap.has_value() ? lclGetLineCap( moLineCap.get() ) : 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.get() != XML_solid) || !maCustomDash.empty()) )
454  {
455  LineDash aLineDash;
456  aLineDash.Style = lclGetDashStyle( moLineCap.get( XML_flat ) );
457 
458  if(moPresetDash.has_value() && moPresetDash.get() != XML_solid)
459  lclConvertPresetDash(aLineDash, moPresetDash.get(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.get() ) );
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 
507 {
508  // rules to calculate the line style inferred from the code in LineProperties::pushToPropMap
509  if (maLineFill.moFillType.get() == XML_noFill)
510  return drawing::LineStyle_NONE;
511  if ((moPresetDash.has_value() && moPresetDash.get() != XML_solid) ||
512  (!moPresetDash && !maCustomDash.empty()))
513  return drawing::LineStyle_DASH;
514  return drawing::LineStyle_SOLID;
515 }
516 
518 {
519  if( moLineCap.has_value() )
520  return lclGetLineCap( moLineCap.get() );
521 
522  return drawing::LineCap_BUTT;
523 }
524 
526 {
527  if( moLineJoint.has_value() )
528  return lclGetLineJoint( moLineJoint.get() );
529 
530  return drawing::LineJoint_NONE;
531 }
532 
534 {
535  return convertEmuToHmm( moLineWidth.get( 0 ) );
536 }
537 
538 } // namespace oox
539 
540 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Provides helper functions for colors, device measurement conversion, graphics, and graphic objects ha...
bool hasTransparency() const
Returns true, if the color is transparent.
Definition: color.cxx:703
sal_Int32 convertEmuToHmm(sal_Int64 nValue)
Converts the passed 64-bit integer value from EMUs to 1/100 mm.
bool setProperty(ShapeProperty ePropId, const Type &rValue)
Sets the specified shape property to the passed value.
OptValue< sal_Int32 > moFillType
OptValue< sal_Int32 > moLineCompound
Preset dash (OOXML token).
bool has_value() const
Definition: helper.hxx:181
Color getBestSolidColor() const
Tries to resolve current settings to a solid color, e.g.
sal_Int32 getLineWidth() const
Calculates the line width attribute from the internal state of the object.
OptValue< sal_Int32 > moPresetDash
Line width (EMUs).
float x
css::drawing::LineJoint getLineJoint() const
Calculates the line joint attribute from the internal state of the object.
OptValue< sal_Int32 > moLineCap
Line compound type (OOXML token).
void assignUsed(const LineArrowProperties &rSourceProps)
Overwrites all members that are explicitly set in rSourceProps.
LineArrowProperties maStartArrow
LineArrowProperties maEndArrow
Start line arrow style.
const Type & get() const
Definition: helper.hxx:184
OptValue< sal_Int32 > moLineJoint
Line cap (OOXML token).
css::drawing::LineStyle getLineStyle() const
Calculates the line style attribute from the internal state of the object.
float y
void pushToPropMap(ShapePropertyMap &rPropMap, const GraphicHelper &rGraphicHelper,::Color nPhClr=API_RGB_TRANSPARENT) const
Writes the properties to the passed property map.
::Color getColor(const GraphicHelper &rGraphicHelper,::Color nPhClr=API_RGB_TRANSPARENT) const
Returns the final RGB color value.
Definition: color.cxx:531
bool isUsed() const
Returns true, if the color is initialized.
Definition: color.hxx:87
void assignIfUsed(const OptValue &rValue)
Definition: helper.hxx:194
::std::vector< DashStop > DashStopVector
std::unique_ptr< char[]> aBuffer
FillProperties maLineFill
End line arrow style.
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
css::drawing::LineCap getLineCap() const
Calculates the line cap attribute from the internal state of the object.
sal_Int16 getTransparency() const
Returns the transparency of the color (0 = opaque, 100 = full transparent).
Definition: color.cxx:708
void assignUsed(const FillProperties &rSourceProps)
Properties for bitmap fills.
Explicit line dash or name of a line dash stored in a global container.
Explicit line start marker or name of a line marker stored in a global container. ...
sal_Int32 nLength
void assignUsed(const LineProperties &rSourceProps)
Line joint type (OOXML token).
OptValue< sal_Int32 > moLineWidth
User-defined line dash style.
DashStopVector maCustomDash
Line fill (solid, gradient, ...).
Explicit line end marker or name of a line marker stored in a global container.