LCOV - code coverage report
Current view: top level - libreoffice/oox/source/vml - vmlformatting.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 206 354 58.2 %
Date: 2012-12-27 Functions: 23 24 95.8 %
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 <rtl/strbuf.hxx>
      22             : #include "oox/drawingml/color.hxx"
      23             : #include "oox/drawingml/drawingmltypes.hxx"
      24             : #include "oox/drawingml/fillproperties.hxx"
      25             : #include "oox/drawingml/lineproperties.hxx"
      26             : #include "oox/drawingml/shapepropertymap.hxx"
      27             : #include "oox/helper/attributelist.hxx"
      28             : #include "oox/helper/graphichelper.hxx"
      29             : 
      30             : namespace oox {
      31             : namespace vml {
      32             : 
      33             : // ============================================================================
      34             : 
      35             : using namespace ::com::sun::star::geometry;
      36             : 
      37             : using ::oox::drawingml::Color;
      38             : using ::oox::drawingml::FillProperties;
      39             : using ::oox::drawingml::LineArrowProperties;
      40             : using ::oox::drawingml::LineProperties;
      41             : using ::oox::drawingml::ShapePropertyMap;
      42             : using ::rtl::OStringBuffer;
      43             : using ::rtl::OUString;
      44             : using ::com::sun::star::awt::Point;
      45             : using ::com::sun::star::drawing::PolygonFlags;
      46             : using ::com::sun::star::drawing::PolygonFlags_NORMAL;
      47             : using ::com::sun::star::drawing::PolygonFlags_CONTROL;
      48             : 
      49             : // ============================================================================
      50             : 
      51             : namespace {
      52             : 
      53         141 : bool lclExtractDouble( double& orfValue, sal_Int32& ornEndPos, const OUString& rValue )
      54             : {
      55             :     // extract the double value and find start position of unit characters
      56         141 :     rtl_math_ConversionStatus eConvStatus = rtl_math_ConversionStatus_Ok;
      57         141 :     orfValue = ::rtl::math::stringToDouble( rValue, '.', '\0', &eConvStatus, &ornEndPos );
      58         141 :     return eConvStatus == rtl_math_ConversionStatus_Ok;
      59             : }
      60             : 
      61             : } // namespace
      62             : 
      63             : // ----------------------------------------------------------------------------
      64             : 
      65         359 : /*static*/ bool ConversionHelper::separatePair( OUString& orValue1, OUString& orValue2,
      66             :         const OUString& rValue, sal_Unicode cSep )
      67             : {
      68         359 :     sal_Int32 nSepPos = rValue.indexOf( cSep );
      69         359 :     if( nSepPos >= 0 )
      70             :     {
      71         301 :         orValue1 = rValue.copy( 0, nSepPos ).trim();
      72         301 :         orValue2 = rValue.copy( nSepPos + 1 ).trim();
      73             :     }
      74             :     else
      75             :     {
      76          58 :         orValue1 = rValue.trim();
      77             :     }
      78         359 :     return !orValue1.isEmpty() && !orValue2.isEmpty();
      79             : }
      80             : 
      81          30 : /*static*/ bool ConversionHelper::decodeBool( const OUString& rValue )
      82             : {
      83          30 :     sal_Int32 nToken = AttributeConversion::decodeToken( rValue );
      84             :     // anything else than 't' or 'true' is considered to be false, as specified
      85          30 :     return (nToken == XML_t) || (nToken == XML_true);
      86             : }
      87             : 
      88           0 : /*static*/ double ConversionHelper::decodePercent( const OUString& rValue, double fDefValue )
      89             : {
      90           0 :     if( rValue.isEmpty() )
      91           0 :         return fDefValue;
      92             : 
      93           0 :     double fValue = 0.0;
      94           0 :     sal_Int32 nEndPos = 0;
      95           0 :     if( !lclExtractDouble( fValue, nEndPos, rValue ) )
      96           0 :         return fDefValue;
      97             : 
      98           0 :     if( nEndPos == rValue.getLength() )
      99           0 :         return fValue;
     100             : 
     101           0 :     if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == '%') )
     102           0 :         return fValue / 100.0;
     103             : 
     104           0 :     if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == 'f') )
     105           0 :         return fValue / 65536.0;
     106             : 
     107             :     OSL_FAIL( "ConversionHelper::decodePercent - unknown measure unit" );
     108           0 :     return fDefValue;
     109             : }
     110             : 
     111         193 : /*static*/ sal_Int64 ConversionHelper::decodeMeasureToEmu( const GraphicHelper& rGraphicHelper,
     112             :         const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel )
     113             : {
     114             :     // default for missing values is 0
     115         193 :     if( rValue.isEmpty() )
     116          52 :         return 0;
     117             : 
     118             :     // TODO: according to spec, value may contain "auto"
     119         141 :     if ( rValue == "auto" )
     120             :     {
     121             :         OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - special value 'auto' must be handled by caller" );
     122           0 :         return nRefValue;
     123             :     }
     124             : 
     125             :     // extract the double value and find start position of unit characters
     126         141 :     double fValue = 0.0;
     127         141 :     sal_Int32 nEndPos = 0;
     128         141 :     if( !lclExtractDouble( fValue, nEndPos, rValue ) || (fValue == 0.0) )
     129          38 :         return 0;
     130             : 
     131             :     // process trailing unit, convert to EMU
     132         103 :     OUString aUnit;
     133         103 :     if( (0 < nEndPos) && (nEndPos < rValue.getLength()) )
     134         103 :         aUnit = rValue.copy( nEndPos );
     135           0 :     else if( bDefaultAsPixel )
     136           0 :         aUnit = "px";
     137             :     // else default is EMU
     138             : 
     139         103 :     if( aUnit.getLength() == 2 )
     140             :     {
     141         103 :         sal_Unicode cChar1 = aUnit[ 0 ];
     142         103 :         sal_Unicode cChar2 = aUnit[ 1 ];
     143         103 :         if( (cChar1 == 'i') && (cChar2 == 'n') )        // 1 inch = 914,400 EMU
     144          40 :             fValue *= 914400.0;
     145          63 :         else if( (cChar1 == 'c') && (cChar2 == 'm') )   // 1 cm = 360,000 EMU
     146           0 :             fValue *= 360000.0;
     147          63 :         else if( (cChar1 == 'm') && (cChar2 == 'm') )   // 1 mm = 36,000 EMU
     148           0 :             fValue *= 36000.0;
     149          63 :         else if( (cChar1 == 'p') && (cChar2 == 't') )   // 1 point = 1/72 inch = 12,700 EMU
     150          63 :             fValue *= 12700.0;
     151           0 :         else if( (cChar1 == 'p') && (cChar2 == 'c') )   // 1 pica = 1/6 inch = 152,400 EMU
     152           0 :             fValue *= 152400.0;
     153           0 :         else if( (cChar1 == 'p') && (cChar2 == 'x') )   // 1 pixel, dependent on output device
     154             :             fValue = static_cast< double >( ::oox::drawingml::convertHmmToEmu(
     155             :                 bPixelX ?
     156           0 :                     rGraphicHelper.convertScreenPixelXToHmm( fValue ) :
     157           0 :                     rGraphicHelper.convertScreenPixelYToHmm( fValue ) ) );
     158             :     }
     159           0 :     else if( (aUnit.getLength() == 1) && (aUnit[ 0 ] == '%') )
     160             :     {
     161           0 :         fValue *= nRefValue / 100.0;
     162             :     }
     163           0 :     else if( bDefaultAsPixel || !aUnit.isEmpty() )   // default as EMU and no unit -> do nothing
     164             :     {
     165             :         OSL_FAIL( "ConversionHelper::decodeMeasureToEmu - unknown measure unit" );
     166           0 :         fValue = nRefValue;
     167             :     }
     168         103 :     return static_cast< sal_Int64 >( fValue + 0.5 );
     169             : }
     170             : 
     171         190 : /*static*/ sal_Int32 ConversionHelper::decodeMeasureToHmm( const GraphicHelper& rGraphicHelper,
     172             :         const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel )
     173             : {
     174         190 :     return ::oox::drawingml::convertEmuToHmm( decodeMeasureToEmu( rGraphicHelper, rValue, nRefValue, bPixelX, bDefaultAsPixel ) );
     175             : }
     176             : 
     177          19 : /*static*/ Color ConversionHelper::decodeColor( const GraphicHelper& rGraphicHelper,
     178             :         const OptValue< OUString >& roVmlColor, const OptValue< double >& roVmlOpacity,
     179             :         sal_Int32 nDefaultRgb, sal_Int32 nPrimaryRgb )
     180             : {
     181          19 :     Color aDmlColor;
     182             : 
     183             :     // convert opacity
     184          19 :     const sal_Int32 DML_FULL_OPAQUE = ::oox::drawingml::MAX_PERCENT;
     185          19 :     double fOpacity = roVmlOpacity.get( 1.0 );
     186          19 :     sal_Int32 nOpacity = getLimitedValue< sal_Int32, double >( fOpacity * DML_FULL_OPAQUE, 0, DML_FULL_OPAQUE );
     187          19 :     if( nOpacity < DML_FULL_OPAQUE )
     188           0 :         aDmlColor.addTransformation( XML_alpha, nOpacity );
     189             : 
     190             :     // color attribute not present - set passed default color
     191          19 :     if( !roVmlColor.has() )
     192             :     {
     193          12 :         aDmlColor.setSrgbClr( nDefaultRgb );
     194             :         return aDmlColor;
     195             :     }
     196             : 
     197             :     // separate leading color name or RGB value from following palette index
     198           7 :     OUString aColorName, aColorIndex;
     199           7 :     separatePair( aColorName, aColorIndex, roVmlColor.get(), ' ' );
     200             : 
     201             :     // RGB colors in the format '#RRGGBB'
     202           7 :     if( (aColorName.getLength() == 7) && (aColorName[ 0 ] == '#') )
     203             :     {
     204           4 :         aDmlColor.setSrgbClr( aColorName.copy( 1 ).toInt32( 16 ) );
     205             :         return aDmlColor;
     206             :     }
     207             : 
     208             :     // RGB colors in the format '#RGB'
     209           3 :     if( (aColorName.getLength() == 4) && (aColorName[ 0 ] == '#') )
     210             :     {
     211           0 :         sal_Int32 nR = aColorName.copy( 1, 1 ).toInt32( 16 ) * 0x11;
     212           0 :         sal_Int32 nG = aColorName.copy( 2, 1 ).toInt32( 16 ) * 0x11;
     213           0 :         sal_Int32 nB = aColorName.copy( 3, 1 ).toInt32( 16 ) * 0x11;
     214           0 :         aDmlColor.setSrgbClr( (nR << 16) | (nG << 8) | nB );
     215             :         return aDmlColor;
     216             :     }
     217             : 
     218             :     /*  Predefined color names or system color names (resolve to RGB to detect
     219             :         valid color name). */
     220           3 :     sal_Int32 nColorToken = AttributeConversion::decodeToken( aColorName );
     221           3 :     sal_Int32 nRgbValue = Color::getVmlPresetColor( nColorToken, API_RGB_TRANSPARENT );
     222           3 :     if( nRgbValue == API_RGB_TRANSPARENT )
     223           0 :         nRgbValue = rGraphicHelper.getSystemColor( nColorToken, API_RGB_TRANSPARENT );
     224           3 :     if( nRgbValue != API_RGB_TRANSPARENT )
     225             :     {
     226           3 :         aDmlColor.setSrgbClr( nRgbValue );
     227             :         return aDmlColor;
     228             :     }
     229             : 
     230             :     // try palette colors enclosed in brackets
     231           0 :     if( (aColorIndex.getLength() >= 3) && (aColorIndex[ 0 ] == '[') && (aColorIndex[ aColorIndex.getLength() - 1 ] == ']') )
     232             :     {
     233           0 :         aDmlColor.setPaletteClr( aColorIndex.copy( 1, aColorIndex.getLength() - 2 ).toInt32() );
     234             :         return aDmlColor;
     235             :     }
     236             : 
     237             :     // try fill gradient modificator 'fill <modifier>(<amount>)'
     238           0 :     if( (nPrimaryRgb != API_RGB_TRANSPARENT) && (nColorToken == XML_fill) )
     239             :     {
     240           0 :         sal_Int32 nOpenParen = aColorIndex.indexOf( '(' );
     241           0 :         sal_Int32 nCloseParen = aColorIndex.indexOf( ')' );
     242           0 :         if( (2 <= nOpenParen) && (nOpenParen + 1 < nCloseParen) && (nCloseParen + 1 == aColorIndex.getLength()) )
     243             :         {
     244           0 :             sal_Int32 nModToken = XML_TOKEN_INVALID;
     245           0 :             switch( AttributeConversion::decodeToken( aColorIndex.copy( 0, nOpenParen ) ) )
     246             :             {
     247           0 :                 case XML_darken:    nModToken = XML_shade;break;
     248           0 :                 case XML_lighten:   nModToken = XML_tint;
     249             :             }
     250           0 :             sal_Int32 nValue = aColorIndex.copy( nOpenParen + 1, nCloseParen - nOpenParen - 1 ).toInt32();
     251           0 :             if( (nModToken != XML_TOKEN_INVALID) && (0 <= nValue) && (nValue < 255) )
     252             :             {
     253             :                 /*  Simulate this modifier color by a color with related transformation.
     254             :                     The modifier amount has to be converted from the range [0;255] to
     255             :                     percentage [0;100000] used by DrawingML. */
     256           0 :                 aDmlColor.setSrgbClr( nPrimaryRgb );
     257           0 :                 aDmlColor.addTransformation( nModToken, static_cast< sal_Int32 >( nValue * ::oox::drawingml::MAX_PERCENT / 255 ) );
     258             :                 return aDmlColor;
     259             :             }
     260             :         }
     261             :     }
     262             : 
     263             :     OSL_FAIL( OStringBuffer( "lclGetColor - invalid VML color name '" ).
     264             :         append( OUStringToOString( roVmlColor.get(), RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() );
     265           0 :     aDmlColor.setSrgbClr( nDefaultRgb );
     266           7 :     return aDmlColor;
     267             : }
     268             : 
     269           1 : /*static*/ void ConversionHelper::decodeVmlPath( ::std::vector< ::std::vector< Point > >& rPointLists, ::std::vector< ::std::vector< PolygonFlags > >& rFlagLists, const OUString& rPath )
     270             : {
     271           1 :     ::std::vector< sal_Int32 > aCoordList;
     272           1 :     Point aCurrentPoint;
     273           1 :     sal_Int32 nTokenStart = 0;
     274           1 :     sal_Int32 nTokenLen = 0;
     275           1 :     sal_Int32 nParamCount = 0;
     276             :     enum VML_State { START, MOVE_REL, MOVE_ABS, BEZIER_REL, BEZIER_ABS,
     277             :                      LINE_REL, LINE_ABS, CLOSE, END };
     278           1 :     VML_State state = START;
     279             : 
     280           1 :     rPointLists.push_back( ::std::vector< Point>() );
     281           1 :     rFlagLists.push_back( ::std::vector< PolygonFlags >() );
     282             : 
     283         896 :     for ( sal_Int32 i = 0; i < rPath.getLength(); i++ )
     284             :     {
     285             :         // Keep track of current integer token
     286         895 :         if ( ( rPath[ i ] >= '0' && rPath[ i ] <= '9' ) || rPath[ i ] == '-' )
     287         700 :             nTokenLen++;
     288         195 :         else if ( rPath[ i ] != ' ' )
     289             :         {
     290             :             // Store coordinate from current token
     291         195 :             if ( state != START )
     292             :             {
     293         194 :                 if ( nTokenLen > 0 )
     294         190 :                     aCoordList.push_back( rPath.copy( nTokenStart, nTokenLen ).toInt32() );
     295             :                 else
     296           4 :                     aCoordList.push_back( 0 );
     297         194 :                 nTokenLen = 0;
     298             :             }
     299             : 
     300         195 :             if (rPath[ i ] == ',' )
     301             :             {
     302         158 :                 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         195 :             if ( rPath[ i ] != ',' || nParamCount == 0)
     309             :             {
     310          37 :                 switch ( state )
     311             :                 {
     312             :                 case MOVE_REL: // 2* params -> param count reset
     313           0 :                     rPointLists.back().push_back( Point( aCoordList[ 0 ], aCoordList[ 1 ] ) );
     314           0 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     315           0 :                     aCurrentPoint = rPointLists.back().back();
     316           0 :                     nParamCount = 2 * 2;
     317           0 :                     break;
     318             : 
     319             :                 case MOVE_ABS: // 2 params -> no param count reset
     320           3 :                     rPointLists.back().push_back( Point( aCoordList[ 0 ], aCoordList[ 1 ] ) );
     321           3 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     322           3 :                     aCurrentPoint = rPointLists.back().back();
     323           3 :                     break;
     324             : 
     325             :                 case BEZIER_REL: // 6* params -> param count reset
     326          32 :                     rPointLists.back().push_back( Point( aCurrentPoint.X + aCoordList[ 0 ],
     327          48 :                                             aCurrentPoint.Y + aCoordList[ 1 ] ) );
     328          32 :                     rPointLists.back().push_back( Point( aCurrentPoint.X + aCoordList[ 2 ],
     329          48 :                                             aCurrentPoint.Y + aCoordList[ 3 ] ) );
     330          32 :                     rPointLists.back().push_back( Point( aCurrentPoint.X + aCoordList[ 4 ],
     331          48 :                                             aCurrentPoint.Y + aCoordList[ 5 ] ) );
     332          16 :                     rFlagLists.back().push_back( PolygonFlags_CONTROL );
     333          16 :                     rFlagLists.back().push_back( PolygonFlags_CONTROL );
     334          16 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     335          16 :                     aCurrentPoint = rPointLists.back().back();
     336          16 :                     nParamCount = 2 * 6;
     337          16 :                     break;
     338             : 
     339             :                 case BEZIER_ABS: // 6* params -> param count reset
     340          15 :                     rPointLists.back().push_back( Point( aCoordList[ 0 ], aCoordList[ 1 ] ) );
     341          15 :                     rPointLists.back().push_back( Point( aCoordList[ 2 ], aCoordList[ 3 ] ) );
     342          15 :                     rPointLists.back().push_back( Point( aCoordList[ 4 ], aCoordList[ 5 ] ) );
     343          15 :                     rFlagLists.back().push_back( PolygonFlags_CONTROL );
     344          15 :                     rFlagLists.back().push_back( PolygonFlags_CONTROL );
     345          15 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     346          15 :                     aCurrentPoint = rPointLists.back().back();
     347          15 :                     nParamCount = 2 * 6;
     348          15 :                     break;
     349             : 
     350             :                 case LINE_REL: // 2* params -> param count reset
     351           0 :                     rPointLists.back().push_back( Point( aCurrentPoint.X + aCoordList[ 0 ],
     352           0 :                                             aCurrentPoint.Y + aCoordList[ 1 ] ) );
     353           0 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     354           0 :                     aCurrentPoint = rPointLists.back().back();
     355           0 :                     nParamCount = 2 * 2;
     356           0 :                     break;
     357             : 
     358             :                 case LINE_ABS: // 2* params -> param count reset
     359           0 :                     rPointLists.back().push_back( Point( aCoordList[ 0 ], aCoordList[ 1 ] ) );
     360           0 :                     rFlagLists.back().push_back( PolygonFlags_NORMAL );
     361           0 :                     aCurrentPoint = rPointLists.back().back();
     362           0 :                     nParamCount = 2 * 2;
     363           0 :                     break;
     364             : 
     365             :                 case CLOSE: // 0 param
     366           0 :                     rPointLists.back().push_back( rPointLists.back()[ 0 ] );
     367           0 :                     rFlagLists.back().push_back( rFlagLists.back()[ 0 ] );
     368           0 :                     aCurrentPoint = rPointLists.back().back();
     369           0 :                     break;
     370             : 
     371             :                 case END: // 0 param
     372           2 :                     rPointLists.push_back( ::std::vector< Point >() );
     373           2 :                     rFlagLists.push_back( ::std::vector< PolygonFlags >() );
     374           2 :                     break;
     375             : 
     376             :                 case START:
     377           1 :                     break;
     378             :                 }
     379             : 
     380          37 :                 aCoordList.clear();
     381             :             }
     382             : 
     383             :             // Move on to current command state
     384         195 :             switch ( rPath[ i ] )
     385             :             {
     386           0 :             case 't': state = MOVE_REL; nTokenLen = 0; nParamCount = 2 * 2; break;
     387           3 :             case 'm': state = MOVE_ABS; nTokenLen = 0; nParamCount = 2 * 2; break;
     388          16 :             case 'v': state = BEZIER_REL; nTokenLen = 0; nParamCount = 2 * 6; break;
     389          15 :             case 'c': state = BEZIER_ABS; nTokenLen = 0; nParamCount = 2 * 6; break;
     390           0 :             case 'r': state = LINE_REL; nTokenLen = 0; nParamCount = 2 * 2; break;
     391           0 :             case 'l': state = LINE_ABS; nTokenLen = 0; nParamCount = 2 * 2; break;
     392           0 :             case 'x': state = CLOSE; nTokenLen = 0; break;
     393           3 :             case 'e': state = END; break;
     394             :             }
     395             : 
     396         195 :             nTokenStart = i+1;
     397             :         }
     398           1 :     }
     399           1 : }
     400             : 
     401             : // ============================================================================
     402             : 
     403             : namespace {
     404             : 
     405          12 : sal_Int64 lclGetEmu( const GraphicHelper& rGraphicHelper, const OptValue< OUString >& roValue, sal_Int64 nDefValue )
     406             : {
     407          12 :     return roValue.has() ? ConversionHelper::decodeMeasureToEmu( rGraphicHelper, roValue.get(), 0, false, false ) : nDefValue;
     408             : }
     409             : 
     410          12 : void lclGetDmlLineDash( OptValue< sal_Int32 >& oroPresetDash, LineProperties::DashStopVector& orCustomDash, const OptValue< OUString >& roDashStyle )
     411             : {
     412          12 :     if( roDashStyle.has() )
     413             :     {
     414           0 :         const OUString& rDashStyle = roDashStyle.get();
     415           0 :         switch( AttributeConversion::decodeToken( rDashStyle ) )
     416             :         {
     417           0 :             case XML_solid:             oroPresetDash = XML_solid;          return;
     418           0 :             case XML_shortdot:          oroPresetDash = XML_sysDot;         return;
     419           0 :             case XML_shortdash:         oroPresetDash = XML_sysDash;        return;
     420           0 :             case XML_shortdashdot:      oroPresetDash = XML_sysDashDot;     return;
     421           0 :             case XML_shortdashdotdot:   oroPresetDash = XML_sysDashDotDot;  return;
     422           0 :             case XML_dot:               oroPresetDash = XML_dot;            return;
     423           0 :             case XML_dash:              oroPresetDash = XML_dash;           return;
     424           0 :             case XML_dashdot:           oroPresetDash = XML_dashDot;        return;
     425           0 :             case XML_longdash:          oroPresetDash = XML_lgDash;         return;
     426           0 :             case XML_longdashdot:       oroPresetDash = XML_lgDashDot;      return;
     427           0 :             case XML_longdashdotdot:    oroPresetDash = XML_lgDashDotDot;   return;
     428             : 
     429             :             // try to convert user-defined dash style
     430             :             default:
     431             :             {
     432           0 :                 ::std::vector< sal_Int32 > aValues;
     433           0 :                 sal_Int32 nIndex = 0;
     434           0 :                 while( nIndex >= 0 )
     435           0 :                     aValues.push_back( rDashStyle.getToken( 0, ' ', nIndex ).toInt32() );
     436           0 :                 size_t nPairs = aValues.size() / 2; // ignore last value if size is odd
     437           0 :                 for( size_t nPairIdx = 0; nPairIdx < nPairs; ++nPairIdx )
     438           0 :                     orCustomDash.push_back( LineProperties::DashStop( aValues[ 2 * nPairIdx ], aValues[ 2 * nPairIdx + 1 ] ) );
     439             :             }
     440             :         }
     441             :     }
     442             : }
     443             : 
     444          24 : sal_Int32 lclGetDmlArrowType( const OptValue< sal_Int32 >& roArrowType )
     445             : {
     446          24 :     if( roArrowType.has() ) switch( roArrowType.get() )
     447             :     {
     448           0 :         case XML_none:      return XML_none;
     449           4 :         case XML_block:     return XML_triangle;
     450           0 :         case XML_classic:   return XML_stealth;
     451           0 :         case XML_diamond:   return XML_diamond;
     452           0 :         case XML_oval:      return XML_oval;
     453           0 :         case XML_open:      return XML_arrow;
     454             :     }
     455          20 :     return XML_none;
     456             : }
     457             : 
     458          24 : sal_Int32 lclGetDmlArrowWidth( const OptValue< sal_Int32 >& roArrowWidth )
     459             : {
     460          24 :     if( roArrowWidth.has() ) switch( roArrowWidth.get() )
     461             :     {
     462           0 :         case XML_narrow:    return XML_sm;
     463           1 :         case XML_medium:    return XML_med;
     464           0 :         case XML_wide:      return XML_lg;
     465             :     }
     466          23 :     return XML_med;
     467             : }
     468             : 
     469          24 : sal_Int32 lclGetDmlArrowLength( const OptValue< sal_Int32 >& roArrowLength )
     470             : {
     471          24 :     if( roArrowLength.has() ) switch( roArrowLength.get() )
     472             :     {
     473           0 :         case XML_short:     return XML_sm;
     474           1 :         case XML_medium:    return XML_med;
     475           0 :         case XML_long:      return XML_lg;
     476             :     }
     477          23 :     return XML_med;
     478             : }
     479             : 
     480          24 : void lclConvertArrow( LineArrowProperties& orArrowProp, const StrokeArrowModel& rStrokeArrow )
     481             : {
     482          24 :     orArrowProp.moArrowType = lclGetDmlArrowType( rStrokeArrow.moArrowType );
     483          24 :     orArrowProp.moArrowWidth = lclGetDmlArrowWidth( rStrokeArrow.moArrowWidth );
     484          24 :     orArrowProp.moArrowLength = lclGetDmlArrowLength( rStrokeArrow.moArrowLength );
     485          24 : }
     486             : 
     487          12 : sal_Int32 lclGetDmlLineCompound( const OptValue< sal_Int32 >& roLineStyle )
     488             : {
     489          12 :     if( roLineStyle.has() ) switch( roLineStyle.get() )
     490             :     {
     491           0 :         case XML_single:            return XML_sng;
     492           0 :         case XML_thinThin:          return XML_dbl;
     493           0 :         case XML_thinThick:         return XML_thinThick;
     494           0 :         case XML_thickThin:         return XML_thickThin;
     495           0 :         case XML_thickBetweenThin:  return XML_tri;
     496             :     }
     497          12 :     return XML_sng;
     498             : }
     499             : 
     500          12 : sal_Int32 lclGetDmlLineCap( const OptValue< sal_Int32 >& roEndCap )
     501             : {
     502          12 :     if( roEndCap.has() ) switch( roEndCap.get() )
     503             :     {
     504           0 :         case XML_flat:      return XML_flat;
     505           0 :         case XML_square:    return XML_sq;
     506           1 :         case XML_round:     return XML_rnd;
     507             :     }
     508          11 :     return XML_flat;    // different defaults in VML (flat) and DrawingML (square)
     509             : }
     510             : 
     511          12 : sal_Int32 lclGetDmlLineJoint( const OptValue< sal_Int32 >& roJoinStyle )
     512             : {
     513          12 :     if( roJoinStyle.has() ) switch( roJoinStyle.get() )
     514             :     {
     515           1 :         case XML_round: return XML_round;
     516           0 :         case XML_bevel: return XML_bevel;
     517           4 :         case XML_miter: return XML_miter;
     518             :     }
     519           7 :     return XML_round;
     520             : }
     521             : 
     522             : } // namespace
     523             : 
     524             : // ============================================================================
     525             : 
     526          22 : void StrokeArrowModel::assignUsed( const StrokeArrowModel& rSource )
     527             : {
     528          22 :     moArrowType.assignIfUsed( rSource.moArrowType );
     529          22 :     moArrowWidth.assignIfUsed( rSource.moArrowWidth );
     530          22 :     moArrowLength.assignIfUsed( rSource.moArrowLength );
     531          22 : }
     532             : 
     533             : // ============================================================================
     534             : 
     535          11 : void StrokeModel::assignUsed( const StrokeModel& rSource )
     536             : {
     537          11 :     moStroked.assignIfUsed( rSource.moStroked );
     538          11 :     maStartArrow.assignUsed( rSource.maStartArrow );
     539          11 :     maEndArrow.assignUsed( rSource.maEndArrow );
     540          11 :     moColor.assignIfUsed( rSource.moColor );
     541          11 :     moOpacity.assignIfUsed( rSource.moOpacity );
     542          11 :     moWeight.assignIfUsed( rSource.moWeight );
     543          11 :     moDashStyle.assignIfUsed( rSource.moDashStyle );
     544          11 :     moLineStyle.assignIfUsed( rSource.moLineStyle );
     545          11 :     moEndCap.assignIfUsed( rSource.moEndCap );
     546          11 :     moJoinStyle.assignIfUsed( rSource.moJoinStyle );
     547          11 : }
     548             : 
     549          18 : void StrokeModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
     550             : {
     551             :     /*  Convert VML line formatting to DrawingML line formatting and let the
     552             :         DrawingML code do the hard work. */
     553          18 :     LineProperties aLineProps;
     554             : 
     555          18 :     if( moStroked.get( true ) )
     556             :     {
     557          12 :         aLineProps.maLineFill.moFillType = XML_solidFill;
     558          12 :         lclConvertArrow( aLineProps.maStartArrow, maStartArrow );
     559          12 :         lclConvertArrow( aLineProps.maEndArrow, maEndArrow );
     560          12 :         aLineProps.maLineFill.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_BLACK );
     561          12 :         aLineProps.moLineWidth = getLimitedValue< sal_Int32, sal_Int64 >( lclGetEmu( rGraphicHelper, moWeight, 1 ), 0, SAL_MAX_INT32 );
     562          12 :         lclGetDmlLineDash( aLineProps.moPresetDash, aLineProps.maCustomDash, moDashStyle );
     563          12 :         aLineProps.moLineCompound = lclGetDmlLineCompound( moLineStyle );
     564          12 :         aLineProps.moLineCap = lclGetDmlLineCap( moEndCap );
     565          12 :         aLineProps.moLineJoint = lclGetDmlLineJoint( moJoinStyle );
     566             :     }
     567             :     else
     568             :     {
     569           6 :         aLineProps.maLineFill.moFillType = XML_noFill;
     570             :     }
     571             : 
     572          18 :     aLineProps.pushToPropMap( rPropMap, rGraphicHelper );
     573          18 : }
     574             : 
     575             : // ============================================================================
     576             : 
     577          11 : void FillModel::assignUsed( const FillModel& rSource )
     578             : {
     579          11 :     moFilled.assignIfUsed( rSource.moFilled );
     580          11 :     moColor.assignIfUsed( rSource.moColor );
     581          11 :     moOpacity.assignIfUsed( rSource.moOpacity );
     582          11 :     moColor2.assignIfUsed( rSource.moColor2 );
     583          11 :     moOpacity2.assignIfUsed( rSource.moOpacity2 );
     584          11 :     moType.assignIfUsed( rSource.moType );
     585          11 :     moAngle.assignIfUsed( rSource.moAngle );
     586          11 :     moFocus.assignIfUsed( rSource.moFocus );
     587          11 :     moFocusPos.assignIfUsed( rSource.moFocusPos );
     588          11 :     moFocusSize.assignIfUsed( rSource.moFocusSize );
     589          11 :     moBitmapPath.assignIfUsed( rSource.moBitmapPath );
     590          11 :     moRotate.assignIfUsed( rSource.moRotate );
     591          11 : }
     592             : 
     593          18 : void FillModel::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper ) const
     594             : {
     595             :     /*  Convert VML fill formatting to DrawingML fill formatting and let the
     596             :         DrawingML code do the hard work. */
     597          18 :     FillProperties aFillProps;
     598             : 
     599          18 :     if( moFilled.get( true ) )
     600             :     {
     601           7 :         sal_Int32 nFillType = moType.get( XML_solid );
     602           7 :         switch( nFillType )
     603             :         {
     604             :             case XML_gradient:
     605             :             case XML_gradientRadial:
     606             :             {
     607           0 :                 aFillProps.moFillType = XML_gradFill;
     608           0 :                 aFillProps.maGradientProps.moRotateWithShape = moRotate.get( false );
     609           0 :                 double fFocus = moFocus.get( 0.0 );
     610             : 
     611             :                 // prepare colors
     612           0 :                 Color aColor1 = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
     613           0 :                 Color aColor2 = ConversionHelper::decodeColor( rGraphicHelper, moColor2, moOpacity2, API_RGB_WHITE, aColor1.getColor( rGraphicHelper ) );
     614             : 
     615             :                 // type XML_gradient is linear or axial gradient
     616           0 :                 if( nFillType == XML_gradient )
     617             :                 {
     618             :                     // normalize angle to range [0;360) degrees
     619           0 :                     sal_Int32 nVmlAngle = getIntervalValue< sal_Int32, sal_Int32 >( moAngle.get( 0 ), 0, 360 );
     620             : 
     621             :                     // focus of -50% or 50% is axial gradient
     622           0 :                     if( ((-0.75 <= fFocus) && (fFocus <= -0.25)) || ((0.25 <= fFocus) && (fFocus <= 0.75)) )
     623             :                     {
     624             :                         /*  According to spec, focus of 50% is outer-to-inner,
     625             :                             and -50% is inner-to-outer (color to color2).
     626             :                             BUT: For angles >= 180 deg., the behaviour is
     627             :                             reversed... that's not spec'ed of course. So,
     628             :                             [0;180) deg. and 50%, or [180;360) deg. and -50% is
     629             :                             outer-to-inner in fact. */
     630           0 :                         bool bOuterToInner = (fFocus > 0.0) == (nVmlAngle < 180);
     631             :                         // simulate axial gradient by 3-step DrawingML gradient
     632           0 :                         const Color& rOuterColor = bOuterToInner ? aColor1 : aColor2;
     633           0 :                         const Color& rInnerColor = bOuterToInner ? aColor2 : aColor1;
     634           0 :                         aFillProps.maGradientProps.maGradientStops[ 0.0 ] = aFillProps.maGradientProps.maGradientStops[ 1.0 ] = rOuterColor;
     635           0 :                         aFillProps.maGradientProps.maGradientStops[ 0.5 ] = rInnerColor;
     636             :                     }
     637             :                     else    // focus of -100%, 0%, and 100% is linear gradient
     638             :                     {
     639             :                         /*  According to spec, focus of -100% or 100% swaps the
     640             :                             start and stop colors, effectively reversing the
     641             :                             gradient. BUT: For angles >= 180 deg., the
     642             :                             behaviour is reversed. This means that in this case
     643             :                             a focus of 0% swaps the gradient. */
     644           0 :                         if( ((fFocus < -0.75) || (fFocus > 0.75)) == (nVmlAngle < 180) )
     645           0 :                             (nVmlAngle += 180) %= 360;
     646             :                         // set the start and stop colors
     647           0 :                         aFillProps.maGradientProps.maGradientStops[ 0.0 ] = aColor1;
     648           0 :                         aFillProps.maGradientProps.maGradientStops[ 1.0 ] = aColor2;
     649             :                     }
     650             : 
     651             :                     // VML counts counterclockwise from bottom, DrawingML clockwise from left
     652           0 :                     sal_Int32 nDmlAngle = (630 - nVmlAngle) % 360;
     653           0 :                     aFillProps.maGradientProps.moShadeAngle = nDmlAngle * ::oox::drawingml::PER_DEGREE;
     654             :                 }
     655             :                 else    // XML_gradientRadial is rectangular gradient
     656             :                 {
     657           0 :                     aFillProps.maGradientProps.moGradientPath = XML_rect;
     658             :                     // convert VML focus position and size to DrawingML fill-to-rect
     659           0 :                     DoublePair aFocusPos = moFocusPos.get( DoublePair( 0.0, 0.0 ) );
     660           0 :                     DoublePair aFocusSize = moFocusSize.get( DoublePair( 0.0, 0.0 ) );
     661           0 :                     double fLeft   = getLimitedValue< double, double >( aFocusPos.first, 0.0, 1.0 );
     662           0 :                     double fTop    = getLimitedValue< double, double >( aFocusPos.second, 0.0, 1.0 );
     663           0 :                     double fRight  = getLimitedValue< double, double >( fLeft + aFocusSize.first, fLeft, 1.0 );
     664           0 :                     double fBottom = getLimitedValue< double, double >( fTop + aFocusSize.second, fTop, 1.0 );
     665             :                     aFillProps.maGradientProps.moFillToRect = IntegerRectangle2D(
     666             :                         static_cast< sal_Int32 >( fLeft * ::oox::drawingml::MAX_PERCENT ),
     667             :                         static_cast< sal_Int32 >( fTop * ::oox::drawingml::MAX_PERCENT ),
     668             :                         static_cast< sal_Int32 >( (1.0 - fRight) * ::oox::drawingml::MAX_PERCENT ),
     669           0 :                         static_cast< sal_Int32 >( (1.0 - fBottom) * ::oox::drawingml::MAX_PERCENT ) );
     670             : 
     671             :                     // set the start and stop colors (focus of 0% means outer-to-inner)
     672           0 :                     bool bOuterToInner = (-0.5 <= fFocus) && (fFocus <= 0.5);
     673           0 :                     aFillProps.maGradientProps.maGradientStops[ 0.0 ] = bOuterToInner ? aColor2 : aColor1;
     674           0 :                     aFillProps.maGradientProps.maGradientStops[ 1.0 ] = bOuterToInner ? aColor1 : aColor2;
     675           0 :                 }
     676             :             }
     677           0 :             break;
     678             : 
     679             :             case XML_pattern:
     680             :             case XML_tile:
     681             :             case XML_frame:
     682             :             {
     683           0 :                 if( moBitmapPath.has() && !moBitmapPath.get().isEmpty() )
     684             :                 {
     685           0 :                     aFillProps.maBlipProps.mxGraphic = rGraphicHelper.importEmbeddedGraphic( moBitmapPath.get() );
     686           0 :                     if( aFillProps.maBlipProps.mxGraphic.is() )
     687             :                     {
     688           0 :                         aFillProps.moFillType = XML_blipFill;
     689           0 :                         aFillProps.maBlipProps.moBitmapMode = (nFillType == XML_frame) ? XML_stretch : XML_tile;
     690           0 :                         break;  // do not break if bitmap is missing, but run to XML_solid instead
     691             :                     }
     692             :                 }
     693             :             }
     694             :             // run-through to XML_solid in case of missing bitmap path intended!
     695             : 
     696             :             case XML_solid:
     697             :             default:
     698             :             {
     699           7 :                 aFillProps.moFillType = XML_solidFill;
     700             :                 // fill color (default is white)
     701           7 :                 aFillProps.maFillColor = ConversionHelper::decodeColor( rGraphicHelper, moColor, moOpacity, API_RGB_WHITE );
     702             :             }
     703             :         }
     704             :     }
     705             :     else
     706             :     {
     707          11 :         aFillProps.moFillType = XML_noFill;
     708             :     }
     709             : 
     710          18 :     aFillProps.pushToPropMap( rPropMap, rGraphicHelper );
     711          18 : }
     712             : 
     713             : // ============================================================================
     714             : 
     715             : } // namespace vml
     716          51 : } // namespace oox
     717             : 
     718             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10