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

Generated by: LCOV version 1.10