LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/basegfx/source/polygon - b2dsvgpolypolygon.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 313 428 73.1 %
Date: 2013-07-09 Functions: 12 13 92.3 %
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             : 
      20             : #include <basegfx/polygon/b2dpolygontools.hxx>
      21             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      22             : #include <basegfx/polygon/b2dpolypolygon.hxx>
      23             : #include <basegfx/matrix/b2dhommatrix.hxx>
      24             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      25             : #include <rtl/ustring.hxx>
      26             : #include <rtl/math.hxx>
      27             : 
      28             : namespace basegfx
      29             : {
      30             :     namespace tools
      31             :     {
      32             :         namespace
      33             :         {
      34       49564 :             void lcl_skipSpaces(sal_Int32&          io_rPos,
      35             :                                 const OUString&     rStr,
      36             :                                 const sal_Int32     nLen)
      37             :             {
      38      151799 :                 while( io_rPos < nLen &&
      39       49783 :                        sal_Unicode(' ') == rStr[io_rPos] )
      40             :                 {
      41        2888 :                     ++io_rPos;
      42             :                 }
      43       49564 :             }
      44             : 
      45      140107 :             void lcl_skipSpacesAndCommas(sal_Int32&         io_rPos,
      46             :                                          const OUString&    rStr,
      47             :                                          const sal_Int32    nLen)
      48             :             {
      49      613055 :                 while(io_rPos < nLen
      50      236474 :                       && (sal_Unicode(' ') == rStr[io_rPos] || sal_Unicode(',') == rStr[io_rPos]))
      51             :                 {
      52       96367 :                     ++io_rPos;
      53             :                 }
      54      140107 :             }
      55             : 
      56       82926 :             inline bool lcl_isOnNumberChar(const sal_Unicode aChar, bool bSignAllowed = true)
      57             :             {
      58       71688 :                 const bool bPredicate( (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
      59       51391 :                                        || (bSignAllowed && sal_Unicode('+') == aChar)
      60       51391 :                                        || (bSignAllowed && sal_Unicode('-') == aChar)
      61      123079 :                                        || (sal_Unicode('.') == aChar) );
      62             : 
      63       82926 :                 return bPredicate;
      64             :             }
      65             : 
      66       80099 :             inline bool lcl_isOnNumberChar(const OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true)
      67             :             {
      68       80099 :                 return lcl_isOnNumberChar(rStr[nPos],
      69      160198 :                                           bSignAllowed);
      70             :             }
      71             : 
      72      140107 :             bool lcl_getDoubleChar(double&              o_fRetval,
      73             :                                    sal_Int32&           io_rPos,
      74             :                                    const OUString&      rStr)
      75             :             {
      76      140107 :                 sal_Unicode aChar( rStr[io_rPos] );
      77      140107 :                 OUStringBuffer sNumberString;
      78      140107 :                 bool separator_seen=false;
      79             : 
      80      140107 :                 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
      81             :                 {
      82       44571 :                     sNumberString.append(rStr[io_rPos]);
      83       44571 :                     aChar = rStr[++io_rPos];
      84             :                 }
      85             : 
      86      959577 :                 while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
      87      260281 :                       || (!separator_seen && sal_Unicode('.') == aChar))
      88             :                 {
      89      679363 :                     if (sal_Unicode('.') == aChar) separator_seen = true;
      90      679363 :                     sNumberString.append(rStr[io_rPos]);
      91      679363 :                     aChar = rStr[++io_rPos];
      92             :                 }
      93             : 
      94      140107 :                 if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
      95             :                 {
      96           9 :                     sNumberString.append(rStr[io_rPos]);
      97           9 :                     aChar = rStr[++io_rPos];
      98             : 
      99           9 :                     if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
     100             :                     {
     101           9 :                         sNumberString.append(rStr[io_rPos]);
     102           9 :                         aChar = rStr[++io_rPos];
     103             :                     }
     104             : 
     105          27 :                     while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
     106             :                     {
     107           9 :                         sNumberString.append(rStr[io_rPos]);
     108           9 :                         aChar = rStr[++io_rPos];
     109             :                     }
     110             :                 }
     111             : 
     112      140107 :                 if(!sNumberString.isEmpty())
     113             :                 {
     114             :                     rtl_math_ConversionStatus eStatus;
     115             :                     o_fRetval = ::rtl::math::stringToDouble( sNumberString.makeStringAndClear(),
     116             :                                                              (sal_Unicode)('.'),
     117             :                                                              (sal_Unicode)(','),
     118             :                                                              &eStatus,
     119      140107 :                                                              NULL );
     120      140107 :                     return ( eStatus == rtl_math_ConversionStatus_Ok );
     121             :                 }
     122             : 
     123           0 :                 return false;
     124             :             }
     125             : 
     126      140107 :             bool lcl_importDoubleAndSpaces( double&             o_fRetval,
     127             :                                             sal_Int32&          io_rPos,
     128             :                                             const OUString&     rStr,
     129             :                                             const sal_Int32     nLen )
     130             :             {
     131      140107 :                 if( !lcl_getDoubleChar(o_fRetval, io_rPos, rStr) )
     132           0 :                     return false;
     133             : 
     134      140107 :                 lcl_skipSpacesAndCommas(io_rPos, rStr, nLen);
     135             : 
     136      140107 :                 return true;
     137             :             }
     138             : 
     139           0 :             bool lcl_importFlagAndSpaces(sal_Int32&         o_nRetval,
     140             :                                          sal_Int32&         io_rPos,
     141             :                                          const OUString&    rStr,
     142             :                                          const sal_Int32    nLen)
     143             :             {
     144           0 :                 sal_Unicode aChar( rStr[io_rPos] );
     145             : 
     146           0 :                 if(sal_Unicode('0') == aChar)
     147             :                 {
     148           0 :                     o_nRetval = 0;
     149           0 :                     ++io_rPos;
     150             :                 }
     151           0 :                 else if (sal_Unicode('1') == aChar)
     152             :                 {
     153           0 :                     o_nRetval = 1;
     154           0 :                     ++io_rPos;
     155             :                 }
     156             :                 else
     157           0 :                     return false;
     158             : 
     159           0 :                 lcl_skipSpacesAndCommas(io_rPos, rStr, nLen);
     160             : 
     161           0 :                 return true;
     162             :             }
     163             : 
     164        2827 :             void lcl_putNumberChar( OUStringBuffer& rStr,
     165             :                                     double          fValue )
     166             :             {
     167        2827 :                 rStr.append( fValue );
     168        2827 :             }
     169             : 
     170        2827 :             void lcl_putNumberCharWithSpace( OUStringBuffer&    rStr,
     171             :                                              double             fValue,
     172             :                                              double                 fOldValue,
     173             :                                              bool                   bUseRelativeCoordinates )
     174             :             {
     175        2827 :                 if( bUseRelativeCoordinates )
     176        2822 :                     fValue -= fOldValue;
     177             : 
     178        2827 :                 const sal_Int32 aLen( rStr.getLength() );
     179        2827 :                 if(aLen > 0)
     180             :                 {
     181        2827 :                     if( lcl_isOnNumberChar(rStr[aLen - 1], false) &&
     182             :                         fValue >= 0.0 )
     183             :                     {
     184         944 :                         rStr.append( sal_Unicode(' ') );
     185             :                     }
     186             :                 }
     187             : 
     188        2827 :                 lcl_putNumberChar(rStr, fValue);
     189        2827 :             }
     190             : 
     191        2011 :             inline sal_Unicode lcl_getCommand( sal_Char cUpperCaseCommand,
     192             :                                                sal_Char cLowerCaseCommand,
     193             :                                                bool     bUseRelativeCoordinates )
     194             :             {
     195        2011 :                 return bUseRelativeCoordinates ? cLowerCaseCommand : cUpperCaseCommand;
     196             :             }
     197             :         }
     198             : 
     199        2016 :         bool importFromSvgD(B2DPolyPolygon& o_rPolyPolygon, const OUString&  rSvgDStatement, bool bWrongPositionAfterZ)
     200             :         {
     201        2016 :             o_rPolyPolygon.clear();
     202        2016 :             const sal_Int32 nLen(rSvgDStatement.getLength());
     203        2016 :             sal_Int32 nPos(0);
     204        2016 :             bool bIsClosed(false);
     205        2016 :             double nLastX( 0.0 );
     206        2016 :             double nLastY( 0.0 );
     207        2016 :             B2DPolygon aCurrPoly;
     208             : 
     209             :             // skip initial whitespace
     210        2016 :             lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     211             : 
     212       46935 :             while(nPos < nLen)
     213             :             {
     214       42903 :                 bool bRelative(false);
     215       42903 :                 bool bMoveTo(false);
     216       42903 :                 const sal_Unicode aCurrChar(rSvgDStatement[nPos]);
     217             : 
     218       42903 :                 switch(aCurrChar)
     219             :                 {
     220             :                     case 'z' :
     221             :                     case 'Z' :
     222             :                     {
     223        3768 :                         nPos++;
     224        3768 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     225             : 
     226             :                         // remember closed state of current polygon
     227        3768 :                         bIsClosed = true;
     228             : 
     229             :                         // update current point - we're back at the start
     230        3768 :                         if( aCurrPoly.count() && !bWrongPositionAfterZ)
     231             :                         {
     232        3764 :                             const B2DPoint aFirst( aCurrPoly.getB2DPoint(0) );
     233        3764 :                             nLastX = aFirst.getX();
     234        3764 :                             nLastY = aFirst.getY();
     235             :                         }
     236        3768 :                         break;
     237             :                     }
     238             : 
     239             :                     case 'm' :
     240             :                     case 'M' :
     241             :                     {
     242        3835 :                         bMoveTo = true;
     243             :                         // FALLTHROUGH intended
     244             :                     }
     245             :                     case 'l' :
     246             :                     case 'L' :
     247             :                     {
     248       16551 :                         if('m' == aCurrChar || 'l' == aCurrChar)
     249             :                         {
     250       10588 :                             bRelative = true;
     251             :                         }
     252             : 
     253       16551 :                         if(bMoveTo)
     254             :                         {
     255             :                             // new polygon start, finish old one
     256        3835 :                             if(aCurrPoly.count())
     257             :                             {
     258             :                                 // add current polygon
     259        1819 :                                 if(bIsClosed)
     260             :                                 {
     261        1809 :                                     closeWithGeometryChange(aCurrPoly);
     262             :                                 }
     263             : 
     264        1819 :                                 o_rPolyPolygon.append(aCurrPoly);
     265             : 
     266             :                                 // reset import values
     267        1819 :                                 bIsClosed = false;
     268        1819 :                                 aCurrPoly.clear();
     269             :                             }
     270             :                         }
     271             : 
     272       16551 :                         nPos++;
     273       16551 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     274             : 
     275       16551 :                         while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
     276             :                         {
     277             :                             double nX, nY;
     278             : 
     279       17697 :                             if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
     280       17697 :                             if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
     281             : 
     282       17697 :                             if(bRelative)
     283             :                             {
     284       11714 :                                 nX += nLastX;
     285       11714 :                                 nY += nLastY;
     286             :                             }
     287             : 
     288             :                             // set last position
     289       17697 :                             nLastX = nX;
     290       17697 :                             nLastY = nY;
     291             : 
     292             :                             // add point
     293       17697 :                             aCurrPoly.append(B2DPoint(nX, nY));
     294             :                         }
     295       16551 :                         break;
     296             :                     }
     297             : 
     298             :                     case 'h' :
     299             :                     {
     300        3284 :                         bRelative = true;
     301             :                         // FALLTHROUGH intended
     302             :                     }
     303             :                     case 'H' :
     304             :                     {
     305        4560 :                         nPos++;
     306        4560 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     307             : 
     308       13747 :                         while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
     309             :                         {
     310        4627 :                             double nX, nY(nLastY);
     311             : 
     312        4627 :                             if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
     313             : 
     314        4627 :                             if(bRelative)
     315             :                             {
     316        3351 :                                 nX += nLastX;
     317             :                             }
     318             : 
     319             :                             // set last position
     320        4627 :                             nLastX = nX;
     321             : 
     322             :                             // add point
     323        4627 :                             aCurrPoly.append(B2DPoint(nX, nY));
     324             :                         }
     325        4560 :                         break;
     326             :                     }
     327             : 
     328             :                     case 'v' :
     329             :                     {
     330        2540 :                         bRelative = true;
     331             :                         // FALLTHROUGH intended
     332             :                     }
     333             :                     case 'V' :
     334             :                     {
     335        3624 :                         nPos++;
     336        3624 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     337             : 
     338       10930 :                         while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
     339             :                         {
     340        3682 :                             double nX(nLastX), nY;
     341             : 
     342        3682 :                             if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
     343             : 
     344        3682 :                             if(bRelative)
     345             :                             {
     346        2598 :                                 nY += nLastY;
     347             :                             }
     348             : 
     349             :                             // set last position
     350        3682 :                             nLastY = nY;
     351             : 
     352             :                             // add point
     353        3682 :                             aCurrPoly.append(B2DPoint(nX, nY));
     354             :                         }
     355        3624 :                         break;
     356             :                     }
     357             : 
     358             :                     case 's' :
     359             :                     {
     360         578 :                         bRelative = true;
     361             :                         // FALLTHROUGH intended
     362             :                     }
     363             :                     case 'S' :
     364             :                     {
     365         699 :                         nPos++;
     366         699 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     367             : 
     368         699 :                         while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
     369             :                         {
     370             :                             double nX, nY;
     371             :                             double nX2, nY2;
     372             : 
     373         768 :                             if(!lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false;
     374         768 :                             if(!lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false;
     375         768 :                             if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
     376         768 :                             if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
     377             : 
     378         768 :                             if(bRelative)
     379             :                             {
     380         647 :                                 nX2 += nLastX;
     381         647 :                                 nY2 += nLastY;
     382         647 :                                 nX += nLastX;
     383         647 :                                 nY += nLastY;
     384             :                             }
     385             : 
     386             :                             // ensure existance of start point
     387         768 :                             if(!aCurrPoly.count())
     388             :                             {
     389           0 :                                 aCurrPoly.append(B2DPoint(nLastX, nLastY));
     390             :                             }
     391             : 
     392             :                             // get first control point. It's the reflection of the PrevControlPoint
     393             :                             // of the last point. If not existent, use current point (see SVG)
     394         768 :                             B2DPoint aPrevControl(B2DPoint(nLastX, nLastY));
     395         768 :                             const sal_uInt32 nIndex(aCurrPoly.count() - 1);
     396             : 
     397         768 :                             if(aCurrPoly.areControlPointsUsed() && aCurrPoly.isPrevControlPointUsed(nIndex))
     398             :                             {
     399         565 :                                 const B2DPoint aPrevPoint(aCurrPoly.getB2DPoint(nIndex));
     400        1130 :                                 const B2DPoint aPrevControlPoint(aCurrPoly.getPrevControlPoint(nIndex));
     401             : 
     402             :                                 // use mirrored previous control point
     403         565 :                                 aPrevControl.setX((2.0 * aPrevPoint.getX()) - aPrevControlPoint.getX());
     404        1130 :                                 aPrevControl.setY((2.0 * aPrevPoint.getY()) - aPrevControlPoint.getY());
     405             :                             }
     406             : 
     407             :                             // append curved edge
     408         768 :                             aCurrPoly.appendBezierSegment(aPrevControl, B2DPoint(nX2, nY2), B2DPoint(nX, nY));
     409             : 
     410             :                             // set last position
     411         768 :                             nLastX = nX;
     412         768 :                             nLastY = nY;
     413         768 :                         }
     414         699 :                         break;
     415             :                     }
     416             : 
     417             :                     case 'c' :
     418             :                     {
     419       12226 :                         bRelative = true;
     420             :                         // FALLTHROUGH intended
     421             :                     }
     422             :                     case 'C' :
     423             :                     {
     424       13691 :                         nPos++;
     425       13691 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     426             : 
     427       13691 :                         while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
     428             :                         {
     429             :                             double nX, nY;
     430             :                             double nX1, nY1;
     431             :                             double nX2, nY2;
     432             : 
     433       14237 :                             if(!lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false;
     434       14237 :                             if(!lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false;
     435       14237 :                             if(!lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false;
     436       14237 :                             if(!lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false;
     437       14237 :                             if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
     438       14237 :                             if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
     439             : 
     440       14237 :                             if(bRelative)
     441             :                             {
     442       12760 :                                 nX1 += nLastX;
     443       12760 :                                 nY1 += nLastY;
     444       12760 :                                 nX2 += nLastX;
     445       12760 :                                 nY2 += nLastY;
     446       12760 :                                 nX += nLastX;
     447       12760 :                                 nY += nLastY;
     448             :                             }
     449             : 
     450             :                             // ensure existance of start point
     451       14237 :                             if(!aCurrPoly.count())
     452             :                             {
     453           0 :                                 aCurrPoly.append(B2DPoint(nLastX, nLastY));
     454             :                             }
     455             : 
     456             :                             // append curved edge
     457       14237 :                             aCurrPoly.appendBezierSegment(B2DPoint(nX1, nY1), B2DPoint(nX2, nY2), B2DPoint(nX, nY));
     458             : 
     459             :                             // set last position
     460       14237 :                             nLastX = nX;
     461       14237 :                             nLastY = nY;
     462             :                         }
     463       13691 :                         break;
     464             :                     }
     465             : 
     466             :                     // #100617# quadratic beziers are imported as cubic ones
     467             :                     case 'q' :
     468             :                     {
     469          10 :                         bRelative = true;
     470             :                         // FALLTHROUGH intended
     471             :                     }
     472             :                     case 'Q' :
     473             :                     {
     474          10 :                         nPos++;
     475          10 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     476             : 
     477          10 :                         while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
     478             :                         {
     479             :                             double nX, nY;
     480             :                             double nX1, nY1;
     481             : 
     482          10 :                             if(!lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false;
     483          10 :                             if(!lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false;
     484          10 :                             if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
     485          10 :                             if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
     486             : 
     487          10 :                             if(bRelative)
     488             :                             {
     489          10 :                                 nX1 += nLastX;
     490          10 :                                 nY1 += nLastY;
     491          10 :                                 nX += nLastX;
     492          10 :                                 nY += nLastY;
     493             :                             }
     494             : 
     495             :                             // calculate the cubic bezier coefficients from the quadratic ones
     496          10 :                             const double nX1Prime((nX1 * 2.0 + nLastX) / 3.0);
     497          10 :                             const double nY1Prime((nY1 * 2.0 + nLastY) / 3.0);
     498          10 :                             const double nX2Prime((nX1 * 2.0 + nX) / 3.0);
     499          10 :                             const double nY2Prime((nY1 * 2.0 + nY) / 3.0);
     500             : 
     501             :                             // ensure existance of start point
     502          10 :                             if(!aCurrPoly.count())
     503             :                             {
     504           0 :                                 aCurrPoly.append(B2DPoint(nLastX, nLastY));
     505             :                             }
     506             : 
     507             :                             // append curved edge
     508          10 :                             aCurrPoly.appendBezierSegment(B2DPoint(nX1Prime, nY1Prime), B2DPoint(nX2Prime, nY2Prime), B2DPoint(nX, nY));
     509             : 
     510             :                             // set last position
     511          10 :                             nLastX = nX;
     512          10 :                             nLastY = nY;
     513             :                         }
     514          10 :                         break;
     515             :                     }
     516             : 
     517             :                     // #100617# relative quadratic beziers are imported as cubic
     518             :                     case 't' :
     519             :                     {
     520           0 :                         bRelative = true;
     521             :                         // FALLTHROUGH intended
     522             :                     }
     523             :                     case 'T' :
     524             :                     {
     525           0 :                         nPos++;
     526           0 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     527             : 
     528           0 :                         while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
     529             :                         {
     530             :                             double nX, nY;
     531             : 
     532           0 :                             if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
     533           0 :                             if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
     534             : 
     535           0 :                             if(bRelative)
     536             :                             {
     537           0 :                                 nX += nLastX;
     538           0 :                                 nY += nLastY;
     539             :                             }
     540             : 
     541             :                             // ensure existance of start point
     542           0 :                             if(!aCurrPoly.count())
     543             :                             {
     544           0 :                                 aCurrPoly.append(B2DPoint(nLastX, nLastY));
     545             :                             }
     546             : 
     547             :                             // get first control point. It's the reflection of the PrevControlPoint
     548             :                             // of the last point. If not existent, use current point (see SVG)
     549           0 :                             B2DPoint aPrevControl(B2DPoint(nLastX, nLastY));
     550           0 :                             const sal_uInt32 nIndex(aCurrPoly.count() - 1);
     551           0 :                             const B2DPoint aPrevPoint(aCurrPoly.getB2DPoint(nIndex));
     552             : 
     553           0 :                             if(aCurrPoly.areControlPointsUsed() && aCurrPoly.isPrevControlPointUsed(nIndex))
     554             :                             {
     555           0 :                                 const B2DPoint aPrevControlPoint(aCurrPoly.getPrevControlPoint(nIndex));
     556             : 
     557             :                                 // use mirrored previous control point
     558           0 :                                 aPrevControl.setX((2.0 * aPrevPoint.getX()) - aPrevControlPoint.getX());
     559           0 :                                 aPrevControl.setY((2.0 * aPrevPoint.getY()) - aPrevControlPoint.getY());
     560             :                             }
     561             : 
     562           0 :                             if(!aPrevControl.equal(aPrevPoint))
     563             :                             {
     564             :                                 // there is a prev control point, and we have the already mirrored one
     565             :                                 // in aPrevControl. We also need the quadratic control point for this
     566             :                                 // new quadratic segment to calculate the 2nd cubic control point
     567             :                                 const B2DPoint aQuadControlPoint(
     568           0 :                                     ((3.0 * aPrevControl.getX()) - aPrevPoint.getX()) / 2.0,
     569           0 :                                     ((3.0 * aPrevControl.getY()) - aPrevPoint.getY()) / 2.0);
     570             : 
     571             :                                 // calculate the cubic bezier coefficients from the quadratic ones.
     572           0 :                                 const double nX2Prime((aQuadControlPoint.getX() * 2.0 + nX) / 3.0);
     573           0 :                                 const double nY2Prime((aQuadControlPoint.getY() * 2.0 + nY) / 3.0);
     574             : 
     575             :                                 // append curved edge, use mirrored cubic control point directly
     576           0 :                                 aCurrPoly.appendBezierSegment(aPrevControl, B2DPoint(nX2Prime, nY2Prime), B2DPoint(nX, nY));
     577             :                             }
     578             :                             else
     579             :                             {
     580             :                                 // when no previous control, SVG says to use current point -> straight line.
     581             :                                 // Just add end point
     582           0 :                                 aCurrPoly.append(B2DPoint(nX, nY));
     583             :                             }
     584             : 
     585             :                             // set last position
     586           0 :                             nLastX = nX;
     587           0 :                             nLastY = nY;
     588           0 :                         }
     589           0 :                         break;
     590             :                     }
     591             : 
     592             :                     case 'a' :
     593             :                     {
     594           0 :                         bRelative = true;
     595             :                         // FALLTHROUGH intended
     596             :                     }
     597             :                     case 'A' :
     598             :                     {
     599           0 :                         nPos++;
     600           0 :                         lcl_skipSpaces(nPos, rSvgDStatement, nLen);
     601             : 
     602           0 :                         while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
     603             :                         {
     604             :                             double nX, nY;
     605             :                             double fRX, fRY, fPhi;
     606             :                             sal_Int32 bLargeArcFlag, bSweepFlag;
     607             : 
     608           0 :                             if(!lcl_importDoubleAndSpaces(fRX, nPos, rSvgDStatement, nLen)) return false;
     609           0 :                             if(!lcl_importDoubleAndSpaces(fRY, nPos, rSvgDStatement, nLen)) return false;
     610           0 :                             if(!lcl_importDoubleAndSpaces(fPhi, nPos, rSvgDStatement, nLen)) return false;
     611           0 :                             if(!lcl_importFlagAndSpaces(bLargeArcFlag, nPos, rSvgDStatement, nLen)) return false;
     612           0 :                             if(!lcl_importFlagAndSpaces(bSweepFlag, nPos, rSvgDStatement, nLen)) return false;
     613           0 :                             if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
     614           0 :                             if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
     615             : 
     616           0 :                             if(bRelative)
     617             :                             {
     618           0 :                                 nX += nLastX;
     619           0 :                                 nY += nLastY;
     620             :                             }
     621             : 
     622           0 :                             if( nX == nLastX && nY == nLastY )
     623           0 :                                 continue; // start==end -> skip according to SVG spec
     624             : 
     625           0 :                             if( fRX == 0.0 || fRY == 0.0 )
     626             :                             {
     627             :                                 // straight line segment according to SVG spec
     628           0 :                                 aCurrPoly.append(B2DPoint(nX, nY));
     629             :                             }
     630             :                             else
     631             :                             {
     632             :                                 // normalize according to SVG spec
     633           0 :                                 fRX=fabs(fRX); fRY=fabs(fRY);
     634             : 
     635             :                                 // from the SVG spec, appendix F.6.4
     636             : 
     637             :                                 // |x1'|   |cos phi   sin phi|  |(x1 - x2)/2|
     638             :                                 // |y1'| = |-sin phi  cos phi|  |(y1 - y2)/2|
     639           0 :                                 const B2DPoint p1(nLastX, nLastY);
     640           0 :                                 const B2DPoint p2(nX, nY);
     641           0 :                                 B2DHomMatrix aTransform(basegfx::tools::createRotateB2DHomMatrix(-fPhi*M_PI/180));
     642             : 
     643           0 :                                 const B2DPoint p1_prime( aTransform * B2DPoint(((p1-p2)/2.0)) );
     644             : 
     645             :                                 //           ______________________________________       rx y1'
     646             :                                 // |cx'|  + /  rx^2 ry^2 - rx^2 y1'^2 - ry^2 x1^2           ry
     647             :                                 // |cy'| =-/       rx^2y1'^2 + ry^2 x1'^2               - ry x1'
     648             :                                 //                                                          rx
     649             :                                 // chose + if f_A != f_S
     650             :                                 // chose - if f_A  = f_S
     651           0 :                                 B2DPoint aCenter_prime;
     652             :                                 const double fRadicant(
     653           0 :                                     (fRX*fRX*fRY*fRY - fRX*fRX*p1_prime.getY()*p1_prime.getY() - fRY*fRY*p1_prime.getX()*p1_prime.getX())/
     654           0 :                                     (fRX*fRX*p1_prime.getY()*p1_prime.getY() + fRY*fRY*p1_prime.getX()*p1_prime.getX()));
     655           0 :                                 if( fRadicant < 0.0 )
     656             :                                 {
     657             :                                     // no solution - according to SVG
     658             :                                     // spec, scale up ellipse
     659             :                                     // uniformly such that it passes
     660             :                                     // through end points (denominator
     661             :                                     // of radicant solved for fRY,
     662             :                                     // with s=fRX/fRY)
     663           0 :                                     const double fRatio(fRX/fRY);
     664             :                                     const double fRadicant2(
     665           0 :                                         p1_prime.getY()*p1_prime.getY() +
     666           0 :                                         p1_prime.getX()*p1_prime.getX()/(fRatio*fRatio));
     667           0 :                                     if( fRadicant2 < 0.0 )
     668             :                                     {
     669             :                                         // only trivial solution, one
     670             :                                         // of the axes 0 -> straight
     671             :                                         // line segment according to
     672             :                                         // SVG spec
     673           0 :                                         aCurrPoly.append(B2DPoint(nX, nY));
     674           0 :                                         continue;
     675             :                                     }
     676             : 
     677           0 :                                     fRY=sqrt(fRadicant2);
     678           0 :                                     fRX=fRatio*fRY;
     679             : 
     680             :                                     // keep center_prime forced to (0,0)
     681             :                                 }
     682             :                                 else
     683             :                                 {
     684             :                                     const double fFactor(
     685           0 :                                         (bLargeArcFlag==bSweepFlag ? -1.0 : 1.0) *
     686           0 :                                         sqrt(fRadicant));
     687             : 
     688             :                                     // actually calculate center_prime
     689           0 :                                     aCenter_prime = B2DPoint(
     690           0 :                                         fFactor*fRX*p1_prime.getY()/fRY,
     691           0 :                                         -fFactor*fRY*p1_prime.getX()/fRX);
     692             :                                 }
     693             : 
     694             :                                 //              +           u - v
     695             :                                 // angle(u,v) =  arccos( ------------ )     (take the sign of (ux vy - uy vx))
     696             :                                 //              -        ||u|| ||v||
     697             : 
     698             :                                 //                  1    | (x1' - cx')/rx |
     699             :                                 // theta1 = angle((   ), |                | )
     700             :                                 //                  0    | (y1' - cy')/ry |
     701           0 :                                 const B2DPoint aRadii(fRX,fRY);
     702             :                                 double fTheta1(
     703             :                                     B2DVector(1.0,0.0).angle(
     704           0 :                                         (p1_prime-aCenter_prime)/aRadii));
     705             : 
     706             :                                 //                 |1|    |  (-x1' - cx')/rx |
     707             :                                 // theta2 = angle( | | ,  |                  | )
     708             :                                 //                 |0|    |  (-y1' - cy')/ry |
     709             :                                 double fTheta2(
     710             :                                     B2DVector(1.0,0.0).angle(
     711           0 :                                         (-p1_prime-aCenter_prime)/aRadii));
     712             : 
     713             :                                 // map both angles to [0,2pi)
     714           0 :                                 fTheta1 = fmod(2*M_PI+fTheta1,2*M_PI);
     715           0 :                                 fTheta2 = fmod(2*M_PI+fTheta2,2*M_PI);
     716             : 
     717             :                                 // make sure the large arc is taken
     718             :                                 // (since
     719             :                                 // createPolygonFromEllipseSegment()
     720             :                                 // normalizes to e.g. cw arc)
     721           0 :                                 if( !bSweepFlag )
     722           0 :                                     std::swap(fTheta1,fTheta2);
     723             : 
     724             :                                 // finally, create bezier polygon from this
     725             :                                 B2DPolygon aSegment(
     726             :                                     tools::createPolygonFromUnitEllipseSegment(
     727           0 :                                         fTheta1, fTheta2 ));
     728             : 
     729             :                                 // transform ellipse by rotation & move to final center
     730           0 :                                 aTransform = basegfx::tools::createScaleB2DHomMatrix(fRX, fRY);
     731             :                                 aTransform.translate(aCenter_prime.getX(),
     732           0 :                                                      aCenter_prime.getY());
     733           0 :                                 aTransform.rotate(fPhi*M_PI/180);
     734           0 :                                 const B2DPoint aOffset((p1+p2)/2.0);
     735             :                                 aTransform.translate(aOffset.getX(),
     736           0 :                                                      aOffset.getY());
     737           0 :                                 aSegment.transform(aTransform);
     738             : 
     739             :                                 // createPolygonFromEllipseSegment()
     740             :                                 // always creates arcs that are
     741             :                                 // positively oriented - flip polygon
     742             :                                 // if we swapped angles above
     743           0 :                                 if( !bSweepFlag )
     744           0 :                                     aSegment.flip();
     745           0 :                                 aCurrPoly.append(aSegment);
     746             :                             }
     747             : 
     748             :                             // set last position
     749           0 :                             nLastX = nX;
     750           0 :                             nLastY = nY;
     751             :                         }
     752           0 :                         break;
     753             :                     }
     754             : 
     755             :                     default:
     756             :                     {
     757             :                         OSL_FAIL("importFromSvgD(): skipping tags in svg:d element (unknown)!");
     758             :                         OSL_TRACE("importFromSvgD(): skipping tags in svg:d element (unknown: \"%c\")!", aCurrChar);
     759           0 :                         ++nPos;
     760           0 :                         break;
     761             :                     }
     762             :                 }
     763             :             }
     764             : 
     765        2016 :             if(aCurrPoly.count())
     766             :             {
     767             :                 // end-process last poly
     768        2016 :                 if(bIsClosed)
     769             :                 {
     770        1959 :                     closeWithGeometryChange(aCurrPoly);
     771             :                 }
     772             : 
     773        2016 :                 o_rPolyPolygon.append(aCurrPoly);
     774             :             }
     775             : 
     776        2016 :             return true;
     777             :         }
     778             : 
     779         710 :         bool importFromSvgPoints( B2DPolygon&            o_rPoly,
     780             :                                   const OUString& rSvgPointsAttribute )
     781             :         {
     782         710 :             o_rPoly.clear();
     783         710 :             const sal_Int32 nLen(rSvgPointsAttribute.getLength());
     784         710 :             sal_Int32 nPos(0);
     785             :             double nX, nY;
     786             : 
     787             :             // skip initial whitespace
     788         710 :             lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen);
     789             : 
     790        5355 :             while(nPos < nLen)
     791             :             {
     792        3935 :                 if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgPointsAttribute, nLen)) return false;
     793        3935 :                 if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgPointsAttribute, nLen)) return false;
     794             : 
     795             :                 // add point
     796        3935 :                 o_rPoly.append(B2DPoint(nX, nY));
     797             : 
     798             :                 // skip to next number, or finish
     799        3935 :                 lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen);
     800             :             }
     801             : 
     802         710 :             return true;
     803             :         }
     804             : 
     805          68 :         OUString exportToSvgD(
     806             :             const B2DPolyPolygon& rPolyPolygon,
     807             :             bool bUseRelativeCoordinates,
     808             :             bool bDetectQuadraticBeziers)
     809             :         {
     810          68 :             const sal_uInt32 nCount(rPolyPolygon.count());
     811          68 :             OUStringBuffer aResult;
     812         136 :             B2DPoint aCurrentSVGPosition(0.0, 0.0); // SVG assumes (0,0) as the initial current point
     813             : 
     814         269 :             for(sal_uInt32 i(0); i < nCount; i++)
     815             :             {
     816         201 :                 const B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(i));
     817         201 :                 const sal_uInt32 nPointCount(aPolygon.count());
     818             : 
     819         201 :                 if(nPointCount)
     820             :                 {
     821         201 :                     const bool bPolyUsesControlPoints(aPolygon.areControlPointsUsed());
     822         201 :                     const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount : nPointCount - 1);
     823         201 :                     sal_Unicode aLastSVGCommand(' '); // last SVG command char
     824         402 :                     B2DPoint aLeft, aRight; // for quadratic bezier test
     825             : 
     826             :                     // handle polygon start point
     827         402 :                     B2DPoint aEdgeStart(aPolygon.getB2DPoint(0));
     828         201 :                     aResult.append(lcl_getCommand('M', 'm', bUseRelativeCoordinates));
     829         201 :                     lcl_putNumberCharWithSpace(aResult, aEdgeStart.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     830         201 :                     lcl_putNumberCharWithSpace(aResult, aEdgeStart.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     831         201 :                     aLastSVGCommand =  lcl_getCommand('L', 'l', bUseRelativeCoordinates);
     832         201 :                     aCurrentSVGPosition = aEdgeStart;
     833             : 
     834        1838 :                     for(sal_uInt32 nIndex(0); nIndex < nEdgeCount; nIndex++)
     835             :                     {
     836             :                         // prepare access to next point
     837        1637 :                         const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
     838        1637 :                         const B2DPoint aEdgeEnd(aPolygon.getB2DPoint(nNextIndex));
     839             : 
     840             :                         // handle edge from (aEdgeStart, aEdgeEnd) using indices (nIndex, nNextIndex)
     841             :                         const bool bEdgeIsBezier(bPolyUsesControlPoints
     842        1637 :                             && (aPolygon.isNextControlPointUsed(nIndex) || aPolygon.isPrevControlPointUsed(nNextIndex)));
     843             : 
     844        1637 :                         if(bEdgeIsBezier)
     845             :                         {
     846             :                             // handle bezier edge
     847         109 :                             const B2DPoint aControlEdgeStart(aPolygon.getNextControlPoint(nIndex));
     848         218 :                             const B2DPoint aControlEdgeEnd(aPolygon.getPrevControlPoint(nNextIndex));
     849         109 :                             bool bIsQuadraticBezier(false);
     850             : 
     851             :                             // check continuity at current edge's start point. For SVG, do NOT use an
     852             :                             // existing continuity since no 'S' or 's' statement should be written. At
     853             :                             // import, that 'previous' control vector is not available. SVG documentation
     854             :                             // says for interpretation:
     855             :                             //
     856             :                             // "(If there is no previous command or if the previous command was
     857             :                             // not an C, c, S or s, assume the first control point is coincident
     858             :                             // with the current point.)"
     859             :                             //
     860             :                             // That's what is done from our import, so avoid exporting it as first statement
     861             :                             // is necessary.
     862             :                             const bool bSymmetricAtEdgeStart(
     863             :                                 0 != nIndex
     864         109 :                                 && CONTINUITY_C2 == aPolygon.getContinuityInPoint(nIndex));
     865             : 
     866         109 :                             if(bDetectQuadraticBeziers)
     867             :                             {
     868             :                                 // check for quadratic beziers - that's
     869             :                                 // the case if both control points are in
     870             :                                 // the same place when they are prolonged
     871             :                                 // to the common quadratic control point
     872             :                                 //
     873             :                                 // Left: P = (3P1 - P0) / 2
     874             :                                 // Right: P = (3P2 - P3) / 2
     875         109 :                                 aLeft = B2DPoint((3.0 * aControlEdgeStart - aEdgeStart) / 2.0);
     876         109 :                                 aRight= B2DPoint((3.0 * aControlEdgeEnd - aEdgeEnd) / 2.0);
     877         109 :                                 bIsQuadraticBezier = aLeft.equal(aRight);
     878             :                             }
     879             : 
     880         109 :                             if(bIsQuadraticBezier)
     881             :                             {
     882             :                                 // approximately equal, export as quadratic bezier
     883          10 :                                 if(bSymmetricAtEdgeStart)
     884             :                                 {
     885           0 :                                     const sal_Unicode aCommand(lcl_getCommand('T', 't', bUseRelativeCoordinates));
     886             : 
     887           0 :                                     if(aLastSVGCommand != aCommand)
     888             :                                     {
     889           0 :                                         aResult.append(aCommand);
     890           0 :                                         aLastSVGCommand = aCommand;
     891             :                                     }
     892             : 
     893           0 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     894           0 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     895           0 :                                     aLastSVGCommand = aCommand;
     896           0 :                                     aCurrentSVGPosition = aEdgeEnd;
     897             :                                 }
     898             :                                 else
     899             :                                 {
     900          10 :                                     const sal_Unicode aCommand(lcl_getCommand('Q', 'q', bUseRelativeCoordinates));
     901             : 
     902          10 :                                     if(aLastSVGCommand != aCommand)
     903             :                                     {
     904          10 :                                         aResult.append(aCommand);
     905          10 :                                         aLastSVGCommand = aCommand;
     906             :                                     }
     907             : 
     908          10 :                                     lcl_putNumberCharWithSpace(aResult, aLeft.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     909          10 :                                     lcl_putNumberCharWithSpace(aResult, aLeft.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     910          10 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     911          10 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     912          10 :                                     aLastSVGCommand = aCommand;
     913          10 :                                     aCurrentSVGPosition = aEdgeEnd;
     914             :                                 }
     915             :                             }
     916             :                             else
     917             :                             {
     918             :                                 // export as cubic bezier
     919          99 :                                 if(bSymmetricAtEdgeStart)
     920             :                                 {
     921          21 :                                     const sal_Unicode aCommand(lcl_getCommand('S', 's', bUseRelativeCoordinates));
     922             : 
     923          21 :                                     if(aLastSVGCommand != aCommand)
     924             :                                     {
     925          17 :                                         aResult.append(aCommand);
     926          17 :                                         aLastSVGCommand = aCommand;
     927             :                                     }
     928             : 
     929          21 :                                     lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     930          21 :                                     lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     931          21 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     932          21 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     933          21 :                                     aLastSVGCommand = aCommand;
     934          21 :                                     aCurrentSVGPosition = aEdgeEnd;
     935             :                                 }
     936             :                                 else
     937             :                                 {
     938          78 :                                     const sal_Unicode aCommand(lcl_getCommand('C', 'c', bUseRelativeCoordinates));
     939             : 
     940          78 :                                     if(aLastSVGCommand != aCommand)
     941             :                                     {
     942          31 :                                         aResult.append(aCommand);
     943          31 :                                         aLastSVGCommand = aCommand;
     944             :                                     }
     945             : 
     946          78 :                                     lcl_putNumberCharWithSpace(aResult, aControlEdgeStart.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     947          78 :                                     lcl_putNumberCharWithSpace(aResult, aControlEdgeStart.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     948          78 :                                     lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     949          78 :                                     lcl_putNumberCharWithSpace(aResult, aControlEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     950          78 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
     951          78 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     952          78 :                                     aLastSVGCommand = aCommand;
     953          78 :                                     aCurrentSVGPosition = aEdgeEnd;
     954             :                                 }
     955         109 :                             }
     956             :                         }
     957             :                         else
     958             :                         {
     959             :                             // straight edge
     960        1528 :                             if(0 == nNextIndex)
     961             :                             {
     962             :                                 // it's a closed polygon's last edge and it's not a bezier edge, so there is
     963             :                                 // no need to write it
     964             :                             }
     965             :                             else
     966             :                             {
     967        1379 :                                 const bool bXEqual(aEdgeStart.getX() == aEdgeEnd.getX());
     968        1379 :                                 const bool bYEqual(aEdgeStart.getY() == aEdgeEnd.getY());
     969             : 
     970        1379 :                                 if(bXEqual && bYEqual)
     971             :                                 {
     972             :                                     // point is a double point; do not export at all
     973             :                                 }
     974        1347 :                                 else if(bXEqual)
     975             :                                 {
     976             :                                     // export as vertical line
     977         451 :                                     const sal_Unicode aCommand(lcl_getCommand('V', 'v', bUseRelativeCoordinates));
     978             : 
     979         451 :                                     if(aLastSVGCommand != aCommand)
     980             :                                     {
     981         430 :                                         aResult.append(aCommand);
     982         430 :                                         aLastSVGCommand = aCommand;
     983             :                                     }
     984             : 
     985         451 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
     986         451 :                                     aCurrentSVGPosition = aEdgeEnd;
     987             :                                 }
     988         896 :                                 else if(bYEqual)
     989             :                                 {
     990             :                                     // export as horizontal line
     991         410 :                                     const sal_Unicode aCommand(lcl_getCommand('H', 'h', bUseRelativeCoordinates));
     992             : 
     993         410 :                                     if(aLastSVGCommand != aCommand)
     994             :                                     {
     995         380 :                                         aResult.append(aCommand);
     996         380 :                                         aLastSVGCommand = aCommand;
     997             :                                     }
     998             : 
     999         410 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
    1000         410 :                                     aCurrentSVGPosition = aEdgeEnd;
    1001             :                                 }
    1002             :                                 else
    1003             :                                 {
    1004             :                                     // export as line
    1005         486 :                                     const sal_Unicode aCommand(lcl_getCommand('L', 'l', bUseRelativeCoordinates));
    1006             : 
    1007         486 :                                     if(aLastSVGCommand != aCommand)
    1008             :                                     {
    1009           6 :                                         aResult.append(aCommand);
    1010           6 :                                         aLastSVGCommand = aCommand;
    1011             :                                     }
    1012             : 
    1013         486 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getX(), aCurrentSVGPosition.getX(), bUseRelativeCoordinates);
    1014         486 :                                     lcl_putNumberCharWithSpace(aResult, aEdgeEnd.getY(), aCurrentSVGPosition.getY(), bUseRelativeCoordinates);
    1015         486 :                                     aCurrentSVGPosition = aEdgeEnd;
    1016             :                                 }
    1017             :                             }
    1018             :                         }
    1019             : 
    1020             :                         // prepare edge start for next loop step
    1021        1637 :                         aEdgeStart = aEdgeEnd;
    1022        1637 :                     }
    1023             : 
    1024             :                     // close path if closed poly (Z and z are equivalent here, but looks nicer when case is matched)
    1025         201 :                     if(aPolygon.isClosed())
    1026             :                     {
    1027         153 :                         aResult.append(lcl_getCommand('Z', 'z', bUseRelativeCoordinates));
    1028             :                         // return to first point
    1029         153 :                         aCurrentSVGPosition = aPolygon.getB2DPoint(0);
    1030         201 :                     }
    1031             :                 }
    1032         201 :             }
    1033             : 
    1034         136 :             return aResult.makeStringAndClear();
    1035             :         }
    1036             :     }
    1037             : }
    1038             : 
    1039             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10