LCOV - code coverage report
Current view: top level - oox/source/vml - vmlformatting.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 374 449 83.3 %
Date: 2014-11-03 Functions: 29 29 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : #include "oox/vml/vmlformatting.hxx"
      20             : 
      21             : #include <com/sun/star/beans/PropertyValue.hpp>
      22             : #include <com/sun/star/beans/XPropertySet.hpp>
      23             : #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
      24             : #include <com/sun/star/table/ShadowFormat.hpp>
      25             : #include <com/sun/star/text/XTextRange.hpp>
      26             : #include <rtl/strbuf.hxx>
      27             : #include "oox/drawingml/color.hxx"
      28             : #include "oox/drawingml/drawingmltypes.hxx"
      29             : #include "oox/drawingml/fillproperties.hxx"
      30             : #include "oox/drawingml/lineproperties.hxx"
      31             : #include "oox/drawingml/shapepropertymap.hxx"
      32             : #include "oox/helper/attributelist.hxx"
      33             : #include "oox/helper/graphichelper.hxx"
      34             : 
      35             : namespace oox {
      36             : namespace vml {
      37             : 
      38             : using namespace ::com::sun::star;
      39             : using namespace ::com::sun::star::geometry;
      40             : 
      41             : using ::oox::drawingml::Color;
      42             : using ::oox::drawingml::FillProperties;
      43             : using ::oox::drawingml::LineArrowProperties;
      44             : using ::oox::drawingml::LineProperties;
      45             : using ::oox::drawingml::ShapePropertyMap;
      46             : using ::com::sun::star::awt::Point;
      47             : using ::com::sun::star::drawing::PolygonFlags;
      48             : using ::com::sun::star::drawing::PolygonFlags_NORMAL;
      49             : using ::com::sun::star::drawing::PolygonFlags_CONTROL;
      50             : 
      51             : namespace {
      52             : 
      53        7826 : bool lclExtractDouble( double& orfValue, sal_Int32& ornEndPos, const OUString& rValue )
      54             : {
      55             :     // extract the double value and find start position of unit characters
      56        7826 :     rtl_math_ConversionStatus eConvStatus = rtl_math_ConversionStatus_Ok;
      57        7826 :     orfValue = ::rtl::math::stringToDouble( rValue, '.', '\0', &eConvStatus, &ornEndPos );
      58        7826 :     return eConvStatus == rtl_math_ConversionStatus_Ok;
      59             : }
      60             : 
      61             : } // namespace
      62             : 
      63       18288 : bool ConversionHelper::separatePair( OUString& orValue1, OUString& orValue2,
      64             :         const OUString& rValue, sal_Unicode cSep )
      65             : {
      66       18288 :     sal_Int32 nSepPos = rValue.indexOf( cSep );
      67       18288 :     if( nSepPos >= 0 )
      68             :     {
      69       15274 :         orValue1 = rValue.copy( 0, nSepPos ).trim();
      70       15274 :         orValue2 = rValue.copy( nSepPos + 1 ).trim();
      71             :     }
      72             :     else
      73             :     {
      74        3014 :         orValue1 = rValue.trim();
      75             :     }
      76       18288 :     return !orValue1.isEmpty() && !orValue2.isEmpty();
      77             : }
      78             : 
      79        1858 : bool ConversionHelper::decodeBool( const OUString& rValue )
      80             : {
      81        1858 :     sal_Int32 nToken = AttributeConversion::decodeToken( rValue );
      82             :     // anything else than 't' or 'true' is considered to be false, as specified
      83        1858 :     return (nToken == XML_t) || (nToken == XML_true);
      84             : }
      85             : 
      86         120 : double ConversionHelper::decodePercent( const OUString& rValue, double fDefValue )
      87             : {
      88         120 :     if( rValue.isEmpty() )
      89          28 :         return fDefValue;
      90             : 
      91          92 :     double fValue = 0.0;
      92          92 :     sal_Int32 nEndPos = 0;
      93          92 :     if( !lclExtractDouble( fValue, nEndPos, rValue ) )
      94           0 :         return fDefValue;
      95             : 
      96          92 :     if( nEndPos == rValue.getLength() )
      97          58 :         return fValue;
      98             : 
      99          34 :     if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == '%') )
     100          18 :         return fValue / 100.0;
     101             : 
     102          16 :     if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == 'f') )
     103          16 :         return fValue / 65536.0;
     104             : 
     105             :     OSL_FAIL( "ConversionHelper::decodePercent - unknown measure unit" );
     106           0 :     return fDefValue;
     107             : }
     108             : 
     109        9858 : sal_Int64 ConversionHelper::decodeMeasureToEmu( const GraphicHelper& rGraphicHelper,
     110             :         const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel )
     111             : {
     112             :     // default for missing values is 0
     113        9858 :     if( rValue.isEmpty() )
     114        2124 :         return 0;
     115             : 
     116             :     // TODO: according to spec, value may contain "auto"
     117        7734 :     if ( rValue == "auto" )
     118             :     {
     119             :         OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - special value 'auto' must be handled by caller" );
     120           0 :         return nRefValue;
     121             :     }
     122             : 
     123             :     // extract the double value and find start position of unit characters
     124        7734 :     double fValue = 0.0;
     125        7734 :     sal_Int32 nEndPos = 0;
     126        7734 :     if( !lclExtractDouble( fValue, nEndPos, rValue ) || (fValue == 0.0) )
     127        1494 :         return 0;
     128             : 
     129             :     // process trailing unit, convert to EMU
     130        6240 :     OUString aUnit;
     131        6240 :     if( (0 < nEndPos) && (nEndPos < rValue.getLength()) )
     132        3160 :         aUnit = rValue.copy( nEndPos );
     133        3080 :     else if( bDefaultAsPixel )
     134           0 :         aUnit = "px";
     135             :     // else default is EMU
     136             : 
     137        6240 :     if( aUnit.getLength() == 2 )
     138             :     {
     139        3144 :         sal_Unicode cChar1 = aUnit[ 0 ];
     140        3144 :         sal_Unicode cChar2 = aUnit[ 1 ];
     141        3144 :         if( (cChar1 == 'i') && (cChar2 == 'n') )        // 1 inch = 914,400 EMU
     142         970 :             fValue *= 914400.0;
     143        2174 :         else if( (cChar1 == 'c') && (cChar2 == 'm') )   // 1 cm = 360,000 EMU
     144           0 :             fValue *= 360000.0;
     145        2174 :         else if( (cChar1 == 'm') && (cChar2 == 'm') )   // 1 mm = 36,000 EMU
     146         226 :             fValue *= 36000.0;
     147        1948 :         else if( (cChar1 == 'p') && (cChar2 == 't') )   // 1 point = 1/72 inch = 12,700 EMU
     148        1948 :             fValue *= 12700.0;
     149           0 :         else if( (cChar1 == 'p') && (cChar2 == 'c') )   // 1 pica = 1/6 inch = 152,400 EMU
     150           0 :             fValue *= 152400.0;
     151           0 :         else if( (cChar1 == 'p') && (cChar2 == 'x') )   // 1 pixel, dependent on output device
     152             :             fValue = static_cast< double >( ::oox::drawingml::convertHmmToEmu(
     153             :                 bPixelX ?
     154           0 :                     rGraphicHelper.convertScreenPixelXToHmm( fValue ) :
     155           0 :                     rGraphicHelper.convertScreenPixelYToHmm( fValue ) ) );
     156             :     }
     157        3096 :     else if( (aUnit.getLength() == 1) && (aUnit[ 0 ] == '%') )
     158             :     {
     159          16 :         fValue *= nRefValue / 100.0;
     160             :     }
     161        3080 :     else if( bDefaultAsPixel || !aUnit.isEmpty() )   // default as EMU and no unit -> do nothing
     162             :     {
     163             :         OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - unknown measure unit" );
     164           0 :         fValue = nRefValue;
     165             :     }
     166        6240 :     return static_cast< sal_Int64 >( fValue + 0.5 );
     167             : }
     168             : 
     169        9592 : sal_Int32 ConversionHelper::decodeMeasureToHmm( const GraphicHelper& rGraphicHelper,
     170             :         const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel )
     171             : {
     172        9592 :     return ::oox::drawingml::convertEmuToHmm( decodeMeasureToEmu( rGraphicHelper, rValue, nRefValue, bPixelX, bDefaultAsPixel ) );
     173             : }
     174             : 
     175        1920 : Color ConversionHelper::decodeColor( const GraphicHelper& rGraphicHelper,
     176             :         const OptValue< OUString >& roVmlColor, const OptValue< double >& roVmlOpacity,
     177             :         sal_Int32 nDefaultRgb, sal_Int32 nPrimaryRgb )
     178             : {
     179        1920 :     Color aDmlColor;
     180             : 
     181             :     // convert opacity
     182        1920 :     const sal_Int32 DML_FULL_OPAQUE = ::oox::drawingml::MAX_PERCENT;
     183        1920 :     double fOpacity = roVmlOpacity.get( 1.0 );
     184        1920 :     sal_Int32 nOpacity = getLimitedValue< sal_Int32, double >( fOpacity * DML_FULL_OPAQUE, 0, DML_FULL_OPAQUE );
     185        1920 :     if( nOpacity < DML_FULL_OPAQUE )
     186          90 :         aDmlColor.addTransformation( XML_alpha, nOpacity );
     187             : 
     188             :     // color attribute not present - set passed default color
     189        1920 :     if( !roVmlColor.has() )
     190             :     {
     191         554 :         aDmlColor.setSrgbClr( nDefaultRgb );
     192         554 :         return aDmlColor;
     193             :     }
     194             : 
     195             :     // separate leading color name or RGB value from following palette index
     196        2732 :     OUString aColorName, aColorIndex;
     197        1366 :     separatePair( aColorName, aColorIndex, roVmlColor.get(), ' ' );
     198             : 
     199             :     // RGB colors in the format '#RRGGBB'
     200        1366 :     if( (aColorName.getLength() == 7) && (aColorName[ 0 ] == '#') )
     201             :     {
     202         868 :         aDmlColor.setSrgbClr( aColorName.copy( 1 ).toUInt32( 16 ) );
     203         868 :         return aDmlColor;
     204             :     }
     205             : 
     206             :     // RGB colors in the format '#RGB'
     207         498 :     if( (aColorName.getLength() == 4) && (aColorName[ 0 ] == '#') )
     208             :     {
     209         110 :         sal_Int32 nR = aColorName.copy( 1, 1 ).toUInt32( 16 ) * 0x11;
     210         110 :         sal_Int32 nG = aColorName.copy( 2, 1 ).toUInt32( 16 ) * 0x11;
     211         110 :         sal_Int32 nB = aColorName.copy( 3, 1 ).toUInt32( 16 ) * 0x11;
     212         110 :         aDmlColor.setSrgbClr( (nR << 16) | (nG << 8) | nB );
     213         110 :         return aDmlColor;
     214             :     }
     215             : 
     216             :     /*  Predefined color names or system color names (resolve to RGB to detect
     217             :         valid color name). */
     218         388 :     sal_Int32 nColorToken = AttributeConversion::decodeToken( aColorName );
     219         388 :     sal_Int32 nRgbValue = Color::getVmlPresetColor( nColorToken, API_RGB_TRANSPARENT );
     220         388 :     if( nRgbValue == API_RGB_TRANSPARENT )
     221           8 :         nRgbValue = rGraphicHelper.getSystemColor( nColorToken, API_RGB_TRANSPARENT );
     222         388 :     if( nRgbValue != API_RGB_TRANSPARENT )
     223             :     {
     224         380 :         aDmlColor.setSrgbClr( nRgbValue );
     225         380 :         return aDmlColor;
     226             :     }
     227             : 
     228             :     // try palette colors enclosed in brackets
     229           8 :     if( (aColorIndex.getLength() >= 3) && (aColorIndex[ 0 ] == '[') && (aColorIndex[ aColorIndex.getLength() - 1 ] == ']') )
     230             :     {
     231           0 :         aDmlColor.setPaletteClr( aColorIndex.copy( 1, aColorIndex.getLength() - 2 ).toInt32() );
     232           0 :         return aDmlColor;
     233             :     }
     234             : 
     235             :     // try fill gradient modificator 'fill <modifier>(<amount>)'
     236           8 :     if( (nPrimaryRgb != API_RGB_TRANSPARENT) && (nColorToken == XML_fill) )
     237             :     {
     238           4 :         sal_Int32 nOpenParen = aColorIndex.indexOf( '(' );
     239           4 :         sal_Int32 nCloseParen = aColorIndex.indexOf( ')' );
     240           4 :         if( (2 <= nOpenParen) && (nOpenParen + 1 < nCloseParen) && (nCloseParen + 1 == aColorIndex.getLength()) )
     241             :         {
     242           4 :             sal_Int32 nModToken = XML_TOKEN_INVALID;
     243           4 :             switch( AttributeConversion::decodeToken( aColorIndex.copy( 0, nOpenParen ) ) )
     244             :             {
     245           0 :                 case XML_darken:    nModToken = XML_shade;break;
     246           4 :                 case XML_lighten:   nModToken = XML_tint;
     247             :             }
     248           4 :             sal_Int32 nValue = aColorIndex.copy( nOpenParen + 1, nCloseParen - nOpenParen - 1 ).toInt32();
     249           4 :             if( (nModToken != XML_TOKEN_INVALID) && (0 <= nValue) && (nValue < 255) )
     250             :             {
     251             :                 /*  Simulate this modifier color by a color with related transformation.
     252             :                     The modifier amount has to be converted from the range [0;255] to
     253             :                     percentage [0;100000] used by DrawingML. */
     254           4 :                 aDmlColor.setSrgbClr( nPrimaryRgb );
     255           4 :                 aDmlColor.addTransformation( nModToken, static_cast< sal_Int32 >( nValue * ::oox::drawingml::MAX_PERCENT / 255 ) );
     256           4 :                 return aDmlColor;
     257             :             }
     258             :         }
     259             :     }
     260             : 
     261             :     OSL_FAIL( OStringBuffer( "lclGetColor - invalid VML color name '" ).
     262             :         append( OUStringToOString( roVmlColor.get(), RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() );
     263           4 :     aDmlColor.setSrgbClr( nDefaultRgb );
     264           4 :     return aDmlColor;
     265             : }
     266             : 
     267         682 : void ConversionHelper::decodeVmlPath( ::std::vector< ::std::vector< Point > >& rPointLists, ::std::vector< ::std::vector< PolygonFlags > >& rFlagLists, const OUString& rPath )
     268             : {
     269         682 :     ::std::vector< sal_Int32 > aCoordList;
     270         682 :     Point aCurrentPoint;
     271         682 :     sal_Int32 nTokenStart = 0;
     272         682 :     sal_Int32 nTokenLen = 0;
     273         682 :     sal_Int32 nParamCount = 0;
     274         682 :     bool bCommand = false;
     275             :     enum VML_State { START, MOVE_REL, MOVE_ABS, BEZIER_REL, BEZIER_ABS,
     276             :                      LINE_REL, LINE_ABS, CLOSE, END, UNSUPPORTED };
     277         682 :     VML_State state = START;
     278             : 
     279         682 :     rPointLists.push_back( ::std::vector< Point>() );
     280         682 :     rFlagLists.push_back( ::std::vector< PolygonFlags >() );
     281             : 
     282      199220 :     for ( sal_Int32 i = 0; i < rPath.getLength(); i++ )
     283             :     {
     284             :         // Keep track of current integer token
     285      198538 :         if ( ( rPath[ i ] >= '0' && rPath[ i ] <= '9' ) || rPath[ i ] == '-' )
     286      136260 :             nTokenLen++;
     287       62278 :         else if ( rPath[ i ] != ' ' )
     288             :         {
     289             :             // Store coordinate from current token
     290       62278 :             if ( state != START && state != UNSUPPORTED )
     291             :             {
     292       61594 :                 if ( nTokenLen > 0 )
     293       54276 :                     aCoordList.push_back( rPath.copy( nTokenStart, nTokenLen ).toInt32() );
     294             :                 else
     295        7318 :                     aCoordList.push_back( 0 );
     296       61594 :                 nTokenLen = 0;
     297             :             }
     298             : 
     299       62278 :             if (rPath[ i ] == ',' )
     300             :             {
     301       36170 :                 nParamCount--;
     302             :             }
     303             : 
     304             :             // Upon finding the next command code, deal with stored
     305             :             // coordinates for previous command and reset parameters counter if needed.
     306             :             // See http://www.w3.org/TR/NOTE-VML#_Toc416858382 for params count reference
     307       62278 :             if ( rPath[ i ] != ',' || nParamCount == 0 )
     308             :             {
     309       30370 :                 switch ( state )
     310             :                 {
     311             :                 case MOVE_REL: // 2* params -> param count reset
     312           0 :                     if ( rPointLists.size() > 0 && rPointLists.back().size() > 0 )
     313             :                     {
     314           0 :                         rPointLists.push_back( ::std::vector< Point >() );
     315           0 :                         rFlagLists.push_back( ::std::vector< PolygonFlags >() );
     316             :                     }
     317           0 :                     rPointLists.back().push_back( Point( aCoordList[ 0 ], aCoordList[ 1 ] ) );
     318           0 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     319           0 :                     aCurrentPoint = rPointLists.back().back();
     320           0 :                     nParamCount = 2;
     321           0 :                     break;
     322             : 
     323             :                 case MOVE_ABS: // 2 params -> no param count reset
     324        1096 :                     if ( rPointLists.size() > 0 && rPointLists.back().size() > 0 )
     325             :                     {
     326         408 :                         rPointLists.push_back( ::std::vector< Point >() );
     327         408 :                         rFlagLists.push_back( ::std::vector< PolygonFlags >() );
     328             :                     }
     329        1096 :                     rPointLists.back().push_back( Point( (aCoordList[ 0 ]), (aCoordList.size() > 1 ? aCoordList[ 1 ] : 0) ) );
     330        1096 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     331        1096 :                     aCurrentPoint = rPointLists.back().back();
     332        1096 :                     break;
     333             : 
     334             :                 case BEZIER_REL: // 6* params -> param count reset
     335         672 :                     rPointLists.back().push_back( Point( aCurrentPoint.X + aCoordList[ 0 ],
     336        1008 :                                             aCurrentPoint.Y + aCoordList[ 1 ] ) );
     337         672 :                     rPointLists.back().push_back( Point( aCurrentPoint.X + aCoordList[ 2 ],
     338        1008 :                                             aCurrentPoint.Y + aCoordList[ 3 ] ) );
     339         672 :                     rPointLists.back().push_back( Point( aCurrentPoint.X + aCoordList[ 4 ],
     340        1008 :                                             aCurrentPoint.Y + aCoordList[ 5 ] ) );
     341         336 :                     rFlagLists.back().push_back( PolygonFlags_CONTROL );
     342         336 :                     rFlagLists.back().push_back( PolygonFlags_CONTROL );
     343         336 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     344         336 :                     aCurrentPoint = rPointLists.back().back();
     345         336 :                     nParamCount = 6;
     346         336 :                     break;
     347             : 
     348             :                 case BEZIER_ABS: // 6* params -> param count reset
     349         494 :                     rPointLists.back().push_back( Point( aCoordList[ 0 ], aCoordList[ 1 ] ) );
     350         494 :                     rPointLists.back().push_back( Point( aCoordList[ 2 ], aCoordList[ 3 ] ) );
     351         494 :                     rPointLists.back().push_back( Point( aCoordList[ 4 ], aCoordList[ 5 ] ) );
     352         494 :                     rFlagLists.back().push_back( PolygonFlags_CONTROL );
     353         494 :                     rFlagLists.back().push_back( PolygonFlags_CONTROL );
     354         494 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     355         494 :                     aCurrentPoint = rPointLists.back().back();
     356         494 :                     nParamCount = 6;
     357         494 :                     break;
     358             : 
     359             :                 case LINE_REL: // 2* params -> param count reset
     360       21908 :                     rPointLists.back().push_back( Point( aCurrentPoint.X + aCoordList[ 0 ],
     361       32862 :                                             aCurrentPoint.Y + aCoordList[ 1 ] ) );
     362       10954 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     363       10954 :                     aCurrentPoint = rPointLists.back().back();
     364       10954 :                     nParamCount = 2;
     365       10954 :                     break;
     366             : 
     367             :                 case LINE_ABS: // 2* params -> param count reset
     368       15720 :                     rPointLists.back().push_back( Point( aCoordList[ 0 ], (aCoordList.size() > 1 ? aCoordList[ 1 ] : 0) ) );
     369       15720 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     370       15720 :                     aCurrentPoint = rPointLists.back().back();
     371       15720 :                     nParamCount = 2;
     372       15720 :                     break;
     373             : 
     374             :                 case CLOSE: // 0 param
     375        1080 :                     rPointLists.back().push_back( rPointLists.back()[ 0 ] );
     376        1080 :                     rFlagLists.back().push_back( rFlagLists.back()[ 0 ] );
     377        1080 :                     aCurrentPoint = rPointLists.back().back();
     378        1080 :                     break;
     379             : 
     380             :                 case END: // 0 param
     381           6 :                     rPointLists.push_back( ::std::vector< Point >() );
     382           6 :                     rFlagLists.push_back( ::std::vector< PolygonFlags >() );
     383           6 :                     break;
     384             : 
     385             :                 case START:
     386             :                 case UNSUPPORTED:
     387         684 :                     break;
     388             :                 }
     389             : 
     390       30370 :                 aCoordList.clear();
     391             :             }
     392             : 
     393             :             // Allow two-char commands to peek ahead to the next character
     394       62278 :             char nextChar = '\0';
     395       62278 :             if (i+1 < rPath.getLength())
     396       61596 :                 nextChar = rPath[i+1];
     397             : 
     398             :             // Move to relevant state upon finding a command
     399       62278 :             bCommand = true;
     400       62278 :             switch ( rPath[ i ] )
     401             :             {
     402             :             // Single-character commands
     403             :             case 't': // rmoveto
     404           0 :                 state = MOVE_REL; nParamCount = 2; break;
     405             :             case 'm': // moveto
     406        1092 :                 state = MOVE_ABS; nParamCount = 2; break;
     407             :             case 'v': // rcurveto
     408         336 :                 state = BEZIER_REL; nParamCount = 6; break;
     409             :             case 'c': // curveto
     410         470 :                 state = BEZIER_ABS; nParamCount = 6; break;
     411             :             case 'r': // rlineto
     412       10954 :                 state = LINE_REL; nParamCount = 2; break;
     413             :             case 'l': // lineto
     414       11478 :                 state = LINE_ABS; nParamCount = 2; break;
     415             :             case 'x': // close
     416        1080 :                 state = CLOSE; break;
     417             :             case 'e': // end
     418         688 :                 state = END; break;
     419             : 
     420             :             // Two-character commands
     421             :             case 'n':
     422             :             {
     423           2 :                 switch ( nextChar )
     424             :                 {
     425             :                 case 'f': // nf - nofill
     426             :                 case 's': // ns - nostroke
     427           2 :                     state = UNSUPPORTED; i++; break;
     428             :                 }
     429           2 :                 break;
     430             :             }
     431             :             case 'a': // Elliptical curves
     432             :             {
     433           0 :                 switch ( nextChar )
     434             :                 {
     435             :                 case 'e': // ae - angleellipseto
     436             :                 case 'l': // al - angleellipse
     437           0 :                     state = UNSUPPORTED; i++; break;
     438             :                 case 't': // at - arcto
     439             :                 case 'r': // ar - arc
     440           0 :                     state = UNSUPPORTED; i++; break;
     441             :                 }
     442           0 :                 break;
     443             :             }
     444             :             case 'w': // Clockwise elliptical arcs
     445             :             {
     446           0 :                 switch ( nextChar )
     447             :                 {
     448             :                 case 'a': // wa - clockwisearcto
     449             :                 case 'r': // wr - clockwisearc
     450           0 :                     state = UNSUPPORTED; i++; break;
     451             :                 }
     452           0 :                 break;
     453             :             }
     454             :             case 'q':
     455             :             {
     456           0 :                 switch ( nextChar )
     457             :                 {
     458             :                 case 'x': // qx - ellipticalquadrantx
     459             :                 case 'y': // qy - ellipticalquadranty
     460           0 :                     state = UNSUPPORTED; i++; break;
     461             :                 case 'b': // qb - quadraticbezier
     462           0 :                     state = UNSUPPORTED; i++; break;
     463             :                 }
     464           0 :                 break;
     465             :             }
     466             :             case 'h': // behaviour extensions
     467             :             {
     468           0 :                 switch ( nextChar )
     469             :                 {
     470             :                 case 'a': // ha - AutoLine
     471             :                 case 'b': // hb - AutoCurve
     472             :                 case 'c': // hc - CornerLine
     473             :                 case 'd': // hd - CornerCurve
     474             :                 case 'e': // he - SmoothLine
     475             :                 case 'f': // hf - SmoothCurve
     476             :                 case 'g': // hg - SymmetricLine
     477             :                 case 'h': // hh - SymmetricCurve
     478             :                 case 'i': // hi - Freeform
     479           0 :                     state = UNSUPPORTED; i++; break;
     480             :                 }
     481           0 :                 break;
     482             :             }
     483             :             default:
     484       36178 :                 bCommand = false;
     485       36178 :                 break;
     486             :             }
     487             : 
     488       62278 :             if (bCommand) nTokenLen = 0;
     489       62278 :             nTokenStart = i+1;
     490             :         }
     491         682 :     }
     492         682 : }
     493             : 
     494             : namespace {
     495             : 
     496         584 : sal_Int64 lclGetEmu( const GraphicHelper& rGraphicHelper, const OptValue< OUString >& roValue, sal_Int64 nDefValue )
     497             : {
     498         584 :     return roValue.has() ? ConversionHelper::decodeMeasureToEmu( rGraphicHelper, roValue.get(), 0, false, false ) : nDefValue;
     499             : }
     500             : 
     501         584 : void lclGetDmlLineDash( OptValue< sal_Int32 >& oroPresetDash, LineProperties::DashStopVector& orCustomDash, const OptValue< OUString >& roDashStyle )
     502             : {
     503         584 :     if( roDashStyle.has() )
     504             :     {
     505           0 :         const OUString& rDashStyle = roDashStyle.get();
     506           0 :         switch( AttributeConversion::decodeToken( rDashStyle ) )
     507             :         {
     508           0 :             case XML_solid:             oroPresetDash = XML_solid;          return;
     509           0 :             case XML_shortdot:          oroPresetDash = XML_sysDot;         return;
     510           0 :             case XML_shortdash:         oroPresetDash = XML_sysDash;        return;
     511           0 :             case XML_shortdashdot:      oroPresetDash = XML_sysDashDot;     return;
     512           0 :             case XML_shortdashdotdot:   oroPresetDash = XML_sysDashDotDot;  return;
     513           0 :             case XML_dot:               oroPresetDash = XML_dot;            return;
     514           0 :             case XML_dash:              oroPresetDash = XML_dash;           return;
     515           0 :             case XML_dashdot:           oroPresetDash = XML_dashDot;        return;
     516           0 :             case XML_longdash:          oroPresetDash = XML_lgDash;         return;
     517           0 :             case XML_longdashdot:       oroPresetDash = XML_lgDashDot;      return;
     518           0 :             case XML_longdashdotdot:    oroPresetDash = XML_lgDashDotDot;   return;
     519             : 
     520             :             // try to convert user-defined dash style
     521             :             default:
     522             :             {
     523           0 :                 ::std::vector< sal_Int32 > aValues;
     524           0 :                 sal_Int32 nIndex = 0;
     525           0 :                 while( nIndex >= 0 )
     526           0 :                     aValues.push_back( rDashStyle.getToken( 0, ' ', nIndex ).toInt32() );
     527           0 :                 size_t nPairs = aValues.size() / 2; // ignore last value if size is odd
     528           0 :                 for( size_t nPairIdx = 0; nPairIdx < nPairs; ++nPairIdx )
     529           0 :                     orCustomDash.push_back( LineProperties::DashStop( aValues[ 2 * nPairIdx ], aValues[ 2 * nPairIdx + 1 ] ) );
     530             :             }
     531             :         }
     532             :     }
     533             : }
     534             : 
     535        1168 : sal_Int32 lclGetDmlArrowType( const OptValue< sal_Int32 >& roArrowType )
     536             : {
     537        1168 :     if( roArrowType.has() ) switch( roArrowType.get() )
     538             :     {
     539           0 :         case XML_none:      return XML_none;
     540          96 :         case XML_block:     return XML_triangle;
     541           0 :         case XML_classic:   return XML_stealth;
     542          20 :         case XML_diamond:   return XML_diamond;
     543           0 :         case XML_oval:      return XML_oval;
     544           8 :         case XML_open:      return XML_arrow;
     545             :     }
     546        1044 :     return XML_none;
     547             : }
     548             : 
     549        1168 : sal_Int32 lclGetDmlArrowWidth( const OptValue< sal_Int32 >& roArrowWidth )
     550             : {
     551        1168 :     if( roArrowWidth.has() ) switch( roArrowWidth.get() )
     552             :     {
     553           0 :         case XML_narrow:    return XML_sm;
     554          22 :         case XML_medium:    return XML_med;
     555           0 :         case XML_wide:      return XML_lg;
     556             :     }
     557        1146 :     return XML_med;
     558             : }
     559             : 
     560        1168 : sal_Int32 lclGetDmlArrowLength( const OptValue< sal_Int32 >& roArrowLength )
     561             : {
     562        1168 :     if( roArrowLength.has() ) switch( roArrowLength.get() )
     563             :     {
     564           0 :         case XML_short:     return XML_sm;
     565          22 :         case XML_medium:    return XML_med;
     566           0 :         case XML_long:      return XML_lg;
     567             :     }
     568        1146 :     return XML_med;
     569             : }
     570             : 
     571        1168 : void lclConvertArrow( LineArrowProperties& orArrowProp, const StrokeArrowModel& rStrokeArrow )
     572             : {
     573        1168 :     orArrowProp.moArrowType = lclGetDmlArrowType( rStrokeArrow.moArrowType );
     574        1168 :     orArrowProp.moArrowWidth = lclGetDmlArrowWidth( rStrokeArrow.moArrowWidth );
     575        1168 :     orArrowProp.moArrowLength = lclGetDmlArrowLength( rStrokeArrow.moArrowLength );
     576        1168 : }
     577             : 
     578         584 : sal_Int32 lclGetDmlLineCompound( const OptValue< sal_Int32 >& roLineStyle )
     579             : {
     580         584 :     if( roLineStyle.has() ) switch( roLineStyle.get() )
     581             :     {
     582           0 :         case XML_single:            return XML_sng;
     583           2 :         case XML_thinThin:          return XML_dbl;
     584           0 :         case XML_thinThick:         return XML_thinThick;
     585           0 :         case XML_thickThin:         return XML_thickThin;
     586           0 :         case XML_thickBetweenThin:  return XML_tri;
     587             :     }
     588         582 :     return XML_sng;
     589             : }
     590             : 
     591         584 : sal_Int32 lclGetDmlLineCap( const OptValue< sal_Int32 >& roEndCap )
     592             : {
     593         584 :     if( roEndCap.has() ) switch( roEndCap.get() )
     594             :     {
     595          42 :         case XML_flat:      return XML_flat;
     596           0 :         case XML_square:    return XML_sq;
     597           2 :         case XML_round:     return XML_rnd;
     598             :     }
     599         540 :     return XML_flat;    // different defaults in VML (flat) and DrawingML (square)
     600             : }
     601             : 
     602         584 : sal_Int32 lclGetDmlLineJoint( const OptValue< sal_Int32 >& roJoinStyle )
     603             : {
     604         584 :     if( roJoinStyle.has() ) switch( roJoinStyle.get() )
     605             :     {
     606          28 :         case XML_round: return XML_round;
     607         168 :         case XML_bevel: return XML_bevel;
     608         144 :         case XML_miter: return XML_miter;
     609             :     }
     610         244 :     return XML_round;
     611             : }
     612             : 
     613             : } // namespace
     614             : 
     615        1228 : void StrokeArrowModel::assignUsed( const StrokeArrowModel& rSource )
     616             : {
     617        1228 :     moArrowType.assignIfUsed( rSource.moArrowType );
     618        1228 :     moArrowWidth.assignIfUsed( rSource.moArrowWidth );
     619        1228 :     moArrowLength.assignIfUsed( rSource.moArrowLength );
     620        1228 : }
     621             : 
     622         614 : void StrokeModel::assignUsed( const StrokeModel& rSource )
     623             : {
     624         614 :     moStroked.assignIfUsed( rSource.moStroked );
     625         614 :     maStartArrow.assignUsed( rSource.maStartArrow );
     626         614 :     maEndArrow.assignUsed( rSource.maEndArrow );
     627         614 :     moColor.assignIfUsed( rSource.moColor );
     628         614 :     moOpacity.assignIfUsed( rSource.moOpacity );
     629         614 :     moWeight.assignIfUsed( rSource.moWeight );
     630         614 :     moDashStyle.assignIfUsed( rSource.moDashStyle );
     631         614 :     moLineStyle.assignIfUsed( rSource.moLineStyle );
     632         614 :     moEndCap.assignIfUsed( rSource.moEndCap );
     633         614 :     moJoinStyle.assignIfUsed( rSource.moJoinStyle );
     634         614 : }
     635             : 
     636        1802 : void StrokeModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
     637             : {
     638             :     /*  Convert VML line formatting to DrawingML line formatting and let the
     639             :         DrawingML code do the hard work. */
     640        1802 :     LineProperties aLineProps;
     641             : 
     642        1802 :     if( moStroked.get( true ) )
     643             :     {
     644         584 :         aLineProps.maLineFill.moFillType = XML_solidFill;
     645         584 :         lclConvertArrow( aLineProps.maStartArrow, maStartArrow );
     646         584 :         lclConvertArrow( aLineProps.maEndArrow, maEndArrow );
     647         584 :         aLineProps.maLineFill.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_BLACK );
     648         584 :         aLineProps.moLineWidth = getLimitedValue< sal_Int32, sal_Int64 >( lclGetEmu( rGraphicHelper, moWeight, 1 ), 0, SAL_MAX_INT32 );
     649         584 :         lclGetDmlLineDash( aLineProps.moPresetDash, aLineProps.maCustomDash, moDashStyle );
     650         584 :         aLineProps.moLineCompound = lclGetDmlLineCompound( moLineStyle );
     651         584 :         aLineProps.moLineCap = lclGetDmlLineCap( moEndCap );
     652         584 :         aLineProps.moLineJoint = lclGetDmlLineJoint( moJoinStyle );
     653             :     }
     654             :     else
     655             :     {
     656        1218 :         aLineProps.maLineFill.moFillType = XML_noFill;
     657             :     }
     658             : 
     659        1802 :     aLineProps.pushToPropMap( rPropMap, rGraphicHelper );
     660        1802 : }
     661             : 
     662         614 : void FillModel::assignUsed( const FillModel& rSource )
     663             : {
     664         614 :     moFilled.assignIfUsed( rSource.moFilled );
     665         614 :     moColor.assignIfUsed( rSource.moColor );
     666         614 :     moOpacity.assignIfUsed( rSource.moOpacity );
     667         614 :     moColor2.assignIfUsed( rSource.moColor2 );
     668         614 :     moOpacity2.assignIfUsed( rSource.moOpacity2 );
     669         614 :     moType.assignIfUsed( rSource.moType );
     670         614 :     moAngle.assignIfUsed( rSource.moAngle );
     671         614 :     moFocus.assignIfUsed( rSource.moFocus );
     672         614 :     moFocusPos.assignIfUsed( rSource.moFocusPos );
     673         614 :     moFocusSize.assignIfUsed( rSource.moFocusSize );
     674         614 :     moBitmapPath.assignIfUsed( rSource.moBitmapPath );
     675         614 :     moRotate.assignIfUsed( rSource.moRotate );
     676         614 : }
     677             : 
     678        1814 : void FillModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
     679             : {
     680             :     /*  Convert VML fill formatting to DrawingML fill formatting and let the
     681             :         DrawingML code do the hard work. */
     682        1814 :     FillProperties aFillProps;
     683             : 
     684        1814 :     if( moFilled.get( true ) )
     685             :     {
     686        1240 :         sal_Int32 nFillType = moType.get( XML_solid );
     687        1240 :         switch( nFillType )
     688             :         {
     689             :             case XML_gradient:
     690             :             case XML_gradientRadial:
     691             :             {
     692          52 :                 aFillProps.moFillType = XML_gradFill;
     693          52 :                 aFillProps.maGradientProps.moRotateWithShape = moRotate.get( false );
     694          52 :                 double fFocus = moFocus.get( 0.0 );
     695             : 
     696             :                 // prepare colors
     697          52 :                 Color aColor1 = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
     698         104 :                 Color aColor2 = ConversionHelper::decodeColor( rGraphicHelper, moColor2, moOpacity2, API_RGB_WHITE, aColor1.getColor( rGraphicHelper ) );
     699             : 
     700             :                 // type XML_gradient is linear or axial gradient
     701          52 :                 if( nFillType == XML_gradient )
     702             :                 {
     703             :                     // normalize angle to range [0;360) degrees
     704          48 :                     sal_Int32 nVmlAngle = getIntervalValue< sal_Int32, sal_Int32 >( moAngle.get( 0 ), 0, 360 );
     705             : 
     706             :                     // focus of -50% or 50% is axial gradient
     707          48 :                     if( ((-0.75 <= fFocus) && (fFocus <= -0.25)) || ((0.25 <= fFocus) && (fFocus <= 0.75)) )
     708             :                     {
     709             :                         /*  According to spec, focus of 50% is outer-to-inner,
     710             :                             and -50% is inner-to-outer (color to color2).
     711             :                             BUT: For angles >= 180 deg., the behaviour is
     712             :                             reversed... that's not spec'ed of course. So,
     713             :                             [0;180) deg. and 50%, or [180;360) deg. and -50% is
     714             :                             outer-to-inner in fact. */
     715          36 :                         bool bOuterToInner = (fFocus > 0.0) == (nVmlAngle < 180);
     716             :                         // simulate axial gradient by 3-step DrawingML gradient
     717          36 :                         const Color& rOuterColor = bOuterToInner ? aColor1 : aColor2;
     718          36 :                         const Color& rInnerColor = bOuterToInner ? aColor2 : aColor1;
     719          36 :                         aFillProps.maGradientProps.maGradientStops[ 0.0 ] = aFillProps.maGradientProps.maGradientStops[ 1.0 ] = rOuterColor;
     720          36 :                         aFillProps.maGradientProps.maGradientStops[ 0.5 ] = rInnerColor;
     721             :                     }
     722             :                     else    // focus of -100%, 0%, and 100% is linear gradient
     723             :                     {
     724             :                         /*  According to spec, focus of -100% or 100% swaps the
     725             :                             start and stop colors, effectively reversing the
     726             :                             gradient. BUT: For angles >= 180 deg., the
     727             :                             behaviour is reversed. This means that in this case
     728             :                             a focus of 0% swaps the gradient. */
     729          12 :                         if( fFocus < -0.5 || fFocus > 0.5 )
     730           0 :                             (nVmlAngle += 180) %= 360;
     731             :                         // set the start and stop colors
     732          12 :                         aFillProps.maGradientProps.maGradientStops[ 0.0 ] = aColor1;
     733          12 :                         aFillProps.maGradientProps.maGradientStops[ 1.0 ] = aColor2;
     734             :                     }
     735             : 
     736             :                     // VML counts counterclockwise from bottom, DrawingML clockwise from left
     737          48 :                     sal_Int32 nDmlAngle = (630 - nVmlAngle) % 360;
     738          48 :                     aFillProps.maGradientProps.moShadeAngle = nDmlAngle * ::oox::drawingml::PER_DEGREE;
     739             :                 }
     740             :                 else    // XML_gradientRadial is rectangular gradient
     741             :                 {
     742           4 :                     aFillProps.maGradientProps.moGradientPath = XML_rect;
     743             :                     // convert VML focus position and size to DrawingML fill-to-rect
     744           4 :                     DoublePair aFocusPos = moFocusPos.get( DoublePair( 0.0, 0.0 ) );
     745           4 :                     DoublePair aFocusSize = moFocusSize.get( DoublePair( 0.0, 0.0 ) );
     746           4 :                     double fLeft   = getLimitedValue< double, double >( aFocusPos.first, 0.0, 1.0 );
     747           4 :                     double fTop    = getLimitedValue< double, double >( aFocusPos.second, 0.0, 1.0 );
     748           4 :                     double fRight  = getLimitedValue< double, double >( fLeft + aFocusSize.first, fLeft, 1.0 );
     749           4 :                     double fBottom = getLimitedValue< double, double >( fTop + aFocusSize.second, fTop, 1.0 );
     750          20 :                     aFillProps.maGradientProps.moFillToRect = IntegerRectangle2D(
     751           4 :                         static_cast< sal_Int32 >( fLeft * ::oox::drawingml::MAX_PERCENT ),
     752           4 :                         static_cast< sal_Int32 >( fTop * ::oox::drawingml::MAX_PERCENT ),
     753           4 :                         static_cast< sal_Int32 >( (1.0 - fRight) * ::oox::drawingml::MAX_PERCENT ),
     754           8 :                         static_cast< sal_Int32 >( (1.0 - fBottom) * ::oox::drawingml::MAX_PERCENT ) );
     755             : 
     756             :                     // set the start and stop colors (focus of 0% means outer-to-inner)
     757           4 :                     bool bOuterToInner = (-0.5 <= fFocus) && (fFocus <= 0.5);
     758           4 :                     aFillProps.maGradientProps.maGradientStops[ 0.0 ] = bOuterToInner ? aColor2 : aColor1;
     759           4 :                     aFillProps.maGradientProps.maGradientStops[ 1.0 ] = bOuterToInner ? aColor1 : aColor2;
     760          52 :                 }
     761             :             }
     762          52 :             break;
     763             : 
     764             :             case XML_pattern:
     765             :             case XML_tile:
     766             :             case XML_frame:
     767             :             {
     768           4 :                 if( moBitmapPath.has() && !moBitmapPath.get().isEmpty() )
     769             :                 {
     770           0 :                     aFillProps.maBlipProps.mxGraphic = rGraphicHelper.importEmbeddedGraphic( moBitmapPath.get() );
     771           0 :                     if( aFillProps.maBlipProps.mxGraphic.is() )
     772             :                     {
     773           0 :                         aFillProps.moFillType = XML_blipFill;
     774           0 :                         aFillProps.maBlipProps.moBitmapMode = (nFillType == XML_frame) ? XML_stretch : XML_tile;
     775           0 :                         break;  // do not break if bitmap is missing, but run to XML_solid instead
     776             :                     }
     777             :                 }
     778             :             }
     779             :             // run-through to XML_solid in case of missing bitmap path intended!
     780             : 
     781             :             case XML_solid:
     782             :             default:
     783             :             {
     784        1188 :                 aFillProps.moFillType = XML_solidFill;
     785             :                 // fill color (default is white)
     786        1188 :                 aFillProps.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
     787             :             }
     788             :         }
     789             :     }
     790             :     else
     791             :     {
     792         574 :         aFillProps.moFillType = XML_noFill;
     793             :     }
     794             : 
     795        1814 :     aFillProps.pushToPropMap( rPropMap, rGraphicHelper );
     796        1814 : }
     797             : 
     798        2522 : ShadowModel::ShadowModel()
     799        2522 :         : mbHasShadow(false)
     800             : {
     801        2522 : }
     802             : 
     803         170 : void ShadowModel::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper) const
     804             : {
     805         170 :     if (!mbHasShadow || (moShadowOn.has() && !moShadowOn.get()))
     806         296 :         return;
     807             : 
     808          44 :     drawingml::Color aColor = ConversionHelper::decodeColor(rGraphicHelper, moColor, moOpacity, API_RGB_GRAY);
     809             :     // nOffset* is in mm100, default value is 35 twips, see DffPropertyReader::ApplyAttributes() in msfilter.
     810          44 :     sal_Int32 nOffsetX = 62, nOffsetY = 62;
     811          44 :     if (moOffset.has())
     812             :     {
     813          80 :         OUString aOffsetX, aOffsetY;
     814          40 :         ConversionHelper::separatePair(aOffsetX, aOffsetY, moOffset.get(), ',');
     815          40 :         if (!aOffsetX.isEmpty())
     816          40 :             nOffsetX = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aOffsetX, 0, false, false );
     817          40 :         if (!aOffsetY.isEmpty())
     818          44 :             nOffsetY = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aOffsetY, 0, false, false );
     819             :     }
     820             : 
     821          44 :     table::ShadowFormat aFormat;
     822          44 :     aFormat.Color = aColor.getColor(rGraphicHelper);
     823          44 :     aFormat.Location = table::ShadowLocation_BOTTOM_RIGHT;
     824             :     // The width of the shadow is the average of the x and y values, see SwWW8ImplReader::MatchSdrItemsIntoFlySet().
     825          44 :     aFormat.ShadowWidth = ((nOffsetX + nOffsetY) / 2);
     826          44 :     rPropMap.setProperty(PROP_ShadowFormat, uno::makeAny(aFormat));
     827             : }
     828             : 
     829        2330 : TextpathModel::TextpathModel()
     830             : {
     831        2330 : }
     832             : 
     833         184 : beans::PropertyValue lcl_createTextpathProps()
     834             : {
     835         184 :     uno::Sequence<beans::PropertyValue> aTextpathPropSeq(4);
     836         184 :     aTextpathPropSeq[0].Name = "TextPath";
     837         184 :     aTextpathPropSeq[0].Value <<= sal_True;
     838         184 :     aTextpathPropSeq[1].Name = "TextPathMode";
     839         184 :     aTextpathPropSeq[1].Value <<= drawing::EnhancedCustomShapeTextPathMode_SHAPE;
     840         184 :     aTextpathPropSeq[2].Name = "ScaleX";
     841         184 :     aTextpathPropSeq[2].Value <<= sal_False;
     842         184 :     aTextpathPropSeq[3].Name = "SameLetterHeights";
     843         184 :     aTextpathPropSeq[3].Value <<= sal_False;
     844             : 
     845         184 :     beans::PropertyValue aRet;
     846         184 :     aRet.Name = "TextPath";
     847         184 :     aRet.Value <<= aTextpathPropSeq;
     848         184 :     return aRet;
     849             : }
     850             : 
     851         516 : void TextpathModel::pushToPropMap(ShapePropertyMap& rPropMap, uno::Reference<drawing::XShape> xShape) const
     852             : {
     853         516 :     if (moString.has())
     854             :     {
     855         184 :         uno::Reference<text::XTextRange> xTextRange(xShape, uno::UNO_QUERY);
     856         184 :         xTextRange->setString(moString.get());
     857             : 
     858         368 :         uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
     859         368 :         uno::Sequence<beans::PropertyValue> aGeomPropSeq = xPropertySet->getPropertyValue("CustomShapeGeometry").get< uno::Sequence<beans::PropertyValue> >();
     860         184 :         bool bFound = false;
     861         804 :         for (int i = 0; i < aGeomPropSeq.getLength(); ++i)
     862             :         {
     863         620 :             beans::PropertyValue& rProp = aGeomPropSeq[i];
     864         620 :             if (rProp.Name == "TextPath")
     865             :             {
     866          92 :                 bFound = true;
     867          92 :                 rProp = lcl_createTextpathProps();
     868             :             }
     869             :         }
     870         184 :         if (!bFound)
     871             :         {
     872          92 :             sal_Int32 nSize = aGeomPropSeq.getLength();
     873          92 :             aGeomPropSeq.realloc(nSize+1);
     874          92 :             aGeomPropSeq[nSize] = lcl_createTextpathProps();
     875             :         }
     876         368 :         rPropMap.setAnyProperty(PROP_CustomShapeGeometry, uno::makeAny(aGeomPropSeq));
     877             :     }
     878         516 : }
     879             : 
     880             : } // namespace vml
     881         408 : } // namespace oox
     882             : 
     883             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10