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

Generated by: LCOV version 1.11