bump product version to 6.3.0.0.beta1
[LibreOffice.git] / oox / source / vml / vmlshapecontext.cxx
blob621f20d29895bd4b6842081c259030157458cba6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
34 namespace oox {
35 namespace vml {
37 using namespace ::com::sun::star;
39 using ::oox::core::ContextHandler2;
40 using ::oox::core::ContextHandler2Helper;
41 using ::oox::core::ContextHandlerRef;
43 namespace {
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);
72 if( oValue.has() )
74 const OUString& aString(oValue.get());
75 const sal_Int32 nLength(aString.getLength());
77 if(nLength > 0)
79 if(aString.endsWith("f"))
81 fRetval = std::max(0.0, std::min(1.0, aString.toDouble() / 65536.0));
83 else
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;
99 if( oValue.has() )
101 OUString aValue1, aValue2;
102 ConversionHelper::separatePair( aValue1, aValue2, oValue.get(), ',' );
103 oRetValue = Int32Pair( aValue1.toInt32(), aValue2.toInt32() );
105 return oRetValue;
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;
114 if( oValue.has() )
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 ) );
122 return oRetValue;
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);
137 } // namespace
139 ShapeLayoutContext::ShapeLayoutContext( ContextHandler2Helper const & rParent, Drawing& rDrawing ) :
140 ContextHandler2( rParent ),
141 mrDrawing( rDrawing )
145 ContextHandlerRef ShapeLayoutContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
147 switch( nElement )
149 case O_TOKEN( idmap ):
151 OUString aBlockIds = rAttribs.getString( XML_data, OUString() );
152 sal_Int32 nIndex = 0;
153 while( nIndex >= 0 )
155 OUString aToken = aBlockIds.getToken( 0, ' ', nIndex ).trim();
156 if( !aToken.isEmpty() )
157 mrDrawing.registerBlockId( aToken.toInt32() );
160 break;
162 return nullptr;
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();
178 return this;
180 return nullptr;
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 )
233 switch( nElement )
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 );
247 else
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 );
262 // TODO:
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 );
271 return nullptr;
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
289 if( bHasOspid )
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" );
311 if( hrpct != "0" )
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 a arcsize attribute to read
329 mrTypeModel.maArcsize = rAttribs.getString(XML_arcsize, OUString());
330 // editas
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 );
355 break;
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 );
369 break;
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);
384 break;
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);
390 break;
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);
399 break;
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));
404 break;
406 return nullptr;
409 OptValue< OUString > ShapeTypeContext::decodeFragmentPath( const AttributeList& rAttribs, sal_Int32 nToken ) const
411 OptValue< OUString > oFragmentPath;
412 OptValue< OUString > oRelId = rAttribs.getString( nToken );
413 if( oRelId.has() )
414 oFragmentPath = getFragmentPathFromRelId( oRelId.get() );
415 return oFragmentPath;
418 void ShapeTypeContext::setStyle( const OUString& rStyle )
420 sal_Int32 nIndex = 0;
421 while( 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)
460 , mrShape(*pShape)
461 , mrShapeModel(pShape->getShapeModel())
463 // collect shape specific attributes
464 mrShapeModel.maType = rAttribs.getXString( XML_type, OUString() );
465 // polyline path
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()));
500 break;
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
516 break;
517 case O_TOKEN( lock ):
518 // TODO
519 break;
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;
530 while( 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);
607 } // namespace vml
608 } // namespace oox
610 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */