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>
48void lclSetDashData( LineDash& orLineDash, sal_Int16 nDots, sal_Int32 nDotLen,
49 sal_Int16 nDashes, sal_Int32 nDashLen, sal_Int32 nDistance )
51 orLineDash.Dots = nDots;
52 orLineDash.DotLen = nDotLen;
53 orLineDash.Dashes = nDashes;
54 orLineDash.DashLen = nDashLen;
55 orLineDash.Distance = nDistance;
60void lclConvertPresetDash(LineDash& orLineDash, sal_Int32 nPresetDash)
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;
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;
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;
78 OSL_FAIL(
"lclConvertPresetDash - unsupported preset dash" );
79 lclSetDashData( orLineDash, 1, 4, 0, 0, 3 );
81 orLineDash.DotLen *= 100;
82 orLineDash.DashLen *= 100;
83 orLineDash.Distance *= 100;
93 OSL_ASSERT(!rCustomDash.empty());
95 orLineDash.Distance = rCustomDash[0].second;
97 orLineDash.DotLen = rCustomDash[0].first;
99 for(
const auto& rIt : rCustomDash)
101 if (rIt.first != orLineDash.DotLen)
106 orLineDash.Dashes = rCustomDash.size() - orLineDash.Dots;
107 if (orLineDash.Dashes > 0)
108 orLineDash.DashLen = rCustomDash[orLineDash.Dots].first;
110 orLineDash.DashLen = 0;
113 orLineDash.DotLen = orLineDash.DotLen / 1000;
114 orLineDash.DashLen = orLineDash.DashLen / 1000;
115 orLineDash.Distance = orLineDash.Distance / 1000;
123void lclRecoverStandardDashStyles(LineDash& orLineDash, sal_Int32 nLineWidth)
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;
134 if (nDots == 3 && nDotLen == 197 &&nDashes == 3 && nDashLen == 100 && nDistance == 100)
136 orLineDash.DashLen = 0;
138 else if (nDots == 1 && nDotLen == 100 && nDashes == 0 && nDistance == 50)
140 orLineDash.DotLen = 0;
142 else if (nDots == 2 && nDashes == 0 && nDotLen == nDistance
143 && std::abs(nDistance * fWidthHelp - 51.0) < fWidthHelp)
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;
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)
156 orLineDash.DotLen = 51;
157 orLineDash.DashLen = 254;
158 orLineDash.Distance = 127;
159 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
161 else if (nDots == 1 && nDotLen == 100 && nDashes == 0
162 && std::abs(nDistance * fWidthHelp - 457.0) < fWidthHelp)
164 orLineDash.DotLen = 0;
165 orLineDash.Distance = 457;
166 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
168 else if (nDots == 1 && nDashes == 10 && nDashLen == 100
169 && std::abs(nDistance * fWidthHelp - 152.0) < fWidthHelp)
171 orLineDash.DotLen = 2007;
172 orLineDash.DashLen = 0;
173 orLineDash.Distance = 152;
174 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
176 else if (nDots == 2 && nDotLen == 100 && nDashes == 1 && nDashLen == nDistance
177 && std::abs(nDistance * fWidthHelp - 203.0) < fWidthHelp)
179 orLineDash.DotLen = 0;
180 orLineDash.DashLen = 203;
181 orLineDash.Distance = 203;
182 orLineDash.Style = orLineDash.Style == DashStyle_ROUNDRELATIVE ? DashStyle_ROUND : DashStyle_RECT;
186DashStyle lclGetDashStyle( sal_Int32 nToken )
188 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
192 case XML_rnd:
return DashStyle_ROUNDRELATIVE;
193 case XML_sq:
return DashStyle_RECTRELATIVE;
194 case XML_flat:
return DashStyle_RECTRELATIVE;
196 return DashStyle_RECTRELATIVE;
199LineCap lclGetLineCap( sal_Int32 nToken )
201 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
204 case XML_rnd:
return LineCap_ROUND;
205 case XML_sq:
return LineCap_SQUARE;
206 case XML_flat:
return LineCap_BUTT;
211LineJoint lclGetLineJoint( sal_Int32 nToken )
213 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
216 case XML_round:
return LineJoint_ROUND;
217 case XML_bevel:
return LineJoint_BEVEL;
218 case XML_miter:
return LineJoint_MITER;
220 return LineJoint_ROUND;
223const sal_Int32 OOX_ARROWSIZE_SMALL = 0;
224const sal_Int32 OOX_ARROWSIZE_MEDIUM = 1;
225const sal_Int32 OOX_ARROWSIZE_LARGE = 2;
227sal_Int32 lclGetArrowSize( sal_Int32 nToken )
229 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
232 case XML_sm:
return OOX_ARROWSIZE_SMALL;
233 case XML_med:
return OOX_ARROWSIZE_MEDIUM;
234 case XML_lg:
return OOX_ARROWSIZE_LARGE;
236 return OOX_ARROWSIZE_MEDIUM;
239void lclPushMarkerProperties( ShapePropertyMap& rPropMap,
240 const LineArrowProperties& rArrowProps, sal_Int32 nLineWidth,
bool bLineEnd )
244 NamedValue aNamedMarker;
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);
254 aBuffer.append(
"msArrowEnd" );
257 aBuffer.append(
"msArrowOpenEnd" );
260 aBuffer.append(
"msArrowStealthEnd" );
263 aBuffer.append(
"msArrowDiamondEnd" );
264 bMarkerCenter =
true;
267 aBuffer.append(
"msArrowOvalEnd" );
268 bMarkerCenter =
true;
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 ) );
278 sal_Int32 nNameIndex = nWidth * 3 +
nLength + 1;
279 aBuffer.append(
" " + OUString::number( nNameIndex ));
283 aBuffer.append(
" " + OUString::number(nLineWidth));
285 OUString aMarkerName =
aBuffer.makeStringAndClear();
287 double fArrowLength = 1.0;
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;
294 double fArrowWidth = 1.0;
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;
302 sal_Int32 nBaseLineWidth = ::std::max< sal_Int32 >( nLineWidth, 70 );
303 nMarkerWidth =
static_cast<sal_Int32
>( fArrowWidth * nBaseLineWidth );
309 if( !rPropMap.hasNamedLineMarkerInTable( aMarkerName ) )
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 ) ); };
316 const double fArrowLineHalfWidth = ::std::max< double >( 100.0 * 0.5 * nLineWidth / nMarkerWidth, 1 );
318 ::std::vector< awt::Point > aPoints;
319 OSL_ASSERT((rArrowProps.moArrowType.value() & sal_Int32(0xFFFF0000))==0);
320 switch( rArrowProps.moArrowType.value() )
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 ) );
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 ) );
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 ) );
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 ) );
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 ) );
371 OSL_ENSURE( !aPoints.empty(),
"lclPushMarkerProperties - missing arrow coordinates" );
372 if( !aPoints.empty() )
374 PolyPolygonBezierCoords aMarkerCoords;
377 ::std::vector< PolygonFlags > aFlags( aPoints.size(), PolygonFlags_NORMAL );
380 aNamedMarker.Name = aMarkerName;
381 aNamedMarker.Value <<= aMarkerCoords;
389 aNamedMarker.Name = aMarkerName;
394 if( aNamedMarker.Name.isEmpty() )
442 drawing::LineStyle eLineStyle = (
maLineFill.
moFillType.value() == XML_noFill) ? drawing::LineStyle_NONE : drawing::LineStyle_SOLID;
454 if( (eLineStyle != drawing::LineStyle_NONE) &&
458 aLineDash.Style = lclGetDashStyle(
moLineCap.value_or( XML_flat ) );
461 lclConvertPresetDash(aLineDash,
moPresetDash.value_or(XML_dash));
465 lclRecoverStandardDashStyles(aLineDash,
nLineWidth);
471 if (eLineCap == LineCap_ROUND || (eLineCap == LineCap_SQUARE &&
maCustomDash.empty()))
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;
484 eLineStyle = drawing::LineStyle_DASH;
505 if (aColor == nPhClr)
521 sal_Int16 nShade = o3tl::narrowing<sal_Int16>(-aLineColor.
getTintOrShade());
537 return drawing::LineStyle_NONE;
540 return drawing::LineStyle_DASH;
541 return drawing::LineStyle_SOLID;
547 return lclGetLineCap(
moLineCap.value() );
549 return drawing::LineCap_BUTT;
557 return drawing::LineJoint_NONE;
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
sal_Int16 getLumMod() const
sal_Int16 getTransparency() const
Returns the transparency of the color (0 = opaque, 100 = full transparent).
sal_Int16 getLumOff() const
bool isUsed() const
Returns true, if the color is initialized.
bool hasTransparency() const
Returns true, if the color is transparent.
sal_Int16 getSchemeColorIndex() const
::Color getColor(const GraphicHelper &rGraphicHelper, ::Color nPhClr=API_RGB_TRANSPARENT) const
Returns the final RGB color value.
bool setProperty(ShapeProperty ePropId, const Type &rValue)
Sets the specified shape property to the passed value.
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)
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