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
;
29 using namespace ::com::sun::star::uno
;
30 using namespace ::com::sun::star::xml::sax
;
34 namespace oox::drawingml
{
36 LinePropertiesContext::LinePropertiesContext( ContextHandler2Helper
const & rParent
, const AttributeList
& rAttribs
,
37 LineProperties
& rLineProperties
, model::LineStyle
* pLineStyle
) noexcept
38 : ContextHandler2(rParent
)
39 , mpLineStyle(pLineStyle
)
40 , mrLineProperties(rLineProperties
)
42 mrLineProperties
.moLineWidth
= rAttribs
.getInteger( XML_w
);
43 mrLineProperties
.moLineCompound
= rAttribs
.getToken( XML_cmpd
);
44 mrLineProperties
.moLineCap
= rAttribs
.getToken( XML_cap
);
48 mpLineStyle
->mnWidth
= rAttribs
.getInteger(XML_w
, 0);
50 switch (rAttribs
.getToken(XML_cap
, XML_TOKEN_INVALID
))
52 case XML_rnd
: mpLineStyle
->meCapType
= model::CapType::Round
; break;
53 case XML_sq
: mpLineStyle
->meCapType
= model::CapType::Square
; break;
54 case XML_flat
: mpLineStyle
->meCapType
= model::CapType::Flat
; break;
56 mpLineStyle
->meCapType
= model::CapType::Unset
; break;
59 switch (rAttribs
.getToken(XML_cmpd
, XML_TOKEN_INVALID
))
61 case XML_sng
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::Single
; break;
62 case XML_dbl
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::Double
; break;
63 case XML_thickThin
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::ThickThin_Double
; break;
64 case XML_thinThick
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::ThinThick_Double
; break;
65 case XML_tri
: mpLineStyle
->meCompoundLineType
= model::CompoundLineType::Triple
; break;
67 mpLineStyle
->meCompoundLineType
= model::CompoundLineType::Unset
; break;
70 switch (rAttribs
.getToken(XML_algn
, XML_TOKEN_INVALID
))
72 case XML_ctr
: mpLineStyle
->mePenAlignment
= model::PenAlignmentType::Center
; break;
73 case XML_in
: mpLineStyle
->mePenAlignment
= model::PenAlignmentType::Inset
; break;
75 mpLineStyle
->mePenAlignment
= model::PenAlignmentType::Unset
; break;
80 LinePropertiesContext::~LinePropertiesContext()
84 ContextHandlerRef
LinePropertiesContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
88 // LineFillPropertiesGroup
89 case A_TOKEN( noFill
):
90 case A_TOKEN( solidFill
):
91 case A_TOKEN( gradFill
):
92 case A_TOKEN( pattFill
):
94 model::FillStyle
* pFillStyle
= nullptr;
97 pFillStyle
= &mpLineStyle
->maLineFillStyle
;
99 return FillPropertiesContext::createFillContext(*this, nElement
, rAttribs
, mrLineProperties
.maLineFill
, pFillStyle
);
103 // LineDashPropertiesGroup
104 case A_TOKEN( prstDash
): // CT_PresetLineDashProperties
106 mrLineProperties
.moPresetDash
= rAttribs
.getToken( XML_val
);
110 auto& rLineDash
= mpLineStyle
->maLineDash
;
111 switch (rAttribs
.getToken(XML_val
, XML_TOKEN_INVALID
))
113 case XML_solid
: rLineDash
.mePresetType
= model::PresetDashType::Solid
; break;
114 case XML_dot
: rLineDash
.mePresetType
= model::PresetDashType::Dot
; break;
115 case XML_dash
: rLineDash
.mePresetType
= model::PresetDashType::Dash
; break;
116 case XML_lgDash
: rLineDash
.mePresetType
= model::PresetDashType::LargeDash
; break;
117 case XML_dashDot
: rLineDash
.mePresetType
= model::PresetDashType::DashDot
; break;
118 case XML_lgDashDot
: rLineDash
.mePresetType
= model::PresetDashType::LargeDashDot
; break;
119 case XML_lgDashDotDot
: rLineDash
.mePresetType
= model::PresetDashType::LargeDashDotDot
; break;
120 case XML_sysDash
: rLineDash
.mePresetType
= model::PresetDashType::SystemDash
; break;
121 case XML_sysDot
: rLineDash
.mePresetType
= model::PresetDashType::SystemDot
; break;
122 case XML_sysDashDot
: rLineDash
.mePresetType
= model::PresetDashType::SystemDashDot
; break;
123 case XML_sysDashDotDot
: rLineDash
.mePresetType
= model::PresetDashType::SystemDashDotDot
; break;
125 rLineDash
.mePresetType
= model::PresetDashType::Unset
; break;
130 case A_TOKEN( custDash
): // CT_DashStopList
134 // 'a:ds' has 2 attributes : 'd' and 'sp'
135 // both are of type 'a:ST_PositivePercentage'
136 // according to the specs Office will read percentages formatted with a trailing percent sign
137 // or formatted as 1000th of a percent without a trailing percent sign, but only write percentages
138 // as 1000th's of a percent without a trailing percent sign.
139 // The code below takes care of both scenarios by converting to '1000th of a percent' always
141 sal_Int32 nDashLength
= 0;
142 aStr
= rAttribs
.getStringDefaulted( XML_d
);
143 if ( aStr
.endsWith("%") )
146 aStr
= aStr
.copy(0, aStr
.getLength() - 1);
148 nDashLength
= aStr
.toInt32();
150 // Convert to 1000th of a percent
155 nDashLength
= rAttribs
.getInteger( XML_d
, 0 );
158 sal_Int32 nSpaceLength
= 0;
159 aStr
= rAttribs
.getStringDefaulted( XML_sp
);
160 if ( aStr
.endsWith("%") )
163 aStr
= aStr
.copy(0, aStr
.getLength() - 1);
165 nSpaceLength
= aStr
.toInt32();
167 // Convert to 1000th of a percent
168 nSpaceLength
*= 1000;
172 nSpaceLength
= rAttribs
.getInteger( XML_sp
, 0 );
175 mrLineProperties
.maCustomDash
.emplace_back( nDashLength
, nSpaceLength
);
179 mpLineStyle
->maLineDash
.maCustomList
.push_back({ nDashLength
, nSpaceLength
});
184 // LineJoinPropertiesGroup
185 case A_TOKEN( round
):
186 case A_TOKEN( bevel
):
187 case A_TOKEN( miter
):
189 sal_Int32 nToken
= getBaseToken(nElement
);
190 mrLineProperties
.moLineJoint
= nToken
;
196 case XML_round
: mpLineStyle
->maLineJoin
.meType
= model::LineJoinType::Round
; break;
197 case XML_bevel
: mpLineStyle
->maLineJoin
.meType
= model::LineJoinType::Bevel
; break;
198 case XML_miter
: mpLineStyle
->maLineJoin
.meType
= model::LineJoinType::Miter
; break;
200 mpLineStyle
->maLineJoin
.meType
= model::LineJoinType::Miter
;
202 if (nToken
== XML_miter
)
204 sal_Int32 nMiterLimit
= rAttribs
.getInteger(XML_lim
, 0);
205 mpLineStyle
->maLineJoin
.mnMiterLimit
= nMiterLimit
;
211 case A_TOKEN( headEnd
): // CT_LineEndProperties
212 case A_TOKEN( tailEnd
): // CT_LineEndProperties
214 bool bTailEnd
= nElement
== A_TOKEN( tailEnd
);
215 LineArrowProperties
& rArrowProps
= bTailEnd
? mrLineProperties
.maEndArrow
: mrLineProperties
.maStartArrow
;
216 rArrowProps
.moArrowType
= rAttribs
.getToken( XML_type
);
217 rArrowProps
.moArrowWidth
= rAttribs
.getToken( XML_w
);
218 rArrowProps
.moArrowLength
= rAttribs
.getToken( XML_len
);
222 model::LineEndType eLineEndType
= model::LineEndType::None
;
223 switch (rAttribs
.getToken(XML_type
, XML_none
))
225 case XML_triangle
: eLineEndType
= model::LineEndType::Triangle
; break;
226 case XML_stealth
: eLineEndType
= model::LineEndType::Stealth
; break;
227 case XML_diamond
: eLineEndType
= model::LineEndType::Diamond
; break;
228 case XML_oval
: eLineEndType
= model::LineEndType::Oval
; break;
229 case XML_arrow
: eLineEndType
= model::LineEndType::Arrow
; break;
231 case XML_none
: eLineEndType
= model::LineEndType::None
; break;
234 model::LineEndLength eLineEndLength
= model::LineEndLength::Unset
;
235 switch (rAttribs
.getToken(XML_len
, XML_TOKEN_INVALID
))
237 case XML_sm
: eLineEndLength
= model::LineEndLength::Small
; break;
238 case XML_med
: eLineEndLength
= model::LineEndLength::Medium
; break;
239 case XML_lg
: eLineEndLength
= model::LineEndLength::Large
; break;
244 model::LineEndWidth eLineEndWidth
= model::LineEndWidth::Unset
;
245 switch (rAttribs
.getToken(XML_w
, XML_TOKEN_INVALID
))
247 case XML_sm
: eLineEndWidth
= model::LineEndWidth::Small
; break;
248 case XML_med
: eLineEndWidth
= model::LineEndWidth::Medium
; break;
249 case XML_lg
: eLineEndWidth
= model::LineEndWidth::Large
; break;
254 if (nElement
== A_TOKEN(tailEnd
))
256 mpLineStyle
->maTailEnd
.meType
= eLineEndType
;
257 mpLineStyle
->maTailEnd
.meLength
= eLineEndLength
;
258 mpLineStyle
->maTailEnd
.meWidth
= eLineEndWidth
;
260 else if (nElement
== A_TOKEN(headEnd
))
262 mpLineStyle
->maHeadEnd
.meType
= eLineEndType
;
263 mpLineStyle
->maHeadEnd
.meLength
= eLineEndLength
;
264 mpLineStyle
->maHeadEnd
.meWidth
= eLineEndWidth
;
275 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */