LCOV - code coverage report
Current view: top level - svgio/source/svgreader - svgtools.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 478 803 59.5 %
Date: 2014-04-11 Functions: 28 35 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <svgio/svgreader/svgtools.hxx>
      21             : #include <osl/thread.h>
      22             : #include <tools/color.hxx>
      23             : #include <basegfx/matrix/b2dhommatrix.hxx>
      24             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      25             : #include <svgio/svgreader/svgtoken.hxx>
      26             : #include <boost/unordered_map.hpp>
      27             : 
      28             : 
      29             : 
      30             : namespace svgio
      31             : {
      32             :     namespace svgreader
      33             :     {
      34             : #ifdef DBG_UTIL
      35             :         void myAssert(const OUString& rMessage)
      36             :         {
      37             :             OString aMessage2;
      38             : 
      39             :             rMessage.convertToString(&aMessage2, osl_getThreadTextEncoding(), RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR|RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR);
      40             :             OSL_ENSURE(false, aMessage2.getStr());
      41             :         }
      42             : #endif
      43             : 
      44             :         // common non-token strings
      45           5 :         const OUString commonStrings::aStrUserSpaceOnUse("userSpaceOnUse");
      46           5 :         const OUString commonStrings::aStrObjectBoundingBox("objectBoundingBox");
      47           5 :         const OUString commonStrings::aStrNonzero("nonzero");
      48           5 :         const OUString commonStrings::aStrEvenOdd("evenodd");
      49             : 
      50         237 :         basegfx::B2DHomMatrix SvgAspectRatio::createLinearMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource)
      51             :         {
      52         237 :             basegfx::B2DHomMatrix aRetval;
      53         237 :             const double fSWidth(rSource.getWidth());
      54         237 :             const double fSHeight(rSource.getHeight());
      55         237 :             const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth));
      56         237 :             const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight));
      57             : 
      58             :             // transform from source state to unit range
      59         237 :             aRetval.translate(-rSource.getMinX(), -rSource.getMinY());
      60             :             aRetval.scale(
      61         474 :                 (bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth(),
      62         711 :                 (bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight());
      63             : 
      64             :             // transform from unit rage to target range
      65         237 :             aRetval.translate(rTarget.getMinX(), rTarget.getMinY());
      66             : 
      67         237 :             return aRetval;
      68             :         }
      69             : 
      70         292 :         basegfx::B2DHomMatrix SvgAspectRatio::createMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource) const
      71             :         {
      72         292 :             if(!isSet() || Align_none == getSvgAlign())
      73             :             {
      74             :                 // create linear mapping (default)
      75           0 :                 return createLinearMapping(rTarget, rSource);
      76             :             }
      77             : 
      78         292 :             basegfx::B2DHomMatrix aRetval;
      79             : 
      80         292 :             const double fSWidth(rSource.getWidth());
      81         292 :             const double fSHeight(rSource.getHeight());
      82         292 :             const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth));
      83         292 :             const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight));
      84         292 :             const double fScaleX((bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth());
      85         292 :             const double fScaleY((bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight());
      86         292 :             const double fScale(isMeetOrSlice() ? std::min(fScaleX, fScaleY) : std::max(fScaleX, fScaleY));
      87             : 
      88             :             // remove source translation, apply scale
      89         292 :             aRetval.translate(-rSource.getMinX(), -rSource.getMinY());
      90         292 :             aRetval.scale(fScale, fScale);
      91             : 
      92             :             // evaluate horizontal alignment
      93         292 :             const double fNewWidth(fSWidth * fScale);
      94         292 :             double fTransX(0.0);
      95             : 
      96         292 :             switch(getSvgAlign())
      97             :             {
      98             :                 case Align_xMidYMin:
      99             :                 case Align_xMidYMid:
     100             :                 case Align_xMidYMax:
     101             :                 {
     102             :                     // centerX
     103         292 :                     const double fFreeSpace(rTarget.getWidth() - fNewWidth);
     104         292 :                     fTransX = fFreeSpace * 0.5;
     105         292 :                     break;
     106             :                 }
     107             :                 case Align_xMaxYMin:
     108             :                 case Align_xMaxYMid:
     109             :                 case Align_xMaxYMax:
     110             :                 {
     111             :                     // Right align
     112           0 :                     const double fFreeSpace(rTarget.getWidth() - fNewWidth);
     113           0 :                     fTransX = fFreeSpace;
     114           0 :                     break;
     115             :                 }
     116           0 :                 default: break;
     117             :             }
     118             : 
     119             :             // evaluate vertical alignment
     120         292 :             const double fNewHeight(fSHeight * fScale);
     121         292 :             double fTransY(0.0);
     122             : 
     123         292 :             switch(getSvgAlign())
     124             :             {
     125             :                 case Align_xMinYMid:
     126             :                 case Align_xMidYMid:
     127             :                 case Align_xMaxYMid:
     128             :                 {
     129             :                     // centerY
     130         292 :                     const double fFreeSpace(rTarget.getHeight() - fNewHeight);
     131         292 :                     fTransY = fFreeSpace * 0.5;
     132         292 :                     break;
     133             :                 }
     134             :                 case Align_xMinYMax:
     135             :                 case Align_xMidYMax:
     136             :                 case Align_xMaxYMax:
     137             :                 {
     138             :                     // Bottom align
     139           0 :                     const double fFreeSpace(rTarget.getHeight() - fNewHeight);
     140           0 :                     fTransY = fFreeSpace;
     141           0 :                     break;
     142             :                 }
     143           0 :                 default: break;
     144             :             }
     145             : 
     146             :             // add target translation
     147             :             aRetval.translate(
     148         292 :                 rTarget.getMinX() + fTransX,
     149         584 :                 rTarget.getMinY() + fTransY);
     150             : 
     151         292 :             return aRetval;
     152             :         }
     153             : 
     154         584 :         double SvgNumber::solveNonPercentage(const InfoProvider& rInfoProvider) const
     155             :         {
     156         584 :             if(isSet())
     157             :             {
     158         584 :                 switch(meUnit)
     159             :                 {
     160             :                     case Unit_em:
     161             :                     {
     162           0 :                         return mfNumber * rInfoProvider.getCurrentFontSizeInherited();
     163             :                     }
     164             :                     case Unit_ex:
     165             :                     {
     166           0 :                         return mfNumber * rInfoProvider.getCurrentXHeightInherited() * 0.5;
     167             :                     }
     168             :                     case Unit_px:
     169             :                     {
     170         584 :                         return mfNumber;
     171             :                     }
     172             :                     case Unit_pt:
     173             :                     case Unit_pc:
     174             :                     case Unit_cm:
     175             :                     case Unit_mm:
     176             :                     case Unit_in:
     177             :                     {
     178           0 :                         double fRetval(mfNumber);
     179             : 
     180           0 :                         switch(meUnit)
     181             :                         {
     182           0 :                             case Unit_pt: fRetval *= F_SVG_PIXEL_PER_INCH / 72.0; break;
     183           0 :                             case Unit_pc: fRetval *= F_SVG_PIXEL_PER_INCH / 6.0; break;
     184           0 :                             case Unit_cm: fRetval *= F_SVG_PIXEL_PER_INCH / 2.54; break;
     185           0 :                             case Unit_mm: fRetval *= 0.1 * F_SVG_PIXEL_PER_INCH / 2.54; break;
     186           0 :                             case Unit_in: fRetval *= F_SVG_PIXEL_PER_INCH; break;
     187           0 :                             default: break;
     188             :                         }
     189             : 
     190           0 :                         return fRetval;
     191             :                         break;
     192             :                     }
     193             :                     default:
     194             :                     {
     195             :                         OSL_ENSURE(false, "Do not use with percentage! ");
     196           0 :                         return 0.0;
     197             :                     }
     198             :                 }
     199             :             }
     200             : 
     201             :             /// not set
     202             :             OSL_ENSURE(false, "SvgNumber not set (!)");
     203           0 :             return 0.0;
     204             :         }
     205             : 
     206       22748 :         double SvgNumber::solve(const InfoProvider& rInfoProvider, NumberType aNumberType) const
     207             :         {
     208       22748 :             if(isSet())
     209             :             {
     210       22748 :                 switch(meUnit)
     211             :                 {
     212             :                     case Unit_px:
     213             :                     {
     214       22748 :                         return mfNumber;
     215             :                     }
     216             :                     case Unit_pt:
     217             :                     case Unit_pc:
     218             :                     case Unit_cm:
     219             :                     case Unit_mm:
     220             :                     case Unit_in:
     221             :                     case Unit_em:
     222             :                     case Unit_ex:
     223             :                     {
     224           0 :                         return solveNonPercentage( rInfoProvider);
     225             :                     }
     226             :                     case Unit_percent:
     227             :                     {
     228           0 :                         double fRetval(mfNumber * 0.01);
     229           0 :                         basegfx::B2DRange aViewPort = rInfoProvider.getCurrentViewPort();
     230             : 
     231           0 :                         if ( aViewPort.isEmpty() )
     232             :                         {
     233             : #ifdef DBG_UTIL
     234             :                             myAssert(OUString("Design error, this case should have been handled in the caller"));
     235             : #endif
     236             :                             // no viewPort, assume a normal page size (A4)
     237             :                             aViewPort = basegfx::B2DRange(
     238             :                                 0.0,
     239             :                                 0.0,
     240             :                                 210.0 * F_SVG_PIXEL_PER_INCH / 2.54,
     241           0 :                                 297.0 * F_SVG_PIXEL_PER_INCH / 2.54);
     242             : 
     243             :                         }
     244             : 
     245           0 :                         if ( !aViewPort.isEmpty() )
     246             :                         {
     247           0 :                             if(xcoordinate == aNumberType)
     248             :                             {
     249             :                                 // it's a x-coordinate, relative to current width (w)
     250           0 :                                 fRetval *= aViewPort.getWidth();
     251             :                             }
     252           0 :                             else if(ycoordinate == aNumberType)
     253             :                             {
     254             :                                 // it's a y-coordinate, relative to current height (h)
     255           0 :                                 fRetval *= aViewPort.getHeight();
     256             :                             }
     257             :                             else // length
     258             :                             {
     259             :                                 // it's a length, relative to sqrt(w*w + h*h)/sqrt(2)
     260           0 :                                 const double fCurrentWidth(aViewPort.getWidth());
     261           0 :                                 const double fCurrentHeight(aViewPort.getHeight());
     262             :                                 const double fCurrentLength(
     263           0 :                                     sqrt(fCurrentWidth * fCurrentWidth + fCurrentHeight * fCurrentHeight)/sqrt(2.0));
     264             : 
     265           0 :                                 fRetval *= fCurrentLength;
     266             :                             }
     267             :                         }
     268             : 
     269           0 :                         return fRetval;
     270             :                     }
     271             :                     default:
     272             :                     {
     273           0 :                         break;
     274             :                     }
     275             :                 }
     276             :             }
     277             : 
     278             :             /// not set
     279             :             OSL_ENSURE(false, "SvgNumber not set (!)");
     280           0 :             return 0.0;
     281             :         }
     282             : 
     283        5779 :         bool SvgNumber::isPositive() const
     284             :         {
     285        5779 :             return basegfx::fTools::moreOrEqual(mfNumber, 0.0);
     286             :         }
     287             : 
     288       21282 :         void skip_char(const OUString& rCandidate, const sal_Unicode& rChar, sal_Int32& nPos, const sal_Int32 nLen)
     289             :         {
     290       46091 :             while(nPos < nLen && rChar == rCandidate[nPos])
     291             :             {
     292        3527 :                 nPos++;
     293             :             }
     294       21282 :         }
     295             : 
     296       15446 :         void skip_char(const OUString& rCandidate, const sal_Unicode& rCharA, const sal_Unicode& rCharB, sal_Int32& nPos, const sal_Int32 nLen)
     297             :         {
     298       39427 :             while(nPos < nLen && (rCharA == rCandidate[nPos] || rCharB == rCandidate[nPos]))
     299             :             {
     300        8535 :                 nPos++;
     301             :             }
     302       15446 :         }
     303             : 
     304       17455 :         void copySign(const OUString& rCandidate, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
     305             :         {
     306       17455 :             if(nPos < nLen)
     307             :             {
     308       17455 :                 const sal_Unicode aChar(rCandidate[nPos]);
     309             : 
     310       17455 :                 if('+' == aChar || '-' == aChar)
     311             :                 {
     312        1150 :                     rTarget.append(aChar);
     313        1150 :                     nPos++;
     314             :                 }
     315             :             }
     316       17455 :         }
     317             : 
     318       17455 :         void copyNumber(const OUString& rCandidate, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
     319             :         {
     320       17455 :             bool bOnNumber(true);
     321             : 
     322      125697 :             while(bOnNumber && nPos < nLen)
     323             :             {
     324       90787 :                 const sal_Unicode aChar(rCandidate[nPos]);
     325             : 
     326       90787 :                 bOnNumber = ('0' <= aChar && '9' >= aChar) || '.' == aChar;
     327             : 
     328       90787 :                 if(bOnNumber)
     329             :                 {
     330       86614 :                     rTarget.append(aChar);
     331       86614 :                     nPos++;
     332             :                 }
     333             :             }
     334       17455 :         }
     335             : 
     336        5132 :         void copyHex(const OUString& rCandidate, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
     337             :         {
     338        5132 :             bool bOnHex(true);
     339             : 
     340       41056 :             while(bOnHex && nPos < nLen)
     341             :             {
     342       30792 :                 const sal_Unicode aChar(rCandidate[nPos]);
     343             : 
     344       30792 :                 bOnHex = ('0' <= aChar && '9' >= aChar)
     345       14387 :                     || ('A' <= aChar && 'F' >= aChar)
     346       30973 :                     || ('a' <= aChar && 'f' >= aChar);
     347             : 
     348       30792 :                 if(bOnHex)
     349             :                 {
     350       30792 :                     rTarget.append(aChar);
     351       30792 :                     nPos++;
     352             :                 }
     353             :             }
     354        5132 :         }
     355             : 
     356        3617 :         void copyString(const OUString& rCandidate, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
     357             :         {
     358        3617 :             bool bOnChar(true);
     359             : 
     360       46298 :             while(bOnChar && nPos < nLen)
     361             :             {
     362       39064 :                 const sal_Unicode aChar(rCandidate[nPos]);
     363             : 
     364       31990 :                 bOnChar = ('a' <= aChar && 'z' >= aChar)
     365        7074 :                     || ('A' <= aChar && 'Z' >= aChar)
     366       46138 :                     || '-' == aChar;
     367             : 
     368       39064 :                 if(bOnChar)
     369             :                 {
     370       35447 :                     rTarget.append(aChar);
     371       35447 :                     nPos++;
     372             :                 }
     373             :             }
     374        3617 :         }
     375             : 
     376        5465 :         void copyToLimiter(const OUString& rCandidate, const sal_Unicode& rLimiter, sal_Int32& nPos, OUStringBuffer& rTarget, const sal_Int32 nLen)
     377             :         {
     378       52594 :             while(nPos < nLen && rLimiter != rCandidate[nPos])
     379             :             {
     380       41664 :                 rTarget.append(rCandidate[nPos]);
     381       41664 :                 nPos++;
     382             :             }
     383        5465 :         }
     384             : 
     385       17442 :         bool readNumber(const OUString& rCandidate, sal_Int32& nPos, double& fNum, const sal_Int32 nLen)
     386             :         {
     387       17442 :             if(nPos < nLen)
     388             :             {
     389       17427 :                 OUStringBuffer aNum;
     390             : 
     391       17427 :                 copySign(rCandidate, nPos, aNum, nLen);
     392       17427 :                 copyNumber(rCandidate, nPos, aNum, nLen);
     393             : 
     394       17427 :                 if(nPos < nLen)
     395             :                 {
     396        4145 :                     const sal_Unicode aChar(rCandidate[nPos]);
     397             : 
     398        4145 :                     if('e' == aChar || 'E' == aChar)
     399             :                     {
     400             :                         // try to read exponential number, but be careful. I had
     401             :                         // a case where dx="2em" was used, thus the 'e' was consumed
     402             :                         // by error. First try if there are numbers after the 'e',
     403             :                         // safe current state
     404          28 :                         nPos++;
     405          28 :                         const OUStringBuffer aNum2(aNum);
     406          28 :                         const sal_Int32 nPosAfterE(nPos);
     407             : 
     408          28 :                         aNum.append(aChar);
     409          28 :                         copySign(rCandidate, nPos, aNum, nLen);
     410          28 :                         copyNumber(rCandidate, nPos, aNum, nLen);
     411             : 
     412          28 :                         if(nPosAfterE == nPos)
     413             :                         {
     414             :                             // no number after 'e', go back. Do not
     415             :                             // return false, it's still a valid integer number
     416           0 :                             aNum = aNum2;
     417           0 :                             nPos--;
     418          28 :                         }
     419             :                     }
     420             :                 }
     421             : 
     422       17427 :                 if(!aNum.isEmpty())
     423             :                 {
     424             :                     rtl_math_ConversionStatus eStatus;
     425             : 
     426             :                     fNum = rtl::math::stringToDouble(
     427             :                         aNum.makeStringAndClear(), '.', ',',
     428       17427 :                         &eStatus, 0);
     429             : 
     430       17427 :                     return eStatus == rtl_math_ConversionStatus_Ok;
     431           0 :                 }
     432             :             }
     433             : 
     434          15 :             return false;
     435             :         }
     436             : 
     437       17427 :         SvgUnit readUnit(const OUString& rCandidate, sal_Int32& nPos, const sal_Int32 nLen)
     438             :         {
     439       17427 :             SvgUnit aRetval(Unit_px);
     440             : 
     441       17427 :             if(nPos < nLen)
     442             :             {
     443        4145 :                 const sal_Unicode aCharA(rCandidate[nPos]);
     444             : 
     445        4145 :                 if(nPos + 1 < nLen)
     446             :                 {
     447        3587 :                     const sal_Unicode aCharB(rCandidate[nPos + 1]);
     448        3587 :                     bool bTwoCharValid(false);
     449             : 
     450        3587 :                     switch(aCharA)
     451             :                     {
     452             :                         case sal_Unicode('e') :
     453             :                         {
     454           0 :                             if('m' == aCharB)
     455             :                             {
     456             :                                 // 'em' Relative to current font size
     457           0 :                                 aRetval = Unit_em;
     458           0 :                                 bTwoCharValid = true;
     459             :                             }
     460           0 :                             else if('x' == aCharB)
     461             :                             {
     462             :                                 // 'ex' Relative to current font x-height
     463           0 :                                 aRetval = Unit_ex;
     464           0 :                                 bTwoCharValid = true;
     465             :                             }
     466           0 :                             break;
     467             :                         }
     468             :                         case sal_Unicode('p') :
     469             :                         {
     470           0 :                             if('x' == aCharB)
     471             :                             {
     472             :                                 // 'px' UserUnit (default)
     473           0 :                                 bTwoCharValid = true;
     474             :                             }
     475           0 :                             else if('t' == aCharB)
     476             :                             {
     477             :                                 // 'pt' == 1.25 px
     478           0 :                                 aRetval = Unit_pt;
     479           0 :                                 bTwoCharValid = true;
     480             :                             }
     481           0 :                             else if('c' == aCharB)
     482             :                             {
     483             :                                 // 'pc' == 15 px
     484           0 :                                 aRetval = Unit_pc;
     485           0 :                                 bTwoCharValid = true;
     486             :                             }
     487           0 :                             break;
     488             :                         }
     489             :                         case sal_Unicode('i') :
     490             :                         {
     491           0 :                             if('n' == aCharB)
     492             :                             {
     493             :                                 // 'in' == 90 px
     494           0 :                                 aRetval = Unit_in;
     495           0 :                                 bTwoCharValid = true;
     496             :                             }
     497           0 :                             break;
     498             :                         }
     499             :                         case sal_Unicode('c') :
     500             :                         {
     501           0 :                             if('m' == aCharB)
     502             :                             {
     503             :                                 // 'cm' == 35.43307 px
     504           0 :                                 aRetval = Unit_cm;
     505           0 :                                 bTwoCharValid = true;
     506             :                             }
     507           0 :                             break;
     508             :                         }
     509             :                         case sal_Unicode('m') :
     510             :                         {
     511           0 :                             if('m' == aCharB)
     512             :                             {
     513             :                                 // 'mm' == 3.543307 px
     514           0 :                                 aRetval = Unit_mm;
     515           0 :                                 bTwoCharValid = true;
     516             :                             }
     517           0 :                             break;
     518             :                         }
     519             :                     }
     520             : 
     521        3587 :                     if(bTwoCharValid)
     522             :                     {
     523           0 :                         nPos += 2;
     524             :                     }
     525             :                 }
     526             :                 else
     527             :                 {
     528         558 :                     if('%' == aCharA)
     529             :                     {
     530             :                         // percent used, relative to current
     531           0 :                         nPos++;
     532           0 :                         aRetval = Unit_percent;
     533             :                     }
     534             :                 }
     535             :             }
     536             : 
     537       17427 :             return aRetval;
     538             :         }
     539             : 
     540       17442 :         bool readNumberAndUnit(const OUString& rCandidate, sal_Int32& nPos, SvgNumber& aNum, const sal_Int32 nLen)
     541             :         {
     542       17442 :             double fNum(0.0);
     543             : 
     544       17442 :             if(readNumber(rCandidate, nPos, fNum, nLen))
     545             :             {
     546       17427 :                 skip_char(rCandidate, ' ', nPos, nLen);
     547       17427 :                 aNum = SvgNumber(fNum, readUnit(rCandidate, nPos, nLen));
     548             : 
     549       17427 :                 return true;
     550             :             }
     551             : 
     552          15 :             return false;
     553             :         }
     554             : 
     555           0 :         bool readAngle(const OUString& rCandidate, sal_Int32& nPos, double& fAngle, const sal_Int32 nLen)
     556             :         {
     557           0 :             if(readNumber(rCandidate, nPos, fAngle, nLen))
     558             :             {
     559           0 :                 skip_char(rCandidate, ' ', nPos, nLen);
     560             : 
     561             :                 enum DegreeType
     562             :                 {
     563             :                     deg,
     564             :                     grad,
     565             :                     rad
     566           0 :                 } aType(deg); // degrees is default
     567             : 
     568           0 :                 if(nPos < nLen)
     569             :                 {
     570           0 :                     const sal_Unicode aChar(rCandidate[nPos]);
     571           0 :                     static OUString aStrGrad("grad");
     572           0 :                     static OUString aStrRad("rad");
     573             : 
     574           0 :                     switch(aChar)
     575             :                     {
     576             :                         case sal_Unicode('g') :
     577             :                         case sal_Unicode('G') :
     578             :                         {
     579           0 :                             if(rCandidate.matchIgnoreAsciiCase(aStrGrad, nPos))
     580             :                             {
     581             :                                 // angle in grad
     582           0 :                                 nPos += aStrGrad.getLength();
     583           0 :                                 aType = grad;
     584             :                             }
     585           0 :                             break;
     586             :                         }
     587             :                         case sal_Unicode('r') :
     588             :                         case sal_Unicode('R') :
     589             :                         {
     590           0 :                             if(rCandidate.matchIgnoreAsciiCase(aStrRad, nPos))
     591             :                             {
     592             :                                 // angle in radians
     593           0 :                                 nPos += aStrRad.getLength();
     594           0 :                                 aType = rad;
     595             :                             }
     596           0 :                             break;
     597             :                         }
     598             :                     }
     599             :                 }
     600             : 
     601             :                 // convert to radians
     602           0 :                 if(deg == aType)
     603             :                 {
     604           0 :                     fAngle *= F_PI / 180.0;
     605             :                 }
     606           0 :                 else if(grad == aType)
     607             :                 {
     608             :                     // looks like 100 grad is 90 degrees
     609           0 :                     fAngle *= F_PI / 200.0;
     610             :                 }
     611             : 
     612           0 :                 return true;
     613             :             }
     614             : 
     615           0 :             return false;
     616             :         }
     617             : 
     618       30792 :         sal_Int32 read_hex(const sal_Unicode& rChar)
     619             :         {
     620       30792 :             if(rChar >= '0' && rChar <= '9')
     621             :             {
     622       16405 :                 return sal_Int32(rChar - sal_Unicode('0'));
     623             :             }
     624       14387 :             else if(rChar >= 'A' && rChar <= 'F')
     625             :             {
     626       14206 :                 return 10 + sal_Int32(rChar - sal_Unicode('A'));
     627             :             }
     628         181 :             else if(rChar >= 'a' && rChar <= 'f')
     629             :             {
     630         181 :                 return 10 + sal_Int32(rChar - sal_Unicode('a'));
     631             :             }
     632             :             else
     633             :             {
     634             :                 // error
     635           0 :                 return 0;
     636             :             }
     637             :         }
     638             : 
     639        1388 :         bool match_colorKeyword(basegfx::BColor& rColor, const OUString& rName)
     640             :         {
     641             :             typedef boost::unordered_map< OUString, Color,
     642             :                       OUStringHash,
     643             :                       ::std::equal_to< OUString >
     644             :                       > ColorTokenMapper;
     645             :             typedef std::pair< OUString, Color > ColorTokenValueType;
     646        1388 :             ColorTokenMapper aColorTokenMapperList;
     647             : 
     648        1388 :             if(aColorTokenMapperList.empty())
     649             :             {
     650        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("aliceblue"), Color(240, 248, 255)));
     651        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("antiquewhite"), Color(250, 235, 215)));
     652        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("aqua"), Color( 0, 255, 255)));
     653        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("aquamarine"), Color(127, 255, 212)));
     654        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("azure"), Color(240, 255, 255)));
     655        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("beige"), Color(245, 245, 220)));
     656        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("bisque"), Color(255, 228, 196)));
     657        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("black"), Color( 0, 0, 0)));
     658        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("blanchedalmond"), Color(255, 235, 205)));
     659        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("blue"), Color( 0, 0, 255)));
     660        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("blueviolet"), Color(138, 43, 226)));
     661        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("brown"), Color(165, 42, 42)));
     662        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("burlywood"), Color(222, 184, 135)));
     663        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("cadetblue"), Color( 95, 158, 160)));
     664        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("chartreuse"), Color(127, 255, 0)));
     665        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("chocolate"), Color(210, 105, 30)));
     666        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("coral"), Color(255, 127, 80)));
     667        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("cornflowerblue"), Color(100, 149, 237)));
     668        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("cornsilk"), Color(255, 248, 220)));
     669        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("crimson"), Color(220, 20, 60)));
     670        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("cyan"), Color( 0, 255, 255)));
     671        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkblue"), Color( 0, 0, 139)));
     672        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkcyan"), Color( 0, 139, 139)));
     673        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkgoldenrod"), Color(184, 134, 11)));
     674        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkgray"), Color(169, 169, 169)));
     675        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkgreen"), Color( 0, 100, 0)));
     676        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkgrey"), Color(169, 169, 169)));
     677        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkkhaki"), Color(189, 183, 107)));
     678        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkmagenta"), Color(139, 0, 139)));
     679        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkolivegreen"), Color( 85, 107, 47)));
     680        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkorange"), Color(255, 140, 0)));
     681        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkorchid"), Color(153, 50, 204)));
     682        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkred"), Color(139, 0, 0)));
     683        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darksalmon"), Color(233, 150, 122)));
     684        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkseagreen"), Color(143, 188, 143)));
     685        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkslateblue"), Color( 72, 61, 139)));
     686        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkslategray"), Color( 47, 79, 79)));
     687        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkslategrey"), Color( 47, 79, 79)));
     688        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkturquoise"), Color( 0, 206, 209)));
     689        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("darkviolet"), Color(148, 0, 211)));
     690        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("deeppink"), Color(255, 20, 147)));
     691        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("deepskyblue"), Color( 0, 191, 255)));
     692        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("dimgray"), Color(105, 105, 105)));
     693        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("dimgrey"), Color(105, 105, 105)));
     694        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("dodgerblue"), Color( 30, 144, 255)));
     695        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("firebrick"), Color(178, 34, 34)));
     696        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("floralwhite"), Color(255, 250, 240)));
     697        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("forestgreen"), Color( 34, 139, 34)));
     698        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("fuchsia"), Color(255, 0, 255)));
     699        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("gainsboro"), Color(220, 220, 220)));
     700        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("ghostwhite"), Color(248, 248, 255)));
     701        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("gold"), Color(255, 215, 0)));
     702        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("goldenrod"), Color(218, 165, 32)));
     703        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("gray"), Color(128, 128, 128)));
     704        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("grey"), Color(128, 128, 128)));
     705        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("green"), Color(0, 128, 0)));
     706        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("greenyellow"), Color(173, 255, 47)));
     707        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("honeydew"), Color(240, 255, 240)));
     708        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("hotpink"), Color(255, 105, 180)));
     709        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("indianred"), Color(205, 92, 92)));
     710        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("indigo"), Color( 75, 0, 130)));
     711        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("ivory"), Color(255, 255, 240)));
     712        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("khaki"), Color(240, 230, 140)));
     713        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lavender"), Color(230, 230, 250)));
     714        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lavenderblush"), Color(255, 240, 245)));
     715        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lawngreen"), Color(124, 252, 0)));
     716        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lemonchiffon"), Color(255, 250, 205)));
     717        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightblue"), Color(173, 216, 230)));
     718        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightcoral"), Color(240, 128, 128)));
     719        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightcyan"), Color(224, 255, 255)));
     720        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightgoldenrodyellow"), Color(250, 250, 210)));
     721        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightgray"), Color(211, 211, 211)));
     722        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightgreen"), Color(144, 238, 144)));
     723        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightgrey"), Color(211, 211, 211)));
     724        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightpink"), Color(255, 182, 193)));
     725        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightsalmon"), Color(255, 160, 122)));
     726        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightseagreen"), Color( 32, 178, 170)));
     727        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightskyblue"), Color(135, 206, 250)));
     728        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightslategray"), Color(119, 136, 153)));
     729        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightslategrey"), Color(119, 136, 153)));
     730        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightsteelblue"), Color(176, 196, 222)));
     731        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lightyellow"), Color(255, 255, 224)));
     732        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("lime"), Color( 0, 255, 0)));
     733        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("limegreen"), Color( 50, 205, 50)));
     734        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("linen"), Color(250, 240, 230)));
     735        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("magenta"), Color(255, 0, 255)));
     736        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("maroon"), Color(128, 0, 0)));
     737        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumaquamarine"), Color(102, 205, 170)));
     738        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumblue"), Color( 0, 0, 205)));
     739        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumorchid"), Color(186, 85, 211)));
     740        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumpurple"), Color(147, 112, 219)));
     741        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumseagreen"), Color( 60, 179, 113)));
     742        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumslateblue"), Color(123, 104, 238)));
     743        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumspringgreen"), Color( 0, 250, 154)));
     744        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumturquoise"), Color( 72, 209, 204)));
     745        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mediumvioletred"), Color(199, 21, 133)));
     746        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("midnightblue"), Color( 25, 25, 112)));
     747        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mintcream"), Color(245, 255, 250)));
     748        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("mistyrose"), Color(255, 228, 225)));
     749        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("moccasin"), Color(255, 228, 181)));
     750        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("navajowhite"), Color(255, 222, 173)));
     751        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("navy"), Color( 0, 0, 128)));
     752        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("oldlace"), Color(253, 245, 230)));
     753        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("olive"), Color(128, 128, 0)));
     754        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("olivedrab"), Color(107, 142, 35)));
     755        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("orange"), Color(255, 165, 0)));
     756        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("orangered"), Color(255, 69, 0)));
     757        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("orchid"), Color(218, 112, 214)));
     758        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("palegoldenrod"), Color(238, 232, 170)));
     759        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("palegreen"), Color(152, 251, 152)));
     760        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("paleturquoise"), Color(175, 238, 238)));
     761        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("palevioletred"), Color(219, 112, 147)));
     762        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("papayawhip"), Color(255, 239, 213)));
     763        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("peachpuff"), Color(255, 218, 185)));
     764        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("peru"), Color(205, 133, 63)));
     765        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("pink"), Color(255, 192, 203)));
     766        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("plum"), Color(221, 160, 221)));
     767        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("powderblue"), Color(176, 224, 230)));
     768        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("purple"), Color(128, 0, 128)));
     769        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("red"), Color(255, 0, 0)));
     770        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("rosybrown"), Color(188, 143, 143)));
     771        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("royalblue"), Color( 65, 105, 225)));
     772        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("saddlebrown"), Color(139, 69, 19)));
     773        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("salmon"), Color(250, 128, 114)));
     774        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("sandybrown"), Color(244, 164, 96)));
     775        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("seagreen"), Color( 46, 139, 87)));
     776        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("seashell"), Color(255, 245, 238)));
     777        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("sienna"), Color(160, 82, 45)));
     778        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("silver"), Color(192, 192, 192)));
     779        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("skyblue"), Color(135, 206, 235)));
     780        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("slateblue"), Color(106, 90, 205)));
     781        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("slategray"), Color(112, 128, 144)));
     782        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("slategrey"), Color(112, 128, 144)));
     783        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("snow"), Color(255, 250, 250)));
     784        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("springgreen"), Color( 0, 255, 127)));
     785        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("steelblue"), Color( 70, 130, 180)));
     786        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("tan"), Color(210, 180, 140)));
     787        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("teal"), Color( 0, 128, 128)));
     788        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("thistle"), Color(216, 191, 216)));
     789        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("tomato"), Color(255, 99, 71)));
     790        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("turquoise"), Color( 64, 224, 208)));
     791        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("violet"), Color(238, 130, 238)));
     792        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("wheat"), Color(245, 222, 179)));
     793        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("white"), Color(255, 255, 255)));
     794        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("whitesmoke"), Color(245, 245, 245)));
     795        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("yellow"), Color(255, 255, 0)));
     796        1388 :                 aColorTokenMapperList.insert(ColorTokenValueType(OUString("yellowgreen"), Color(154, 205, 50)));
     797             :             }
     798             : 
     799        1388 :             const ColorTokenMapper::const_iterator aResult(aColorTokenMapperList.find(rName));
     800             : 
     801        1388 :             if(aResult == aColorTokenMapperList.end())
     802             :             {
     803        1388 :                 return false;
     804             :             }
     805             :             else
     806             :             {
     807           0 :                 rColor = aResult->second.getBColor();
     808           0 :                 return true;
     809        1388 :             }
     810             :         }
     811             : 
     812        6520 :         bool read_color(const OUString& rCandidate, basegfx::BColor& rColor)
     813             :         {
     814        6520 :             const sal_Int32 nLen(rCandidate.getLength());
     815             : 
     816        6520 :             if(nLen)
     817             :             {
     818        6520 :                 const sal_Unicode aChar(rCandidate[0]);
     819        6520 :                 const double fFactor(1.0 / 255.0);
     820             : 
     821        6520 :                 if(aChar == '#')
     822             :                 {
     823             :                     // hex definition
     824        5132 :                     OUStringBuffer aNum;
     825        5132 :                     sal_Int32 nPos(1);
     826             : 
     827        5132 :                     copyHex(rCandidate, nPos, aNum, nLen);
     828        5132 :                     const sal_Int32 nLength(aNum.getLength());
     829             : 
     830        5132 :                     if(3 == nLength)
     831             :                     {
     832           0 :                         const sal_Int32 nR(read_hex(aNum[0]));
     833           0 :                         const sal_Int32 nG(read_hex(aNum[1]));
     834           0 :                         const sal_Int32 nB(read_hex(aNum[2]));
     835             : 
     836           0 :                         rColor.setRed((nR | (nR << 4)) * fFactor);
     837           0 :                         rColor.setGreen((nG | (nG << 4)) * fFactor);
     838           0 :                         rColor.setBlue((nB | (nB << 4)) * fFactor);
     839             : 
     840           0 :                         return true;
     841             :                     }
     842        5132 :                     else if(6 == nLength)
     843             :                     {
     844        5132 :                         const sal_Int32 nR1(read_hex(aNum[0]));
     845        5132 :                         const sal_Int32 nR2(read_hex(aNum[1]));
     846        5132 :                         const sal_Int32 nG1(read_hex(aNum[2]));
     847        5132 :                         const sal_Int32 nG2(read_hex(aNum[3]));
     848        5132 :                         const sal_Int32 nB1(read_hex(aNum[4]));
     849        5132 :                         const sal_Int32 nB2(read_hex(aNum[5]));
     850             : 
     851        5132 :                         rColor.setRed((nR2 | (nR1 << 4)) * fFactor);
     852        5132 :                         rColor.setGreen((nG2 | (nG1 << 4)) * fFactor);
     853        5132 :                         rColor.setBlue((nB2 | (nB1 << 4)) * fFactor);
     854             : 
     855        5132 :                         return true;
     856           0 :                     }
     857             :                 }
     858             :                 else
     859             :                 {
     860        1388 :                     static OUString aStrRgb("rgb");
     861             : 
     862        1388 :                     if(rCandidate.matchIgnoreAsciiCase(aStrRgb, 0))
     863             :                     {
     864             :                         // rgb definition
     865           0 :                         sal_Int32 nPos(aStrRgb.getLength());
     866           0 :                         skip_char(rCandidate, ' ', '(', nPos, nLen);
     867           0 :                         double fR(0.0);
     868             : 
     869           0 :                         if(readNumber(rCandidate, nPos, fR, nLen))
     870             :                         {
     871           0 :                             skip_char(rCandidate, ' ', nPos, nLen);
     872             : 
     873           0 :                             if(nPos < nLen)
     874             :                             {
     875           0 :                                 const sal_Unicode aPercentChar(rCandidate[nPos]);
     876           0 :                                 const bool bIsPercent('%' == aPercentChar);
     877           0 :                                 double fG(0.0);
     878             : 
     879           0 :                                 if(bIsPercent)
     880             :                                 {
     881           0 :                                     skip_char(rCandidate, '%', nPos, nLen);
     882             :                                 }
     883             : 
     884           0 :                                 skip_char(rCandidate, ' ', ',', nPos, nLen);
     885             : 
     886           0 :                                 if(readNumber(rCandidate, nPos, fG, nLen))
     887             :                                 {
     888           0 :                                     double fB(0.0);
     889             : 
     890           0 :                                     if(bIsPercent)
     891             :                                     {
     892           0 :                                         skip_char(rCandidate, '%', nPos, nLen);
     893             :                                     }
     894             : 
     895           0 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
     896             : 
     897           0 :                                     if(readNumber(rCandidate, nPos, fB, nLen))
     898             :                                     {
     899           0 :                                         const double fFac(bIsPercent ? 0.01 : fFactor);
     900             : 
     901           0 :                                         rColor.setRed(fR * fFac);
     902           0 :                                         rColor.setGreen(fG * fFac);
     903           0 :                                         rColor.setBlue(fB * fFac);
     904             : 
     905           0 :                                         if(bIsPercent)
     906             :                                         {
     907           0 :                                             skip_char(rCandidate, '%', nPos, nLen);
     908             :                                         }
     909             : 
     910           0 :                                         skip_char(rCandidate, ' ', ')', nPos, nLen);
     911           0 :                                         return true;
     912             :                                     }
     913             :                                 }
     914             :                             }
     915             :                         }
     916             :                     }
     917             :                     else
     918             :                     {
     919             :                         // color keyword
     920        1388 :                         if(match_colorKeyword(rColor, rCandidate))
     921             :                         {
     922           0 :                             return true;
     923             :                         }
     924             :                     }
     925             :                 }
     926             :             }
     927             : 
     928        1388 :             return false;
     929             :         }
     930             : 
     931         292 :         basegfx::B2DRange readViewBox(const OUString& rCandidate, InfoProvider& rInfoProvider)
     932             :         {
     933         292 :             const sal_Int32 nLen(rCandidate.getLength());
     934             : 
     935         292 :             if(nLen)
     936             :             {
     937         292 :                 sal_Int32 nPos(0);
     938         292 :                 SvgNumber aMinX;
     939         292 :                 skip_char(rCandidate, ' ', ',', nPos, nLen);
     940             : 
     941         292 :                 if(readNumberAndUnit(rCandidate, nPos, aMinX, nLen))
     942             :                 {
     943         292 :                     SvgNumber aMinY;
     944         292 :                     skip_char(rCandidate, ' ', ',', nPos, nLen);
     945             : 
     946         292 :                     if(readNumberAndUnit(rCandidate, nPos, aMinY, nLen))
     947             :                     {
     948         292 :                         SvgNumber aWidth;
     949         292 :                         skip_char(rCandidate, ' ', ',', nPos, nLen);
     950             : 
     951         292 :                         if(readNumberAndUnit(rCandidate, nPos, aWidth, nLen))
     952             :                         {
     953         292 :                             SvgNumber aHeight;
     954         292 :                             skip_char(rCandidate, ' ', ',', nPos, nLen);
     955             : 
     956         292 :                             if(readNumberAndUnit(rCandidate, nPos, aHeight, nLen))
     957             :                             {
     958         292 :                                 double fX(aMinX.solve(rInfoProvider, xcoordinate));
     959         292 :                                 double fY(aMinY.solve(rInfoProvider, ycoordinate));
     960         292 :                                 double fW(aWidth.solve(rInfoProvider,xcoordinate));
     961         292 :                                 double fH(aHeight.solve(rInfoProvider,ycoordinate));
     962         292 :                                 return basegfx::B2DRange(fX,fY,fX+fW,fY+fH);
     963             :                             }
     964             :                         }
     965             :                     }
     966             :                 }
     967             :             }
     968             : 
     969           0 :             return basegfx::B2DRange();
     970             :         }
     971             : 
     972         553 :         basegfx::B2DHomMatrix readTransform(const OUString& rCandidate, InfoProvider& rInfoProvider)
     973             :         {
     974         553 :             basegfx::B2DHomMatrix aMatrix;
     975         553 :             const sal_Int32 nLen(rCandidate.getLength());
     976             : 
     977         553 :             if(nLen)
     978             :             {
     979         553 :                 sal_Int32 nPos(0);
     980         553 :                 skip_char(rCandidate, ' ', ',', nPos, nLen);
     981             : 
     982        1659 :                 while(nPos < nLen)
     983             :                 {
     984         553 :                     const sal_Unicode aChar(rCandidate[nPos]);
     985         553 :                     const sal_Int32 nInitPos(nPos);
     986         553 :                     static OUString aStrMatrix("matrix");
     987         553 :                     static OUString aStrTranslate("translate");
     988         553 :                     static OUString aStrScale("scale");
     989         553 :                     static OUString aStrRotate("rotate");
     990         553 :                     static OUString aStrSkewX("skewX");
     991         553 :                     static OUString aStrSkewY("skewY");
     992             : 
     993         553 :                     switch(aChar)
     994             :                     {
     995             :                         case sal_Unicode('m') :
     996             :                         {
     997         538 :                             if(rCandidate.match(aStrMatrix, nPos))
     998             :                             {
     999             :                                 // matrix element
    1000         538 :                                 nPos += aStrMatrix.getLength();
    1001         538 :                                 skip_char(rCandidate, ' ', '(', nPos, nLen);
    1002         538 :                                 SvgNumber aVal;
    1003         538 :                                 basegfx::B2DHomMatrix aNew;
    1004             : 
    1005         538 :                                 if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
    1006             :                                 {
    1007         538 :                                     aNew.set(0, 0, aVal.solve(rInfoProvider)); // Element A
    1008         538 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1009             : 
    1010         538 :                                     if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
    1011             :                                     {
    1012         538 :                                         aNew.set(1, 0, aVal.solve(rInfoProvider)); // Element B
    1013         538 :                                         skip_char(rCandidate, ' ', ',', nPos, nLen);
    1014             : 
    1015         538 :                                         if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
    1016             :                                         {
    1017         538 :                                             aNew.set(0, 1, aVal.solve(rInfoProvider)); // Element C
    1018         538 :                                             skip_char(rCandidate, ' ', ',', nPos, nLen);
    1019             : 
    1020         538 :                                             if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
    1021             :                                             {
    1022         538 :                                                 aNew.set(1, 1, aVal.solve(rInfoProvider)); // Element D
    1023         538 :                                                 skip_char(rCandidate, ' ', ',', nPos, nLen);
    1024             : 
    1025         538 :                                                 if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
    1026             :                                                 {
    1027         538 :                                                     aNew.set(0, 2, aVal.solve(rInfoProvider, xcoordinate)); // Element E
    1028         538 :                                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1029             : 
    1030         538 :                                                     if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
    1031             :                                                     {
    1032         538 :                                                         aNew.set(1, 2, aVal.solve(rInfoProvider, ycoordinate)); // Element F
    1033         538 :                                                         skip_char(rCandidate, ' ', ')', nPos, nLen);
    1034         538 :                                                         skip_char(rCandidate, ' ', ',', nPos, nLen);
    1035             : 
    1036             :                                                         // caution: String is evaluated from left to right, but matrix multiplication
    1037             :                                                         // in SVG is right to left, so put the new transformation before the current
    1038             :                                                         // one by multiplicating from the right side
    1039         538 :                                                         aMatrix = aMatrix * aNew;
    1040             :                                                     }
    1041             :                                                 }
    1042             :                                             }
    1043             :                                         }
    1044             :                                     }
    1045         538 :                                 }
    1046             :                             }
    1047         538 :                             break;
    1048             :                         }
    1049             :                         case sal_Unicode('t') :
    1050             :                         {
    1051          15 :                             if(rCandidate.match(aStrTranslate, nPos))
    1052             :                             {
    1053             :                                 // translate element
    1054          15 :                                 nPos += aStrTranslate.getLength();
    1055          15 :                                 skip_char(rCandidate, ' ', '(', nPos, nLen);
    1056          15 :                                 SvgNumber aTransX;
    1057             : 
    1058          15 :                                 if(readNumberAndUnit(rCandidate, nPos, aTransX, nLen))
    1059             :                                 {
    1060          15 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1061          15 :                                     SvgNumber aTransY;
    1062          15 :                                     readNumberAndUnit(rCandidate, nPos, aTransY, nLen);
    1063          15 :                                     skip_char(rCandidate, ' ', ')', nPos, nLen);
    1064          15 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1065             : 
    1066          30 :                                     aMatrix = aMatrix * basegfx::tools::createTranslateB2DHomMatrix(
    1067             :                                         aTransX.solve(rInfoProvider, xcoordinate),
    1068          15 :                                         aTransY.solve(rInfoProvider, ycoordinate));
    1069             :                                 }
    1070             :                             }
    1071          15 :                             break;
    1072             :                         }
    1073             :                         case sal_Unicode('s') :
    1074             :                         {
    1075           0 :                             if(rCandidate.match(aStrScale, nPos))
    1076             :                             {
    1077             :                                 // scale element
    1078           0 :                                 nPos += aStrScale.getLength();
    1079           0 :                                 skip_char(rCandidate, ' ', '(', nPos, nLen);
    1080           0 :                                 SvgNumber aScaleX;
    1081             : 
    1082           0 :                                 if(readNumberAndUnit(rCandidate, nPos, aScaleX, nLen))
    1083             :                                 {
    1084           0 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1085           0 :                                     SvgNumber aScaleY(aScaleX);
    1086           0 :                                     readNumberAndUnit(rCandidate, nPos, aScaleY, nLen);
    1087           0 :                                     skip_char(rCandidate, ' ', ')', nPos, nLen);
    1088           0 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1089             : 
    1090           0 :                                     aMatrix = aMatrix * basegfx::tools::createScaleB2DHomMatrix(
    1091             :                                         aScaleX.solve(rInfoProvider),
    1092           0 :                                         aScaleY.solve(rInfoProvider));
    1093             :                                 }
    1094             :                             }
    1095           0 :                             else if(rCandidate.match(aStrSkewX, nPos))
    1096             :                             {
    1097             :                                 // skewx element
    1098           0 :                                 nPos += aStrSkewX.getLength();
    1099           0 :                                 skip_char(rCandidate, ' ', '(', nPos, nLen);
    1100           0 :                                 double fSkewX(0.0);
    1101             : 
    1102           0 :                                 if(readAngle(rCandidate, nPos, fSkewX, nLen))
    1103             :                                 {
    1104           0 :                                     skip_char(rCandidate, ' ', ')', nPos, nLen);
    1105           0 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1106             : 
    1107           0 :                                     aMatrix = aMatrix * basegfx::tools::createShearXB2DHomMatrix(tan(fSkewX));
    1108             :                                 }
    1109             :                             }
    1110           0 :                             else if(rCandidate.match(aStrSkewY, nPos))
    1111             :                             {
    1112             :                                 // skewy element
    1113           0 :                                 nPos += aStrSkewY.getLength();
    1114           0 :                                 skip_char(rCandidate, ' ', '(', nPos, nLen);
    1115           0 :                                 double fSkewY(0.0);
    1116             : 
    1117           0 :                                 if(readAngle(rCandidate, nPos, fSkewY, nLen))
    1118             :                                 {
    1119           0 :                                     skip_char(rCandidate, ' ', ')', nPos, nLen);
    1120           0 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1121             : 
    1122           0 :                                     aMatrix = aMatrix * basegfx::tools::createShearYB2DHomMatrix(tan(fSkewY));
    1123             :                                 }
    1124             :                             }
    1125           0 :                             break;
    1126             :                         }
    1127             :                         case sal_Unicode('r') :
    1128             :                         {
    1129           0 :                             if(rCandidate.match(aStrRotate, nPos))
    1130             :                             {
    1131             :                                 // rotate element
    1132           0 :                                 nPos += aStrRotate.getLength();
    1133           0 :                                 skip_char(rCandidate, ' ', '(', nPos, nLen);
    1134           0 :                                 double fAngle(0.0);
    1135             : 
    1136           0 :                                 if(readAngle(rCandidate, nPos, fAngle, nLen))
    1137             :                                 {
    1138           0 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1139           0 :                                     SvgNumber aX;
    1140           0 :                                     readNumberAndUnit(rCandidate, nPos, aX, nLen);
    1141           0 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1142           0 :                                     SvgNumber aY;
    1143           0 :                                     readNumberAndUnit(rCandidate, nPos, aY, nLen);
    1144           0 :                                     skip_char(rCandidate, ' ', ')', nPos, nLen);
    1145           0 :                                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1146             : 
    1147           0 :                                     const double fX(aX.isSet() ? aX.solve(rInfoProvider, xcoordinate) : 0.0);
    1148           0 :                                     const double fY(aY.isSet() ? aY.solve(rInfoProvider, ycoordinate) : 0.0);
    1149             : 
    1150           0 :                                     if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
    1151             :                                     {
    1152             :                                         // rotate around point
    1153           0 :                                         aMatrix = aMatrix * basegfx::tools::createRotateAroundPoint(fX, fY, fAngle);
    1154             :                                     }
    1155             :                                     else
    1156             :                                     {
    1157             :                                         // rotate
    1158           0 :                                         aMatrix = aMatrix * basegfx::tools::createRotateB2DHomMatrix(fAngle);
    1159             :                                     }
    1160             :                                 }
    1161             :                             }
    1162           0 :                             break;
    1163             :                         }
    1164             :                     }
    1165             : 
    1166         553 :                     if(nInitPos == nPos)
    1167             :                     {
    1168             :                         OSL_ENSURE(false, "Could not interpret on current position (!)");
    1169           0 :                         nPos++;
    1170             :                     }
    1171             :                 }
    1172             :             }
    1173             : 
    1174         553 :             return aMatrix;
    1175             :         }
    1176             : 
    1177       12975 :         bool readSingleNumber(const OUString& rCandidate, SvgNumber& aNum)
    1178             :         {
    1179       12975 :             const sal_Int32 nLen(rCandidate.getLength());
    1180       12975 :             sal_Int32 nPos(0);
    1181             : 
    1182       12975 :             return readNumberAndUnit(rCandidate, nPos, aNum, nLen);
    1183             :         }
    1184             : 
    1185        1610 :         bool readLocalUrl(const OUString& rCandidate, OUString& rURL)
    1186             :         {
    1187        1610 :             static OUString aStrUrl("url");
    1188             : 
    1189        1610 :             if(rCandidate.startsWith(aStrUrl))
    1190             :             {
    1191        1610 :                 const sal_Int32 nLen(rCandidate.getLength());
    1192        1610 :                 sal_Int32 nPos(aStrUrl.getLength());
    1193             : 
    1194        1610 :                 skip_char(rCandidate, '(', '#', nPos, nLen);
    1195        1610 :                 OUStringBuffer aTokenValue;
    1196        1610 :                 copyToLimiter(rCandidate, ')', nPos, aTokenValue, nLen);
    1197        1610 :                 rURL = aTokenValue.makeStringAndClear();
    1198             : 
    1199        1610 :                 return true;
    1200             :             }
    1201             : 
    1202           0 :             return false;
    1203             :         }
    1204             : 
    1205        6520 :         bool readSvgPaint(const OUString& rCandidate, SvgPaint& rSvgPaint, OUString& rURL)
    1206             :         {
    1207        6520 :             if( !rCandidate.isEmpty() )
    1208             :             {
    1209        6520 :                 basegfx::BColor aColor;
    1210             : 
    1211        6520 :                 if(read_color(rCandidate, aColor))
    1212             :                 {
    1213        5132 :                     rSvgPaint = SvgPaint(aColor, true, true);
    1214        5132 :                     return true;
    1215             :                 }
    1216             :                 else
    1217             :                 {
    1218        1388 :                     if(rCandidate.startsWith("none"))
    1219             :                     {
    1220         105 :                         rSvgPaint = SvgPaint(aColor, true, false, false);
    1221         105 :                         return true;
    1222             :                     }
    1223        1283 :                     else if(readLocalUrl(rCandidate, rURL))
    1224             :                     {
    1225             :                         /// Url is copied to rURL, but needs to be solved outside this helper
    1226        1283 :                         return false;
    1227             :                     }
    1228           0 :                     else if(rCandidate.startsWith("currentColor"))
    1229             :                     {
    1230           0 :                         rSvgPaint = SvgPaint(aColor, true, true, true);
    1231           0 :                         return true;
    1232             :                     }
    1233           0 :                 }
    1234             :             }
    1235             : 
    1236           0 :             return false;
    1237             :         }
    1238             : 
    1239          15 :         bool readSvgNumberVector(const OUString& rCandidate, SvgNumberVector& rSvgNumberVector)
    1240             :         {
    1241          15 :             const sal_Int32 nLen(rCandidate.getLength());
    1242          15 :             rSvgNumberVector.clear();
    1243             : 
    1244          15 :             if(nLen)
    1245             :             {
    1246          15 :                 sal_Int32 nPos(0);
    1247          15 :                 SvgNumber aNum;
    1248          15 :                 skip_char(rCandidate, ' ', ',', nPos, nLen);
    1249             : 
    1250          56 :                 while(readNumberAndUnit(rCandidate, nPos, aNum, nLen))
    1251             :                 {
    1252          26 :                     rSvgNumberVector.push_back(aNum);
    1253          26 :                     skip_char(rCandidate, ' ', ',', nPos, nLen);
    1254             :                 }
    1255             : 
    1256          15 :                 return !rSvgNumberVector.empty();
    1257             :             }
    1258             : 
    1259           0 :             return false;
    1260             :         }
    1261             : 
    1262           0 :         SvgAspectRatio readSvgAspectRatio(const OUString& rCandidate)
    1263             :         {
    1264           0 :             const sal_Int32 nLen(rCandidate.getLength());
    1265             : 
    1266           0 :             if(nLen)
    1267             :             {
    1268           0 :                 sal_Int32 nPos(0);
    1269           0 :                 SvgAlign aSvgAlign(Align_xMidYMid);
    1270           0 :                 bool bDefer(false);
    1271           0 :                 bool bMeetOrSlice(true);
    1272           0 :                 bool bChanged(false);
    1273             : 
    1274           0 :                 while(nPos < nLen)
    1275             :                 {
    1276           0 :                     const sal_Int32 nInitPos(nPos);
    1277           0 :                     skip_char(rCandidate, ' ', nPos, nLen);
    1278           0 :                     OUStringBuffer aTokenName;
    1279           0 :                     copyString(rCandidate, nPos, aTokenName, nLen);
    1280             : 
    1281           0 :                     if(!aTokenName.isEmpty())
    1282             :                     {
    1283           0 :                         switch(StrToSVGToken(aTokenName.makeStringAndClear()))
    1284             :                         {
    1285             :                             case SVGTokenDefer:
    1286             :                             {
    1287           0 :                                 bDefer = true;
    1288           0 :                                 bChanged = true;
    1289           0 :                                 break;
    1290             :                             }
    1291             :                             case SVGTokenNone:
    1292             :                             {
    1293           0 :                                 aSvgAlign = Align_none;
    1294           0 :                                 bChanged = true;
    1295           0 :                                 break;
    1296             :                             }
    1297             :                             case SVGTokenXMinYMin:
    1298             :                             {
    1299           0 :                                 aSvgAlign = Align_xMinYMin;
    1300           0 :                                 bChanged = true;
    1301           0 :                                 break;
    1302             :                             }
    1303             :                             case SVGTokenXMidYMin:
    1304             :                             {
    1305           0 :                                 aSvgAlign = Align_xMidYMin;
    1306           0 :                                 bChanged = true;
    1307           0 :                                 break;
    1308             :                             }
    1309             :                             case SVGTokenXMaxYMin:
    1310             :                             {
    1311           0 :                                 aSvgAlign = Align_xMaxYMin;
    1312           0 :                                 bChanged = true;
    1313           0 :                                 break;
    1314             :                             }
    1315             :                             case SVGTokenXMinYMid:
    1316             :                             {
    1317           0 :                                 aSvgAlign = Align_xMinYMid;
    1318           0 :                                 bChanged = true;
    1319           0 :                                 break;
    1320             :                             }
    1321             :                             case SVGTokenXMidYMid:
    1322             :                             {
    1323           0 :                                 aSvgAlign = Align_xMidYMid;
    1324           0 :                                 bChanged = true;
    1325           0 :                                 break;
    1326             :                             }
    1327             :                             case SVGTokenXMaxYMid:
    1328             :                             {
    1329           0 :                                 aSvgAlign = Align_xMaxYMid;
    1330           0 :                                 bChanged = true;
    1331           0 :                                 break;
    1332             :                             }
    1333             :                             case SVGTokenXMinYMax:
    1334             :                             {
    1335           0 :                                 aSvgAlign = Align_xMinYMax;
    1336           0 :                                 bChanged = true;
    1337           0 :                                 break;
    1338             :                             }
    1339             :                             case SVGTokenXMidYMax:
    1340             :                             {
    1341           0 :                                 aSvgAlign = Align_xMidYMax;
    1342           0 :                                 bChanged = true;
    1343           0 :                                 break;
    1344             :                             }
    1345             :                             case SVGTokenXMaxYMax:
    1346             :                             {
    1347           0 :                                 aSvgAlign = Align_xMaxYMax;
    1348           0 :                                 bChanged = true;
    1349           0 :                                 break;
    1350             :                             }
    1351             :                             case SVGTokenMeet:
    1352             :                             {
    1353           0 :                                 bMeetOrSlice = true;
    1354           0 :                                 bChanged = true;
    1355           0 :                                 break;
    1356             :                             }
    1357             :                             case SVGTokenSlice:
    1358             :                             {
    1359           0 :                                 bMeetOrSlice = false;
    1360           0 :                                 bChanged = true;
    1361           0 :                                 break;
    1362             :                             }
    1363             :                             default:
    1364             :                             {
    1365           0 :                                 break;
    1366             :                             }
    1367             :                         }
    1368             :                     }
    1369             : 
    1370           0 :                     if(nInitPos == nPos)
    1371             :                     {
    1372             :                         OSL_ENSURE(false, "Could not interpret on current position (!)");
    1373           0 :                         nPos++;
    1374             :                     }
    1375           0 :                 }
    1376             : 
    1377           0 :                 if(bChanged)
    1378             :                 {
    1379           0 :                     return SvgAspectRatio(aSvgAlign, bDefer, bMeetOrSlice);
    1380             :                 }
    1381             :             }
    1382             : 
    1383           0 :             return SvgAspectRatio();
    1384             :         }
    1385             : 
    1386           0 :         bool readSvgStringVector(const OUString& rCandidate, SvgStringVector& rSvgStringVector)
    1387             :         {
    1388           0 :             rSvgStringVector.clear();
    1389           0 :             const sal_Int32 nLen(rCandidate.getLength());
    1390             : 
    1391           0 :             if(nLen)
    1392             :             {
    1393           0 :                 sal_Int32 nPos(0);
    1394           0 :                 OUStringBuffer aTokenValue;
    1395           0 :                 skip_char(rCandidate, ' ', ',', nPos, nLen);
    1396             : 
    1397           0 :                 while(nPos < nLen)
    1398             :                 {
    1399           0 :                     copyToLimiter(rCandidate, ',', nPos, aTokenValue, nLen);
    1400           0 :                     skip_char(rCandidate, ',', ' ', nPos, nLen);
    1401           0 :                     const OUString aString = aTokenValue.makeStringAndClear();
    1402             : 
    1403           0 :                     if(!aString.isEmpty())
    1404             :                     {
    1405           0 :                         rSvgStringVector.push_back(aString);
    1406             :                     }
    1407           0 :                 }
    1408             :             }
    1409             : 
    1410           0 :             return !rSvgStringVector.empty();
    1411             :         }
    1412             : 
    1413         238 :         void readImageLink(const OUString& rCandidate, OUString& rXLink, OUString& rUrl, OUString& rMimeType, OUString& rData)
    1414             :         {
    1415         238 :             rXLink = rUrl = rMimeType = rData = OUString();
    1416             : 
    1417         238 :             if('#' == rCandidate[0])
    1418             :             {
    1419             :                 // local link
    1420           0 :                 rXLink = rCandidate.copy(1);
    1421             :             }
    1422             :             else
    1423             :             {
    1424         238 :                 static OUString aStrData("data:");
    1425             : 
    1426         238 :                 if(rCandidate.match(aStrData, 0))
    1427             :                 {
    1428             :                     // embedded data
    1429         238 :                     sal_Int32 nPos(aStrData.getLength());
    1430         238 :                     sal_Int32 nLen(rCandidate.getLength());
    1431         238 :                     OUStringBuffer aBuffer;
    1432             : 
    1433             :                     // read mime type
    1434         238 :                     skip_char(rCandidate, ' ', nPos, nLen);
    1435         238 :                     copyToLimiter(rCandidate, ';', nPos, aBuffer, nLen);
    1436         238 :                     skip_char(rCandidate, ' ', ';', nPos, nLen);
    1437         238 :                     rMimeType = aBuffer.makeStringAndClear();
    1438             : 
    1439         238 :                     if(!rMimeType.isEmpty() && nPos < nLen)
    1440             :                     {
    1441         238 :                         static OUString aStrImage("image");
    1442             : 
    1443         238 :                         if(rMimeType.match(aStrImage, 0))
    1444             :                         {
    1445             :                             // image data
    1446         238 :                             OUString aData(rCandidate.copy(nPos));
    1447         238 :                             static OUString aStrBase64("base64");
    1448             : 
    1449         238 :                             if(aData.match(aStrBase64, 0))
    1450             :                             {
    1451             :                                 // base64 encoded
    1452         238 :                                 nPos = aStrBase64.getLength();
    1453         238 :                                 nLen = aData.getLength();
    1454             : 
    1455         238 :                                 skip_char(aData, ' ', ',', nPos, nLen);
    1456             : 
    1457         238 :                                 if(nPos < nLen)
    1458             :                                 {
    1459         238 :                                     rData = aData.copy(nPos);
    1460             :                                 }
    1461         238 :                             }
    1462             :                         }
    1463         238 :                     }
    1464             :                 }
    1465             :                 else
    1466             :                 {
    1467             :                     // Url (path and filename)
    1468           0 :                     rUrl = rCandidate;
    1469             :                 }
    1470             :             }
    1471         238 :         }
    1472             : 
    1473           0 :         OUString convert(const OUString& rCandidate, const sal_Unicode& rPattern, const sal_Unicode& rNew, bool bRemove)
    1474             :         {
    1475           0 :             const sal_Int32 nLen(rCandidate.getLength());
    1476             : 
    1477           0 :             if(nLen)
    1478             :             {
    1479           0 :                 sal_Int32 nPos(0);
    1480           0 :                 OUStringBuffer aBuffer;
    1481           0 :                 bool bChanged(false);
    1482             : 
    1483           0 :                 while(nPos < nLen)
    1484             :                 {
    1485           0 :                     const sal_Unicode aChar(rCandidate[nPos]);
    1486             : 
    1487           0 :                     if(rPattern == aChar)
    1488             :                     {
    1489           0 :                         bChanged = true;
    1490             : 
    1491           0 :                         if(!bRemove)
    1492             :                         {
    1493           0 :                             aBuffer.append(rNew);
    1494             :                         }
    1495             :                     }
    1496             :                     else
    1497             :                     {
    1498           0 :                         aBuffer.append(aChar);
    1499             :                     }
    1500             : 
    1501           0 :                     nPos++;
    1502             :                 }
    1503             : 
    1504           0 :                 if(bChanged)
    1505             :                 {
    1506           0 :                     return aBuffer.makeStringAndClear();
    1507           0 :                 }
    1508             :             }
    1509             : 
    1510           0 :             return rCandidate;
    1511             :         }
    1512             : 
    1513           0 :         OUString consolidateContiguosSpace(const OUString& rCandidate)
    1514             :         {
    1515           0 :             const sal_Int32 nLen(rCandidate.getLength());
    1516             : 
    1517           0 :             if(nLen)
    1518             :             {
    1519           0 :                 sal_Int32 nPos(0);
    1520           0 :                 OUStringBuffer aBuffer;
    1521           0 :                 bool bInsideSpace(false);
    1522           0 :                 const sal_Unicode aSpace(' ');
    1523             : 
    1524           0 :                 while(nPos < nLen)
    1525             :                 {
    1526           0 :                     const sal_Unicode aChar(rCandidate[nPos]);
    1527             : 
    1528           0 :                     if(aSpace == aChar)
    1529             :                     {
    1530           0 :                         bInsideSpace = true;
    1531             :                     }
    1532             :                     else
    1533             :                     {
    1534           0 :                         if(bInsideSpace)
    1535             :                         {
    1536           0 :                             bInsideSpace = false;
    1537           0 :                             aBuffer.append(aSpace);
    1538             :                         }
    1539             : 
    1540           0 :                         aBuffer.append(aChar);
    1541             :                     }
    1542             : 
    1543           0 :                     nPos++;
    1544             :                 }
    1545             : 
    1546           0 :                 if(bInsideSpace)
    1547             :                 {
    1548           0 :                     aBuffer.append(aSpace);
    1549             :                 }
    1550             : 
    1551           0 :                 if(aBuffer.getLength() != nLen)
    1552             :                 {
    1553           0 :                     return aBuffer.makeStringAndClear();
    1554           0 :                 }
    1555             :             }
    1556             : 
    1557           0 :             return rCandidate;
    1558             :         }
    1559             : 
    1560           0 :         OUString whiteSpaceHandlingDefault(const OUString& rCandidate)
    1561             :         {
    1562           0 :             const sal_Unicode aNewline('\n');
    1563           0 :             const sal_Unicode aTab('\t');
    1564           0 :             const sal_Unicode aSpace(' ');
    1565             : 
    1566             :             // remove all newline characters
    1567           0 :             OUString aRetval(convert(rCandidate, aNewline, aNewline, true));
    1568             : 
    1569             :             // convert tab to space
    1570           0 :             aRetval = convert(aRetval, aTab, aSpace, false);
    1571             : 
    1572             :             // strip of all leading and trailing spaces
    1573           0 :             aRetval = aRetval.trim();
    1574             : 
    1575             :             // consolidate contiguos space
    1576           0 :             aRetval = consolidateContiguosSpace(aRetval);
    1577             : 
    1578           0 :             return aRetval;
    1579             :         }
    1580             : 
    1581           0 :         OUString whiteSpaceHandlingPreserve(const OUString& rCandidate)
    1582             :         {
    1583           0 :             const sal_Unicode aNewline('\n');
    1584           0 :             const sal_Unicode aTab('\t');
    1585           0 :             const sal_Unicode aSpace(' ');
    1586             : 
    1587             :             // convert newline to space
    1588           0 :             OUString aRetval(convert(rCandidate, aNewline, aSpace, false));
    1589             : 
    1590             :             // convert tab to space
    1591           0 :             aRetval = convert(rCandidate, aTab, aSpace, false);
    1592             : 
    1593           0 :             return rCandidate;
    1594             :         }
    1595             : 
    1596          15 :         ::std::vector< double > solveSvgNumberVector(const SvgNumberVector& rInput, const InfoProvider& rInfoProvider, NumberType aNumberType)
    1597             :         {
    1598          15 :             ::std::vector< double > aRetval;
    1599             : 
    1600          15 :             if(!rInput.empty())
    1601             :             {
    1602          15 :                 const double nCount(rInput.size());
    1603          15 :                 aRetval.reserve(nCount);
    1604             : 
    1605          41 :                 for(sal_uInt32 a(0); a < nCount; a++)
    1606             :                 {
    1607          26 :                     aRetval.push_back(rInput[a].solve(rInfoProvider, aNumberType));
    1608             :                 }
    1609             :             }
    1610             : 
    1611          15 :             return aRetval;
    1612             :         }
    1613             : 
    1614             :     } // end of namespace svgreader
    1615          15 : } // end of namespace svgio
    1616             : 
    1617             : 
    1618             : // eof
    1619             : 
    1620             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10