1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawingml/linepropertiescontext.hxx>
21 #include <drawingml/misccontexts.hxx>
22 #include <drawingml/lineproperties.hxx>
23 #include <oox/helper/attributelist.hxx>
24 #include <oox/token/namespaces.hxx>
25 #include <oox/token/tokens.hxx>
26 #include <docmodel/theme/FormatScheme.hxx>
28 using namespace ::oox::core
;
32 namespace oox::drawingml
{
34 LinePropertiesContext::LinePropertiesContext( ContextHandler2Helper
const & rParent
, const AttributeList
& rAttribs
,
35 LineProperties
& rLineProperties
, model::LineStyle
* pLineStyle
) noexcept
36 : ContextHandler2(rParent
)
37 , mpLineStyle(pLineStyle
)
38 , mrLineProperties(rLineProperties
)
40 mrLineProperties
.moLineWidth
= rAttribs
.getInteger( XML_w
);
41 mrLineProperties
.moLineCompound
= rAttribs
.getToken( XML_cmpd
);
42 mrLineProperties
.moLineCap
= rAttribs
.getToken( XML_cap
);
46 mpLineStyle
->mnWidth
= rAttribs
.getInteger(XML_w
, 0);
48 switch (rAttribs
.getToken(XML_cap
, XML_TOKEN_INVALID
))
50 case XML_rnd
: mpLineStyle
->meCapType
= model::CapType::Round
; break;
51 case XML_sq
: mpLineStyle
->meCapType
= model::CapType::Square
; break;
52 case XML_flat
: mpLineStyle
->meCapType
= model::CapType::Flat
; break;
54 mpLineStyle
->meCapType
= model::CapType::Unset
; break;
57 switch (rAttribs
.getToken(XML_cmpd
, XML_TOKEN_INVALID
))
59 case XML_sng
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::Single
; break;
60 case XML_dbl
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::Double
; break;
61 case XML_thickThin
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::ThickThin_Double
; break;
62 case XML_thinThick
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::ThinThick_Double
; break;
63 case XML_tri
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::Triple
; break;
65 mpLineStyle
->meCompoundLineType
= model::CompoundLineType::Unset
; break;
68 switch (rAttribs
.getToken(XML_algn
, XML_TOKEN_INVALID
))
70 case XML_ctr
: mpLineStyle
->mePenAlignment
= model::PenAlignmentType::Center
; break;
71 case XML_in
: mpLineStyle
->mePenAlignment
= model::PenAlignmentType::Inset
; break;
73 mpLineStyle
->mePenAlignment
= model::PenAlignmentType::Unset
; break;
78 LinePropertiesContext::~LinePropertiesContext()
82 ContextHandlerRef
LinePropertiesContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
86 // LineFillPropertiesGroup
87 case A_TOKEN( noFill
):
88 case A_TOKEN( solidFill
):
89 case A_TOKEN( gradFill
):
90 case A_TOKEN( pattFill
):
92 model::FillStyle
* pFillStyle
= nullptr;
95 pFillStyle
= &mpLineStyle
->maLineFillStyle
;
97 return FillPropertiesContext::createFillContext(*this, nElement
, rAttribs
, mrLineProperties
.maLineFill
, pFillStyle
);
101 // LineDashPropertiesGroup
102 case A_TOKEN( prstDash
): // CT_PresetLineDashProperties
104 mrLineProperties
.moPresetDash
= rAttribs
.getToken( XML_val
);
108 auto& rLineDash
= mpLineStyle
->maLineDash
;
109 switch (rAttribs
.getToken(XML_val
, XML_TOKEN_INVALID
))
111 case XML_solid
: rLineDash
.mePresetType
= model::PresetDashType::Solid
; break;
112 case XML_dot
: rLineDash
.mePresetType
= model::PresetDashType::Dot
; break;
113 case XML_dash
: rLineDash
.mePresetType
= model::PresetDashType::Dash
; break;
114 case XML_lgDash
: rLineDash
.mePresetType
= model::PresetDashType::LargeDash
; break;
115 case XML_dashDot
: rLineDash
.mePresetType
= model::PresetDashType::DashDot
; break;
116 case XML_lgDashDot
: rLineDash
.mePresetType
= model::PresetDashType::LargeDashDot
; break;
117 case XML_lgDashDotDot
: rLineDash
.mePresetType
= model::PresetDashType::LargeDashDotDot
; break;
118 case XML_sysDash
: rLineDash
.mePresetType
= model::PresetDashType::SystemDash
; break;
119 case XML_sysDot
: rLineDash
.mePresetType
= model::PresetDashType::SystemDot
; break;
120 case XML_sysDashDot
: rLineDash
.mePresetType
= model::PresetDashType::SystemDashDot
; break;
121 case XML_sysDashDotDot
: rLineDash
.mePresetType
= model::PresetDashType::SystemDashDotDot
; break;
123 rLineDash
.mePresetType
= model::PresetDashType::Unset
; break;
128 case A_TOKEN( custDash
): // CT_DashStopList
132 // 'a:ds' has 2 attributes : 'd' and 'sp'
133 // both are of type 'a:ST_PositivePercentage'
134 // according to the specs Office will read percentages formatted with a trailing percent sign
135 // or formatted as 1000th of a percent without a trailing percent sign, but only write percentages
136 // as 1000th's of a percent without a trailing percent sign.
137 // The code below takes care of both scenarios by converting to '1000th of a percent' always
139 sal_Int32 nDashLength
= 0;
140 aStr
= rAttribs
.getStringDefaulted( XML_d
);
141 if ( aStr
.endsWith("%") )
144 aStr
= aStr
.copy(0, aStr
.getLength() - 1);
146 nDashLength
= aStr
.toInt32();
148 // Convert to 1000th of a percent
153 nDashLength
= rAttribs
.getInteger( XML_d
, 0 );
156 sal_Int32 nSpaceLength
= 0;
157 aStr
= rAttribs
.getStringDefaulted( XML_sp
);
158 if ( aStr
.endsWith("%") )
161 aStr
= aStr
.copy(0, aStr
.getLength() - 1);
163 nSpaceLength
= aStr
.toInt32();
165 // Convert to 1000th of a percent
166 nSpaceLength
*= 1000;
170 nSpaceLength
= rAttribs
.getInteger( XML_sp
, 0 );
173 mrLineProperties
.maCustomDash
.emplace_back( nDashLength
, nSpaceLength
);
177 mpLineStyle
->maLineDash
.maCustomList
.push_back({ nDashLength
, nSpaceLength
});
182 // LineJoinPropertiesGroup
183 case A_TOKEN( round
):
184 case A_TOKEN( bevel
):
185 case A_TOKEN( miter
):
187 sal_Int32 nToken
= getBaseToken(nElement
);
188 mrLineProperties
.moLineJoint
= nToken
;
194 case XML_round
: mpLineStyle
->maLineJoin
.meType
= model::LineJoinType::Round
; break;
195 case XML_bevel
: mpLineStyle
->maLineJoin
.meType
= model::LineJoinType::Bevel
; break;
196 case XML_miter
: mpLineStyle
->maLineJoin
.meType
= model::LineJoinType::Miter
; break;
198 mpLineStyle
->maLineJoin
.meType
= model::LineJoinType::Miter
;
200 if (nToken
== XML_miter
)
202 sal_Int32 nMiterLimit
= rAttribs
.getInteger(XML_lim
, 0);
203 mpLineStyle
->maLineJoin
.mnMiterLimit
= nMiterLimit
;
209 case A_TOKEN( headEnd
): // CT_LineEndProperties
210 case A_TOKEN( tailEnd
): // CT_LineEndProperties
212 bool bTailEnd
= nElement
== A_TOKEN( tailEnd
);
213 LineArrowProperties
& rArrowProps
= bTailEnd
? mrLineProperties
.maEndArrow
: mrLineProperties
.maStartArrow
;
214 rArrowProps
.moArrowType
= rAttribs
.getToken( XML_type
);
215 rArrowProps
.moArrowWidth
= rAttribs
.getToken( XML_w
);
216 rArrowProps
.moArrowLength
= rAttribs
.getToken( XML_len
);
220 model::LineEndType eLineEndType
= model::LineEndType::None
;
221 switch (rAttribs
.getToken(XML_type
, XML_none
))
223 case XML_triangle
: eLineEndType
= model::LineEndType::Triangle
; break;
224 case XML_stealth
: eLineEndType
= model::LineEndType::Stealth
; break;
225 case XML_diamond
: eLineEndType
= model::LineEndType::Diamond
; break;
226 case XML_oval
: eLineEndType
= model::LineEndType::Oval
; break;
227 case XML_arrow
: eLineEndType
= model::LineEndType::Arrow
; break;
229 case XML_none
: eLineEndType
= model::LineEndType::None
; break;
232 model::LineEndLength eLineEndLength
= model::LineEndLength::Unset
;
233 switch (rAttribs
.getToken(XML_len
, XML_TOKEN_INVALID
))
235 case XML_sm
: eLineEndLength
= model::LineEndLength::Small
; break;
236 case XML_med
: eLineEndLength
= model::LineEndLength::Medium
; break;
237 case XML_lg
: eLineEndLength
= model::LineEndLength::Large
; break;
242 model::LineEndWidth eLineEndWidth
= model::LineEndWidth::Unset
;
243 switch (rAttribs
.getToken(XML_w
, XML_TOKEN_INVALID
))
245 case XML_sm
: eLineEndWidth
= model::LineEndWidth::Small
; break;
246 case XML_med
: eLineEndWidth
= model::LineEndWidth::Medium
; break;
247 case XML_lg
: eLineEndWidth
= model::LineEndWidth::Large
; break;
252 if (nElement
== A_TOKEN(tailEnd
))
254 mpLineStyle
->maTailEnd
.meType
= eLineEndType
;
255 mpLineStyle
->maTailEnd
.meLength
= eLineEndLength
;
256 mpLineStyle
->maTailEnd
.meWidth
= eLineEndWidth
;
258 else if (nElement
== A_TOKEN(headEnd
))
260 mpLineStyle
->maHeadEnd
.meType
= eLineEndType
;
261 mpLineStyle
->maHeadEnd
.meLength
= eLineEndLength
;
262 mpLineStyle
->maHeadEnd
.meWidth
= eLineEndWidth
;
273 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */