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 <oox/vml/vmlshapecontext.hxx>
22 #include <oox/core/xmlfilterbase.hxx>
23 #include <oox/helper/attributelist.hxx>
24 #include <oox/helper/helper.hxx>
25 #include <oox/token/namespaces.hxx>
26 #include <oox/token/tokens.hxx>
27 #include <oox/vml/vmldrawing.hxx>
28 #include <oox/vml/vmlshape.hxx>
29 #include <oox/vml/vmlshapecontainer.hxx>
30 #include <oox/vml/vmltextboxcontext.hxx>
32 #include <osl/diagnose.h>
37 using namespace ::com::sun::star
;
39 using ::oox::core::ContextHandler2
;
40 using ::oox::core::ContextHandler2Helper
;
41 using ::oox::core::ContextHandlerRef
;
45 /** Returns the boolean value from the specified VML attribute (if present).
47 OptValue
< bool > lclDecodeBool( const AttributeList
& rAttribs
, sal_Int32 nToken
)
49 OptValue
< OUString
> oValue
= rAttribs
.getString( nToken
);
50 if( oValue
.has() ) return OptValue
< bool >( ConversionHelper::decodeBool( oValue
.get() ) );
51 return OptValue
< bool >();
54 /** Returns the percentage value from the specified VML attribute (if present).
55 The value will be normalized (1.0 is returned for 100%).
57 OptValue
< double > lclDecodePercent( const AttributeList
& rAttribs
, sal_Int32 nToken
, double fDefValue
)
59 OptValue
< OUString
> oValue
= rAttribs
.getString( nToken
);
60 if( oValue
.has() ) return OptValue
< double >( ConversionHelper::decodePercent( oValue
.get(), fDefValue
) );
61 return OptValue
< double >();
64 /** #119750# Special method for opacity; it *should* be a percentage value, but there are cases
65 where a value relative to 0xffff (65536) is used, ending with an 'f'
67 OptValue
< double > lclDecodeOpacity( const AttributeList
& rAttribs
, sal_Int32 nToken
, double fDefValue
)
69 OptValue
< OUString
> oValue
= rAttribs
.getString( nToken
);
70 double fRetval(fDefValue
);
74 const OUString
& aString(oValue
.get());
75 const sal_Int32
nLength(aString
.getLength());
79 if(aString
.endsWith("f"))
81 fRetval
= std::max(0.0, std::min(1.0, aString
.toDouble() / 65536.0));
85 fRetval
= ConversionHelper::decodePercent( aString
, fDefValue
);
90 return OptValue
< double >(fRetval
);
93 /** Returns the integer value pair from the specified VML attribute (if present).
95 OptValue
< Int32Pair
> lclDecodeInt32Pair( const AttributeList
& rAttribs
, sal_Int32 nToken
)
97 OptValue
< OUString
> oValue
= rAttribs
.getString( nToken
);
98 OptValue
< Int32Pair
> oRetValue
;
101 OUString aValue1
, aValue2
;
102 ConversionHelper::separatePair( aValue1
, aValue2
, oValue
.get(), ',' );
103 oRetValue
= Int32Pair( aValue1
.toInt32(), aValue2
.toInt32() );
108 /** Returns the percentage pair from the specified VML attribute (if present).
110 OptValue
< DoublePair
> lclDecodePercentPair( const AttributeList
& rAttribs
, sal_Int32 nToken
)
112 OptValue
< OUString
> oValue
= rAttribs
.getString( nToken
);
113 OptValue
< DoublePair
> oRetValue
;
116 OUString aValue1
, aValue2
;
117 ConversionHelper::separatePair( aValue1
, aValue2
, oValue
.get(), ',' );
118 oRetValue
= DoublePair(
119 ConversionHelper::decodePercent( aValue1
, 0.0 ),
120 ConversionHelper::decodePercent( aValue2
, 0.0 ) );
125 /** Returns the boolean value from the passed string of an attribute in the x:
126 namespace (VML for spreadsheets). Supported values: f, t, False, True.
127 @param bDefaultForEmpty Default value for the empty string.
129 bool lclDecodeVmlxBool( const OUString
& rValue
, bool bDefaultForEmpty
)
131 if( rValue
.isEmpty() ) return bDefaultForEmpty
;
132 sal_Int32 nToken
= AttributeConversion::decodeToken( rValue
);
133 // anything else than 't' or 'True' is considered to be false, as specified
134 return (nToken
== XML_t
) || (nToken
== XML_True
);
139 ShapeLayoutContext::ShapeLayoutContext( ContextHandler2Helper
const & rParent
, Drawing
& rDrawing
) :
140 ContextHandler2( rParent
),
141 mrDrawing( rDrawing
)
145 ContextHandlerRef
ShapeLayoutContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
149 case O_TOKEN( idmap
):
151 OUString aBlockIds
= rAttribs
.getString( XML_data
, OUString() );
152 sal_Int32 nIndex
= 0;
155 OUString aToken
= aBlockIds
.getToken( 0, ' ', nIndex
).trim();
156 if( !aToken
.isEmpty() )
157 mrDrawing
.registerBlockId( aToken
.toInt32() );
165 ClientDataContext::ClientDataContext( ContextHandler2Helper
const & rParent
,
166 ClientData
& rClientData
, const AttributeList
& rAttribs
) :
167 ContextHandler2( rParent
),
168 mrClientData( rClientData
)
170 mrClientData
.mnObjType
= rAttribs
.getToken( XML_ObjectType
, XML_TOKEN_INVALID
);
173 ContextHandlerRef
ClientDataContext::onCreateContext( sal_Int32
/*nElement*/, const AttributeList
& /*rAttribs*/ )
175 if( isRootElement() )
177 maElementText
.clear();
183 void ClientDataContext::onCharacters( const OUString
& rChars
)
185 /* Empty but existing elements have special meaning, e.g. 'true'. Collect
186 existing text and convert it in onEndElement(). */
187 maElementText
= rChars
;
190 void ClientDataContext::onEndElement()
192 switch( getCurrentElement() )
194 case VMLX_TOKEN( Anchor
): mrClientData
.maAnchor
= maElementText
; break;
195 case VMLX_TOKEN( FmlaMacro
): mrClientData
.maFmlaMacro
= maElementText
; break;
196 case VMLX_TOKEN( FmlaPict
): mrClientData
.maFmlaPict
= maElementText
; break;
197 case VMLX_TOKEN( FmlaLink
): mrClientData
.maFmlaLink
= maElementText
; break;
198 case VMLX_TOKEN( FmlaRange
): mrClientData
.maFmlaRange
= maElementText
; break;
199 case VMLX_TOKEN( FmlaGroup
): mrClientData
.maFmlaGroup
= maElementText
; break;
200 case VMLX_TOKEN( TextHAlign
): mrClientData
.mnTextHAlign
= AttributeConversion::decodeToken( maElementText
); break;
201 case VMLX_TOKEN( TextVAlign
): mrClientData
.mnTextVAlign
= AttributeConversion::decodeToken( maElementText
); break;
202 case VMLX_TOKEN( Column
): mrClientData
.mnCol
= maElementText
.toInt32(); break;
203 case VMLX_TOKEN( Row
): mrClientData
.mnRow
= maElementText
.toInt32(); break;
204 case VMLX_TOKEN( Checked
): mrClientData
.mnChecked
= maElementText
.toInt32(); break;
205 case VMLX_TOKEN( DropStyle
): mrClientData
.mnDropStyle
= AttributeConversion::decodeToken( maElementText
); break;
206 case VMLX_TOKEN( DropLines
): mrClientData
.mnDropLines
= maElementText
.toInt32(); break;
207 case VMLX_TOKEN( Val
): mrClientData
.mnVal
= maElementText
.toInt32(); break;
208 case VMLX_TOKEN( Min
): mrClientData
.mnMin
= maElementText
.toInt32(); break;
209 case VMLX_TOKEN( Max
): mrClientData
.mnMax
= maElementText
.toInt32(); break;
210 case VMLX_TOKEN( Inc
): mrClientData
.mnInc
= maElementText
.toInt32(); break;
211 case VMLX_TOKEN( Page
): mrClientData
.mnPage
= maElementText
.toInt32(); break;
212 case VMLX_TOKEN( SelType
): mrClientData
.mnSelType
= AttributeConversion::decodeToken( maElementText
); break;
213 case VMLX_TOKEN( VTEdit
): mrClientData
.mnVTEdit
= maElementText
.toInt32(); break;
214 case VMLX_TOKEN( PrintObject
): mrClientData
.mbPrintObject
= lclDecodeVmlxBool( maElementText
, true ); break;
215 case VMLX_TOKEN( Visible
): mrClientData
.mbVisible
= lclDecodeVmlxBool( maElementText
, true ); break;
216 case VMLX_TOKEN( DDE
): mrClientData
.mbDde
= lclDecodeVmlxBool( maElementText
, true ); break;
217 case VMLX_TOKEN( NoThreeD
): mrClientData
.mbNo3D
= lclDecodeVmlxBool( maElementText
, true ); break;
218 case VMLX_TOKEN( NoThreeD2
): mrClientData
.mbNo3D2
= lclDecodeVmlxBool( maElementText
, true ); break;
219 case VMLX_TOKEN( MultiLine
): mrClientData
.mbMultiLine
= lclDecodeVmlxBool( maElementText
, true ); break;
220 case VMLX_TOKEN( VScroll
): mrClientData
.mbVScroll
= lclDecodeVmlxBool( maElementText
, true ); break;
221 case VMLX_TOKEN( SecretEdit
): mrClientData
.mbSecretEdit
= lclDecodeVmlxBool( maElementText
, true ); break;
225 ShapeContextBase::ShapeContextBase( ContextHandler2Helper
const & rParent
) :
226 ContextHandler2( rParent
)
230 ContextHandlerRef
ShapeContextBase::createShapeContext( ContextHandler2Helper
const & rParent
,
231 ShapeContainer
& rShapes
, sal_Int32 nElement
, const AttributeList
& rAttribs
)
235 case O_TOKEN( shapelayout
):
236 return new ShapeLayoutContext( rParent
, rShapes
.getDrawing() );
238 case VML_TOKEN( shapetype
):
239 return new ShapeTypeContext( rParent
, rShapes
.createShapeType(), rAttribs
);
240 case VML_TOKEN( group
):
241 return new GroupShapeContext( rParent
, rShapes
.createShape
< GroupShape
>(), rAttribs
);
242 case VML_TOKEN( shape
):
243 if (rAttribs
.hasAttribute(XML_path
) &&
244 // tdf#122563 skip in the case of empty path
245 !rAttribs
.getString(XML_path
, "").isEmpty())
246 return new ShapeContext( rParent
, rShapes
.createShape
< BezierShape
>(), rAttribs
);
248 return new ShapeContext( rParent
, rShapes
.createShape
< ComplexShape
>(), rAttribs
);
249 case VML_TOKEN( rect
):
250 return new RectangleShapeContext( rParent
, rAttribs
, rShapes
.createShape
< RectangleShape
>() );
251 case VML_TOKEN( roundrect
):
252 return new ShapeContext( rParent
, rShapes
.createShape
< RectangleShape
>(), rAttribs
);
253 case VML_TOKEN( oval
):
254 return new ShapeContext( rParent
, rShapes
.createShape
< EllipseShape
>(), rAttribs
);
255 case VML_TOKEN( polyline
):
256 return new ShapeContext( rParent
, rShapes
.createShape
< PolyLineShape
>(), rAttribs
);
257 case VML_TOKEN( line
):
258 return new ShapeContext( rParent
, rShapes
.createShape
< LineShape
>(), rAttribs
);
259 case VML_TOKEN( curve
):
260 return new ShapeContext( rParent
, rShapes
.createShape
< BezierShape
>(), rAttribs
);
263 case VML_TOKEN( arc
):
264 case VML_TOKEN( diagram
):
265 case VML_TOKEN( image
):
266 return new ShapeContext( rParent
, rShapes
.createShape
< ComplexShape
>(), rAttribs
);
268 case W_TOKEN(control
):
269 return new ControlShapeContext( rParent
, rShapes
, rAttribs
);
274 ShapeTypeContext::ShapeTypeContext(ContextHandler2Helper
const & rParent
,
275 std::shared_ptr
<ShapeType
> const& pShapeType
,
276 const AttributeList
& rAttribs
)
277 : ShapeContextBase(rParent
)
278 , m_pShapeType(pShapeType
) // tdf#112311 keep it alive
279 , mrTypeModel( pShapeType
->getTypeModel() )
281 // shape identifier and shape name
282 bool bHasOspid
= rAttribs
.hasAttribute( O_TOKEN( spid
) );
283 mrTypeModel
.maShapeId
= rAttribs
.getXString( bHasOspid
? O_TOKEN( spid
) : XML_id
, OUString() );
284 mrTypeModel
.maLegacyId
= rAttribs
.getString( XML_id
, OUString() );
285 OSL_ENSURE( !mrTypeModel
.maShapeId
.isEmpty(), "ShapeTypeContext::ShapeTypeContext - missing shape identifier" );
286 // builtin shape type identifier
287 mrTypeModel
.moShapeType
= rAttribs
.getInteger( O_TOKEN( spt
) );
288 // if the o:spid attribute exists, the id attribute contains the user-defined shape name
291 mrTypeModel
.maShapeName
= rAttribs
.getXString( XML_id
, OUString() );
292 // get ShapeType and ShapeId from name for compatibility
293 static const OUString sShapeTypePrefix
= "shapetype_";
294 if( mrTypeModel
.maShapeName
.startsWith( sShapeTypePrefix
) )
296 mrTypeModel
.maShapeId
= mrTypeModel
.maShapeName
;
297 mrTypeModel
.moShapeType
= mrTypeModel
.maShapeName
.copy(sShapeTypePrefix
.getLength()).toInt32();
301 // coordinate system position/size, CSS style
302 mrTypeModel
.moCoordPos
= lclDecodeInt32Pair( rAttribs
, XML_coordorigin
);
303 mrTypeModel
.moCoordSize
= lclDecodeInt32Pair( rAttribs
, XML_coordsize
);
304 setStyle( rAttribs
.getString( XML_style
, OUString() ) );
305 if( lclDecodeBool( rAttribs
, O_TOKEN( hr
)).get( false ))
306 { // MSO's handling of o:hr width is nowhere near what the spec says:
307 // - o:hrpct is not in % but in 0.1%
308 // - if o:hrpct is not given, 100% width is assumed
309 // - given width is used only if explicit o:hrpct="0" is given
310 OUString hrpct
= rAttribs
.getString( O_TOKEN( hrpct
), "1000" );
312 mrTypeModel
.maWidthPercent
= OUString::number( hrpct
.toInt32() );
313 mrTypeModel
.maWrapDistanceLeft
= "0";
314 mrTypeModel
.maWrapDistanceRight
= "0";
315 mrTypeModel
.maPositionHorizontal
= rAttribs
.getString( O_TOKEN( hralign
), "left" );
316 mrTypeModel
.moWrapType
= "topAndBottom";
319 // stroke settings (may be overridden by v:stroke element later)
320 mrTypeModel
.maStrokeModel
.moStroked
= lclDecodeBool( rAttribs
, XML_stroked
);
321 mrTypeModel
.maStrokeModel
.moColor
= rAttribs
.getString( XML_strokecolor
);
322 mrTypeModel
.maStrokeModel
.moWeight
= rAttribs
.getString( XML_strokeweight
);
324 // fill settings (may be overridden by v:fill element later)
325 mrTypeModel
.maFillModel
.moFilled
= lclDecodeBool( rAttribs
, XML_filled
);
326 mrTypeModel
.maFillModel
.moColor
= rAttribs
.getString( XML_fillcolor
);
328 // For roundrect we may have an arcsize attribute to read
329 mrTypeModel
.maArcsize
= rAttribs
.getString(XML_arcsize
, OUString());
331 mrTypeModel
.maEditAs
= rAttribs
.getString(XML_editas
, OUString());
333 mrTypeModel
.maAdjustments
= rAttribs
.getString(XML_adj
, OUString());
336 ContextHandlerRef
ShapeTypeContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
338 if( isRootElement() ) switch( nElement
)
340 case VML_TOKEN( stroke
):
341 mrTypeModel
.maStrokeModel
.moStroked
.assignIfUsed( lclDecodeBool( rAttribs
, XML_on
) );
342 mrTypeModel
.maStrokeModel
.maStartArrow
.moArrowType
= rAttribs
.getToken( XML_startarrow
);
343 mrTypeModel
.maStrokeModel
.maStartArrow
.moArrowWidth
= rAttribs
.getToken( XML_startarrowwidth
);
344 mrTypeModel
.maStrokeModel
.maStartArrow
.moArrowLength
= rAttribs
.getToken( XML_startarrowlength
);
345 mrTypeModel
.maStrokeModel
.maEndArrow
.moArrowType
= rAttribs
.getToken( XML_endarrow
);
346 mrTypeModel
.maStrokeModel
.maEndArrow
.moArrowWidth
= rAttribs
.getToken( XML_endarrowwidth
);
347 mrTypeModel
.maStrokeModel
.maEndArrow
.moArrowLength
= rAttribs
.getToken( XML_endarrowlength
);
348 mrTypeModel
.maStrokeModel
.moColor
.assignIfUsed( rAttribs
.getString( XML_color
) );
349 mrTypeModel
.maStrokeModel
.moOpacity
= lclDecodeOpacity( rAttribs
, XML_opacity
, 1.0 );
350 mrTypeModel
.maStrokeModel
.moWeight
.assignIfUsed( rAttribs
.getString( XML_weight
) );
351 mrTypeModel
.maStrokeModel
.moDashStyle
= rAttribs
.getString( XML_dashstyle
);
352 mrTypeModel
.maStrokeModel
.moLineStyle
= rAttribs
.getToken( XML_linestyle
);
353 mrTypeModel
.maStrokeModel
.moEndCap
= rAttribs
.getToken( XML_endcap
);
354 mrTypeModel
.maStrokeModel
.moJoinStyle
= rAttribs
.getToken( XML_joinstyle
);
356 case VML_TOKEN( fill
):
357 mrTypeModel
.maFillModel
.moFilled
.assignIfUsed( lclDecodeBool( rAttribs
, XML_on
) );
358 mrTypeModel
.maFillModel
.moColor
.assignIfUsed( rAttribs
.getString( XML_color
) );
359 mrTypeModel
.maFillModel
.moOpacity
= lclDecodeOpacity( rAttribs
, XML_opacity
, 1.0 );
360 mrTypeModel
.maFillModel
.moColor2
= rAttribs
.getString( XML_color2
);
361 mrTypeModel
.maFillModel
.moOpacity2
= lclDecodeOpacity( rAttribs
, XML_opacity2
, 1.0 );
362 mrTypeModel
.maFillModel
.moType
= rAttribs
.getToken( XML_type
);
363 mrTypeModel
.maFillModel
.moAngle
= rAttribs
.getInteger( XML_angle
);
364 mrTypeModel
.maFillModel
.moFocus
= lclDecodePercent( rAttribs
, XML_focus
, 0.0 );
365 mrTypeModel
.maFillModel
.moFocusPos
= lclDecodePercentPair( rAttribs
, XML_focusposition
);
366 mrTypeModel
.maFillModel
.moFocusSize
= lclDecodePercentPair( rAttribs
, XML_focussize
);
367 mrTypeModel
.maFillModel
.moBitmapPath
= decodeFragmentPath( rAttribs
, O_TOKEN( relid
) );
368 mrTypeModel
.maFillModel
.moRotate
= lclDecodeBool( rAttribs
, XML_rotate
);
370 case VML_TOKEN( imagedata
):
372 // shapes in docx use r:id for the relationship id
373 // in xlsx it they use o:relid
374 bool bHasORelId
= rAttribs
.hasAttribute( O_TOKEN( relid
) );
375 mrTypeModel
.moGraphicPath
= decodeFragmentPath( rAttribs
, bHasORelId
? O_TOKEN( relid
) : R_TOKEN( id
) );
376 mrTypeModel
.moGraphicTitle
= rAttribs
.getString( O_TOKEN( title
) );
378 // Get crop attributes.
379 mrTypeModel
.moCropBottom
= rAttribs
.getString(XML_cropbottom
);
380 mrTypeModel
.moCropLeft
= rAttribs
.getString(XML_cropleft
);
381 mrTypeModel
.moCropRight
= rAttribs
.getString(XML_cropright
);
382 mrTypeModel
.moCropTop
= rAttribs
.getString(XML_croptop
);
385 case NMSP_vmlWord
| XML_wrap
:
386 mrTypeModel
.moWrapAnchorX
= rAttribs
.getString(XML_anchorx
);
387 mrTypeModel
.moWrapAnchorY
= rAttribs
.getString(XML_anchory
);
388 mrTypeModel
.moWrapType
= rAttribs
.getString(XML_type
);
389 mrTypeModel
.moWrapSide
= rAttribs
.getString(XML_side
);
391 case VML_TOKEN( shadow
):
393 mrTypeModel
.maShadowModel
.mbHasShadow
= true;
394 mrTypeModel
.maShadowModel
.moShadowOn
= lclDecodeBool(rAttribs
, XML_on
).get(false);
395 mrTypeModel
.maShadowModel
.moColor
.assignIfUsed(rAttribs
.getString(XML_color
));
396 mrTypeModel
.maShadowModel
.moOffset
.assignIfUsed(rAttribs
.getString(XML_offset
));
397 mrTypeModel
.maShadowModel
.moOpacity
= lclDecodePercent(rAttribs
, XML_opacity
, 1.0);
400 case VML_TOKEN( textpath
):
401 mrTypeModel
.maTextpathModel
.moString
.assignIfUsed(rAttribs
.getString(XML_string
));
402 mrTypeModel
.maTextpathModel
.moStyle
.assignIfUsed(rAttribs
.getString(XML_style
));
403 mrTypeModel
.maTextpathModel
.moTrim
.assignIfUsed(lclDecodeBool(rAttribs
, XML_trim
));
409 OptValue
< OUString
> ShapeTypeContext::decodeFragmentPath( const AttributeList
& rAttribs
, sal_Int32 nToken
) const
411 OptValue
< OUString
> oFragmentPath
;
412 OptValue
< OUString
> oRelId
= rAttribs
.getString( nToken
);
414 oFragmentPath
= getFragmentPathFromRelId( oRelId
.get() );
415 return oFragmentPath
;
418 void ShapeTypeContext::setStyle( const OUString
& rStyle
)
420 sal_Int32 nIndex
= 0;
423 OUString aName
, aValue
;
424 if( ConversionHelper::separatePair( aName
, aValue
, rStyle
.getToken( 0, ';', nIndex
), ':' ) )
426 if( aName
== "position" ) mrTypeModel
.maPosition
= aValue
;
427 else if( aName
== "z-index" ) mrTypeModel
.maZIndex
= aValue
;
428 else if( aName
== "left" ) mrTypeModel
.maLeft
= aValue
;
429 else if( aName
== "top" ) mrTypeModel
.maTop
= aValue
;
430 else if( aName
== "width" ) mrTypeModel
.maWidth
= aValue
;
431 else if( aName
== "height" ) mrTypeModel
.maHeight
= aValue
;
432 else if( aName
== "margin-left" ) mrTypeModel
.maMarginLeft
= aValue
;
433 else if( aName
== "margin-top" ) mrTypeModel
.maMarginTop
= aValue
;
434 else if( aName
== "mso-position-vertical-relative" ) mrTypeModel
.maPositionVerticalRelative
= aValue
;
435 else if( aName
== "mso-position-horizontal-relative" ) mrTypeModel
.maPositionHorizontalRelative
= aValue
;
436 else if( aName
== "mso-position-horizontal" ) mrTypeModel
.maPositionHorizontal
= aValue
;
437 else if( aName
== "mso-position-vertical" ) mrTypeModel
.maPositionVertical
= aValue
;
438 else if( aName
== "mso-width-percent" ) mrTypeModel
.maWidthPercent
= aValue
;
439 else if( aName
== "mso-width-relative" ) mrTypeModel
.maWidthRelative
= aValue
;
440 else if( aName
== "mso-height-percent" ) mrTypeModel
.maHeightPercent
= aValue
;
441 else if( aName
== "mso-height-relative" ) mrTypeModel
.maHeightRelative
= aValue
;
442 else if( aName
== "mso-fit-shape-to-text" ) mrTypeModel
.mbAutoHeight
= true;
443 else if( aName
== "rotation" ) mrTypeModel
.maRotation
= aValue
;
444 else if( aName
== "flip" ) mrTypeModel
.maFlip
= aValue
;
445 else if( aName
== "visibility" )
446 mrTypeModel
.mbVisible
= aValue
!= "hidden";
447 else if( aName
== "mso-wrap-style" ) mrTypeModel
.maWrapStyle
= aValue
;
448 else if ( aName
== "v-text-anchor" ) mrTypeModel
.maVTextAnchor
= aValue
;
449 else if ( aName
== "mso-wrap-distance-left" ) mrTypeModel
.maWrapDistanceLeft
= aValue
;
450 else if ( aName
== "mso-wrap-distance-right" ) mrTypeModel
.maWrapDistanceRight
= aValue
;
451 else if ( aName
== "mso-wrap-distance-top" ) mrTypeModel
.maWrapDistanceTop
= aValue
;
452 else if ( aName
== "mso-wrap-distance-bottom" ) mrTypeModel
.maWrapDistanceBottom
= aValue
;
457 ShapeContext::ShapeContext(ContextHandler2Helper
const& rParent
,
458 const std::shared_ptr
<ShapeBase
>& pShape
, const AttributeList
& rAttribs
)
459 : ShapeTypeContext(rParent
, pShape
, rAttribs
)
461 , mrShapeModel(pShape
->getShapeModel())
463 // collect shape specific attributes
464 mrShapeModel
.maType
= rAttribs
.getXString( XML_type
, OUString() );
466 setPoints( rAttribs
.getString( XML_points
, OUString() ) );
467 // line start and end positions
468 setFrom(rAttribs
.getString(XML_from
, OUString()));
469 setTo(rAttribs
.getString(XML_to
, OUString()));
470 setControl1(rAttribs
.getString(XML_control1
, OUString()));
471 setControl2(rAttribs
.getString(XML_control2
, OUString()));
472 setVmlPath(rAttribs
.getString(XML_path
, OUString()));
475 ContextHandlerRef
ShapeContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
477 // Excel specific shape client data
478 if( isRootElement() ) switch( nElement
)
480 case VML_TOKEN( textbox
):
481 if (getParentElement() != VML_TOKEN( group
))
483 // Custom shape in Writer with a textbox are transformed into a frame
484 dynamic_cast<SimpleShape
&>( mrShape
).setService(
485 "com.sun.star.text.TextFrame");
487 else if (getCurrentElement() == VML_TOKEN(rect
))
488 // Transform only rectangles into a TextShape inside a groupshape.
489 dynamic_cast<SimpleShape
&>(mrShape
).setService("com.sun.star.drawing.TextShape");
490 return new TextBoxContext( *this, mrShapeModel
.createTextBox(mrShape
.getTypeModel()), rAttribs
,
491 mrShape
.getDrawing().getFilter().getGraphicHelper());
492 case VMLX_TOKEN( ClientData
):
493 return new ClientDataContext( *this, mrShapeModel
.createClientData(), rAttribs
);
494 case VMLPPT_TOKEN( textdata
):
495 // Force RectangleShape, this is ugly :(
496 // and is there because of the lines above which change it to TextFrame
497 dynamic_cast< SimpleShape
& >( mrShape
).setService(
498 "com.sun.star.drawing.RectangleShape");
499 mrShapeModel
.maLegacyDiagramPath
= getFragmentPathFromRelId(rAttribs
.getString(XML_id
, OUString()));
501 case O_TOKEN( signatureline
):
502 mrShapeModel
.mbIsSignatureLine
= true;
503 mrShapeModel
.maSignatureId
= rAttribs
.getString(XML_id
, OUString());
504 mrShapeModel
.maSignatureLineSuggestedSignerName
505 = rAttribs
.getString(O_TOKEN(suggestedsigner
), OUString());
506 mrShapeModel
.maSignatureLineSuggestedSignerTitle
507 = rAttribs
.getString(O_TOKEN(suggestedsigner2
), OUString());
508 mrShapeModel
.maSignatureLineSuggestedSignerEmail
509 = rAttribs
.getString(O_TOKEN(suggestedsigneremail
), OUString());
510 mrShapeModel
.maSignatureLineSigningInstructions
511 = rAttribs
.getString(O_TOKEN(signinginstructions
), OUString());
512 mrShapeModel
.mbSignatureLineShowSignDate
= ConversionHelper::decodeBool(
513 rAttribs
.getString(XML_showsigndate
, "t")); // default is true
514 mrShapeModel
.mbSignatureLineCanAddComment
= ConversionHelper::decodeBool(
515 rAttribs
.getString(XML_allowcomments
, "f")); // default is false
517 case O_TOKEN( lock
):
521 // handle remaining stuff in base class
522 return ShapeTypeContext::onCreateContext( nElement
, rAttribs
);
525 void ShapeContext::setPoints( const OUString
& rPoints
)
527 mrShapeModel
.maPoints
.clear();
528 sal_Int32 nIndex
= 0;
532 sal_Int32 nX
= rPoints
.getToken( 0, ',', nIndex
).toInt32();
533 sal_Int32 nY
= rPoints
.getToken( 0, ',', nIndex
).toInt32();
534 mrShapeModel
.maPoints
.emplace_back( nX
, nY
);
538 void ShapeContext::setFrom( const OUString
& rPoints
)
540 if (!rPoints
.isEmpty())
541 mrShapeModel
.maFrom
= rPoints
;
544 void ShapeContext::setTo( const OUString
& rPoints
)
546 if (!rPoints
.isEmpty())
547 mrShapeModel
.maTo
= rPoints
;
550 void ShapeContext::setControl1( const OUString
& rPoints
)
552 if (!rPoints
.isEmpty())
553 mrShapeModel
.maControl1
= rPoints
;
556 void ShapeContext::setControl2( const OUString
& rPoints
)
558 if (!rPoints
.isEmpty())
559 mrShapeModel
.maControl2
= rPoints
;
561 void ShapeContext::setVmlPath( const OUString
& rPath
)
563 if (!rPath
.isEmpty())
564 mrShapeModel
.maVmlPath
= rPath
;
567 GroupShapeContext::GroupShapeContext(ContextHandler2Helper
const& rParent
,
568 const std::shared_ptr
<GroupShape
>& pShape
,
569 const AttributeList
& rAttribs
)
570 : ShapeContext(rParent
, pShape
, rAttribs
)
571 , mrShapes(pShape
->getChildren())
575 ContextHandlerRef
GroupShapeContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
577 // try to create a context of an embedded shape
578 ContextHandlerRef xContext
= createShapeContext( *this, mrShapes
, nElement
, rAttribs
);
579 // handle remaining stuff of this shape in base class
580 return xContext
.get() ? xContext
: ShapeContext::onCreateContext( nElement
, rAttribs
);
583 RectangleShapeContext::RectangleShapeContext(ContextHandler2Helper
const& rParent
,
584 const AttributeList
& rAttribs
,
585 const std::shared_ptr
<RectangleShape
>& pShape
)
586 : ShapeContext(rParent
, pShape
, rAttribs
)
590 ContextHandlerRef
RectangleShapeContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
592 // The parent class's context is fine
593 return ShapeContext::onCreateContext( nElement
, rAttribs
);
596 ControlShapeContext::ControlShapeContext( ::oox::core::ContextHandler2Helper
const & rParent
, ShapeContainer
& rShapes
, const AttributeList
& rAttribs
)
597 : ShapeContextBase (rParent
)
599 ::oox::vml::ControlInfo aInfo
;
600 aInfo
.maShapeId
= rAttribs
.getXString( W_TOKEN( shapeid
), OUString() );
601 aInfo
.maFragmentPath
= getFragmentPathFromRelId(rAttribs
.getString( R_TOKEN(id
), OUString() ));
602 aInfo
.maName
= rAttribs
.getString( W_TOKEN( name
), OUString() );
603 aInfo
.mbTextContentShape
= true;
604 rShapes
.getDrawing().registerControl(aInfo
);
610 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */