LCOV - code coverage report
Current view: top level - svgio/source/svgreader - svgstyleattributes.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 411 994 41.3 %
Date: 2014-04-11 Functions: 34 56 60.7 %
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/svgstyleattributes.hxx>
      21             : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
      22             : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
      23             : #include <svgio/svgreader/svgnode.hxx>
      24             : #include <svgio/svgreader/svgdocument.hxx>
      25             : #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
      26             : #include <svgio/svgreader/svggradientnode.hxx>
      27             : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
      28             : #include <basegfx/vector/b2enums.hxx>
      29             : #include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
      30             : #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
      31             : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
      32             : #include <svgio/svgreader/svgclippathnode.hxx>
      33             : #include <svgio/svgreader/svgmasknode.hxx>
      34             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      35             : #include <svgio/svgreader/svgmarkernode.hxx>
      36             : #include <basegfx/curve/b2dcubicbezier.hxx>
      37             : #include <svgio/svgreader/svgpatternnode.hxx>
      38             : #include <drawinglayer/primitive2d/patternfillprimitive2d.hxx>
      39             : #include <basegfx/polygon/b2dpolygontools.hxx>
      40             : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
      41             : 
      42             : 
      43             : 
      44             : namespace svgio
      45             : {
      46             :     namespace svgreader
      47             :     {
      48         226 :         basegfx::B2DLineJoin StrokeLinejoinToB2DLineJoin(StrokeLinejoin aStrokeLinejoin)
      49             :         {
      50         226 :             if(StrokeLinejoin_round == aStrokeLinejoin)
      51             :             {
      52          30 :                 return basegfx::B2DLINEJOIN_ROUND;
      53             :             }
      54         196 :             else if(StrokeLinejoin_bevel == aStrokeLinejoin)
      55             :             {
      56           0 :                 return basegfx::B2DLINEJOIN_BEVEL;
      57             :             }
      58             : 
      59         196 :             return basegfx::B2DLINEJOIN_MITER;
      60             :         }
      61             : 
      62         226 :         com::sun::star::drawing::LineCap StrokeLinecapToDrawingLineCap(StrokeLinecap aStrokeLinecap)
      63             :         {
      64         226 :             switch(aStrokeLinecap)
      65             :             {
      66             :                 default: /* StrokeLinecap_notset, StrokeLinecap_butt */
      67             :                 {
      68         188 :                     return com::sun::star::drawing::LineCap_BUTT;
      69             :                 }
      70             :                 case StrokeLinecap_round:
      71             :                 {
      72          38 :                     return com::sun::star::drawing::LineCap_ROUND;
      73             :                 }
      74             :                 case StrokeLinecap_square:
      75             :                 {
      76           0 :                     return com::sun::star::drawing::LineCap_SQUARE;
      77             :                 }
      78             :             }
      79             :         }
      80             : 
      81           0 :         FontStretch getWider(FontStretch aSource)
      82             :         {
      83           0 :             switch(aSource)
      84             :             {
      85           0 :                 case FontStretch_ultra_condensed: aSource = FontStretch_extra_condensed; break;
      86           0 :                 case FontStretch_extra_condensed: aSource = FontStretch_condensed; break;
      87           0 :                 case FontStretch_condensed: aSource = FontStretch_semi_condensed; break;
      88           0 :                 case FontStretch_semi_condensed: aSource = FontStretch_normal; break;
      89           0 :                 case FontStretch_normal: aSource = FontStretch_semi_expanded; break;
      90           0 :                 case FontStretch_semi_expanded: aSource = FontStretch_expanded; break;
      91           0 :                 case FontStretch_expanded: aSource = FontStretch_extra_expanded; break;
      92           0 :                 case FontStretch_extra_expanded: aSource = FontStretch_ultra_expanded; break;
      93           0 :                 default: break;
      94             :             }
      95             : 
      96           0 :             return aSource;
      97             :         }
      98             : 
      99           0 :         FontStretch getNarrower(FontStretch aSource)
     100             :         {
     101           0 :             switch(aSource)
     102             :             {
     103           0 :                 case FontStretch_extra_condensed: aSource = FontStretch_ultra_condensed; break;
     104           0 :                 case FontStretch_condensed: aSource = FontStretch_extra_condensed; break;
     105           0 :                 case FontStretch_semi_condensed: aSource = FontStretch_condensed; break;
     106           0 :                 case FontStretch_normal: aSource = FontStretch_semi_condensed; break;
     107           0 :                 case FontStretch_semi_expanded: aSource = FontStretch_normal; break;
     108           0 :                 case FontStretch_expanded: aSource = FontStretch_semi_expanded; break;
     109           0 :                 case FontStretch_extra_expanded: aSource = FontStretch_expanded; break;
     110           0 :                 case FontStretch_ultra_expanded: aSource = FontStretch_extra_expanded; break;
     111           0 :                 default: break;
     112             :             }
     113             : 
     114           0 :             return aSource;
     115             :         }
     116             : 
     117           0 :         FontWeight getBolder(FontWeight aSource)
     118             :         {
     119           0 :             switch(aSource)
     120             :             {
     121           0 :                 case FontWeight_100: aSource = FontWeight_200; break;
     122           0 :                 case FontWeight_200: aSource = FontWeight_300; break;
     123           0 :                 case FontWeight_300: aSource = FontWeight_400; break;
     124           0 :                 case FontWeight_400: aSource = FontWeight_500; break;
     125           0 :                 case FontWeight_500: aSource = FontWeight_600; break;
     126           0 :                 case FontWeight_600: aSource = FontWeight_700; break;
     127           0 :                 case FontWeight_700: aSource = FontWeight_800; break;
     128           0 :                 case FontWeight_800: aSource = FontWeight_900; break;
     129           0 :                 default: break;
     130             :             }
     131             : 
     132           0 :             return aSource;
     133             :         }
     134             : 
     135           0 :         FontWeight getLighter(FontWeight aSource)
     136             :         {
     137           0 :             switch(aSource)
     138             :             {
     139           0 :                 case FontWeight_200: aSource = FontWeight_100; break;
     140           0 :                 case FontWeight_300: aSource = FontWeight_200; break;
     141           0 :                 case FontWeight_400: aSource = FontWeight_300; break;
     142           0 :                 case FontWeight_500: aSource = FontWeight_400; break;
     143           0 :                 case FontWeight_600: aSource = FontWeight_500; break;
     144           0 :                 case FontWeight_700: aSource = FontWeight_600; break;
     145           0 :                 case FontWeight_800: aSource = FontWeight_700; break;
     146           0 :                 case FontWeight_900: aSource = FontWeight_800; break;
     147           0 :                 default: break;
     148             :             }
     149             : 
     150           0 :             return aSource;
     151             :         }
     152             : 
     153           0 :         ::FontWeight getVclFontWeight(FontWeight aSource)
     154             :         {
     155           0 :             ::FontWeight nRetval(WEIGHT_NORMAL);
     156             : 
     157           0 :             switch(aSource)
     158             :             {
     159           0 :                 case FontWeight_100: nRetval = WEIGHT_ULTRALIGHT; break;
     160           0 :                 case FontWeight_200: nRetval = WEIGHT_LIGHT; break;
     161           0 :                 case FontWeight_300: nRetval = WEIGHT_SEMILIGHT; break;
     162           0 :                 case FontWeight_400: nRetval = WEIGHT_NORMAL; break;
     163           0 :                 case FontWeight_500: nRetval = WEIGHT_MEDIUM; break;
     164           0 :                 case FontWeight_600: nRetval = WEIGHT_SEMIBOLD; break;
     165           0 :                 case FontWeight_700: nRetval = WEIGHT_BOLD; break;
     166           0 :                 case FontWeight_800: nRetval = WEIGHT_ULTRABOLD; break;
     167           0 :                 case FontWeight_900: nRetval = WEIGHT_BLACK; break;
     168           0 :                 default: break;
     169             :             }
     170             : 
     171           0 :             return nRetval;
     172             :         }
     173             : 
     174        3566 :         void SvgStyleAttributes::readStyle(const OUString& rCandidate)
     175             :         {
     176        3566 :             const sal_Int32 nLen(rCandidate.getLength());
     177        3566 :             sal_Int32 nPos(0);
     178             : 
     179       10749 :             while(nPos < nLen)
     180             :             {
     181        3617 :                 const sal_Int32 nInitPos(nPos);
     182        3617 :                 skip_char(rCandidate, ' ', nPos, nLen);
     183        3617 :                 OUStringBuffer aTokenName;
     184        3617 :                 copyString(rCandidate, nPos, aTokenName, nLen);
     185             : 
     186        3617 :                 if(!aTokenName.isEmpty())
     187             :                 {
     188        3617 :                     skip_char(rCandidate, ' ', ':', nPos, nLen);
     189        3617 :                     OUStringBuffer aTokenValue;
     190        3617 :                     copyToLimiter(rCandidate, ';', nPos, aTokenValue, nLen);
     191        3617 :                     skip_char(rCandidate, ' ', ';', nPos, nLen);
     192        7234 :                     const OUString aOUTokenName(aTokenName.makeStringAndClear());
     193        7234 :                     const OUString aOUTokenValue(aTokenValue.makeStringAndClear());
     194             : 
     195        7234 :                     parseStyleAttribute(aOUTokenName, StrToSVGToken(aOUTokenName), aOUTokenValue);
     196             :                 }
     197             : 
     198        3617 :                 if(nInitPos == nPos)
     199             :                 {
     200             :                     OSL_ENSURE(false, "Could not interpret on current position (!)");
     201           0 :                     nPos++;
     202             :                 }
     203        3617 :             }
     204        3566 :         }
     205             : 
     206      127808 :         const SvgStyleAttributes* SvgStyleAttributes::getParentStyle() const
     207             :         {
     208      127808 :             if(getCssStyleParent())
     209             :             {
     210           0 :                 return getCssStyleParent();
     211             :             }
     212             : 
     213      127808 :             if(mrOwner.getParent())
     214             :             {
     215      101210 :                 return mrOwner.getParent()->getSvgStyleAttributes();
     216             :             }
     217             : 
     218       26598 :             return 0;
     219             :         }
     220             : 
     221           0 :         void SvgStyleAttributes::add_text(
     222             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     223             :             drawinglayer::primitive2d::Primitive2DSequence& rSource) const
     224             :         {
     225           0 :             if(rSource.hasElements())
     226             :             {
     227             :                 // at this point the primitives in rSource are of type TextSimplePortionPrimitive2D
     228             :                 // or TextDecoratedPortionPrimitive2D and have the Fill Color (pAttributes->getFill())
     229             :                 // set. When another fill is used and also evtl. stroke is set it gets necessary to
     230             :                 // dismantle to geometry and add needed primitives
     231           0 :                 const basegfx::BColor* pFill = getFill();
     232           0 :                 const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
     233           0 :                 const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
     234           0 :                 const basegfx::BColor* pStroke = getStroke();
     235           0 :                 const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
     236           0 :                 const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
     237           0 :                 basegfx::B2DPolyPolygon aMergedArea;
     238             : 
     239           0 :                 if(pFillGradient || pFillPattern || pStroke || pStrokeGradient || pStrokePattern)
     240             :                 {
     241             :                     // text geometry is needed, create
     242             :                     // use neutral ViewInformation and create LineGeometryExtractor2D
     243           0 :                     const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
     244           0 :                     drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
     245             : 
     246             :                     // proccess
     247           0 :                     aExtractor.process(rSource);
     248             : 
     249             :                     // get results
     250           0 :                     const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
     251           0 :                     const sal_uInt32 nResultCount(rResult.size());
     252           0 :                     basegfx::B2DPolyPolygonVector aTextFillVector;
     253           0 :                     aTextFillVector.reserve(nResultCount);
     254             : 
     255           0 :                     for(sal_uInt32 a(0); a < nResultCount; a++)
     256             :                     {
     257           0 :                         const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
     258             : 
     259           0 :                         if(rCandidate.getIsFilled())
     260             :                         {
     261           0 :                             aTextFillVector.push_back(rCandidate.getB2DPolyPolygon());
     262             :                         }
     263             :                     }
     264             : 
     265           0 :                     if(!aTextFillVector.empty())
     266             :                     {
     267           0 :                         aMergedArea = basegfx::tools::mergeToSinglePolyPolygon(aTextFillVector);
     268           0 :                     }
     269             :                 }
     270             : 
     271           0 :                 const bool bStrokeUsed(pStroke || pStrokeGradient || pStrokePattern);
     272             : 
     273             :                 // add fill. Use geometry even for simple color fill when stroke
     274             :                 // is used, else text rendering and the geometry-based stroke will
     275             :                 // normally not really match optically due to divrese system text
     276             :                 // renderers
     277           0 :                 if(aMergedArea.count() && (pFillGradient || pFillPattern || bStrokeUsed))
     278             :                 {
     279             :                     // create text fill content based on geometry
     280           0 :                     add_fill(aMergedArea, rTarget, aMergedArea.getB2DRange());
     281             :                 }
     282           0 :                 else if(pFill)
     283             :                 {
     284             :                     // add the already prepared primitives for single color fill
     285           0 :                     drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource);
     286             :                 }
     287             : 
     288             :                 // add stroke
     289           0 :                 if(aMergedArea.count() && bStrokeUsed)
     290             :                 {
     291             :                     // create text stroke content
     292           0 :                     add_stroke(aMergedArea, rTarget, aMergedArea.getB2DRange());
     293           0 :                 }
     294             :             }
     295           0 :         }
     296             : 
     297        1247 :         void SvgStyleAttributes::add_fillGradient(
     298             :             const basegfx::B2DPolyPolygon& rPath,
     299             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     300             :             const SvgGradientNode& rFillGradient,
     301             :             const basegfx::B2DRange& rGeoRange) const
     302             :         {
     303             :             // create fill content
     304        1247 :             drawinglayer::primitive2d::SvgGradientEntryVector aSvgGradientEntryVector;
     305             : 
     306             :             // get the color stops
     307        1247 :             rFillGradient.collectGradientEntries(aSvgGradientEntryVector);
     308             : 
     309        1247 :             if(!aSvgGradientEntryVector.empty())
     310             :             {
     311        1247 :                 basegfx::B2DHomMatrix aGeoToUnit;
     312        2494 :                 basegfx::B2DHomMatrix aGradientTransform;
     313             : 
     314        1247 :                 if(rFillGradient.getGradientTransform())
     315             :                 {
     316         205 :                     aGradientTransform = *rFillGradient.getGradientTransform();
     317             :                 }
     318             : 
     319        1247 :                 if(userSpaceOnUse == rFillGradient.getGradientUnits())
     320             :                 {
     321        1247 :                     aGeoToUnit.translate(-rGeoRange.getMinX(), -rGeoRange.getMinY());
     322        1247 :                     aGeoToUnit.scale(1.0 / rGeoRange.getWidth(), 1.0 / rGeoRange.getHeight());
     323             :                 }
     324             : 
     325        1247 :                 if(SVGTokenLinearGradient == rFillGradient.getType())
     326             :                 {
     327        1147 :                     basegfx::B2DPoint aStart(0.0, 0.0);
     328        2294 :                     basegfx::B2DPoint aEnd(1.0, 0.0);
     329             : 
     330        1147 :                     if(userSpaceOnUse == rFillGradient.getGradientUnits())
     331             :                     {
     332             :                         // all possible units
     333        1147 :                         aStart.setX(rFillGradient.getX1().solve(mrOwner, xcoordinate));
     334        1147 :                         aStart.setY(rFillGradient.getY1().solve(mrOwner, ycoordinate));
     335        1147 :                         aEnd.setX(rFillGradient.getX2().solve(mrOwner, xcoordinate));
     336        1147 :                         aEnd.setY(rFillGradient.getY2().solve(mrOwner, ycoordinate));
     337             :                     }
     338             :                     else
     339             :                     {
     340             :                         // fractions or percent relative to object bounds
     341           0 :                         const SvgNumber X1(rFillGradient.getX1());
     342           0 :                         const SvgNumber Y1(rFillGradient.getY1());
     343           0 :                         const SvgNumber X2(rFillGradient.getX2());
     344           0 :                         const SvgNumber Y2(rFillGradient.getY2());
     345             : 
     346           0 :                         aStart.setX(Unit_percent == X1.getUnit() ? X1.getNumber() * 0.01 : X1.getNumber());
     347           0 :                         aStart.setY(Unit_percent == Y1.getUnit() ? Y1.getNumber() * 0.01 : Y1.getNumber());
     348           0 :                         aEnd.setX(Unit_percent == X2.getUnit() ? X2.getNumber() * 0.01 : X2.getNumber());
     349           0 :                         aEnd.setY(Unit_percent == Y2.getUnit() ? Y2.getNumber() * 0.01 : Y2.getNumber());
     350             :                     }
     351             : 
     352        1147 :                     if(!aGeoToUnit.isIdentity())
     353             :                     {
     354        1147 :                         aStart *= aGeoToUnit;
     355        1147 :                         aEnd *= aGeoToUnit;
     356             :                     }
     357             : 
     358             :                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
     359             :                         rTarget,
     360             :                         new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D(
     361             :                             aGradientTransform,
     362             :                             rPath,
     363             :                             aSvgGradientEntryVector,
     364             :                             aStart,
     365             :                             aEnd,
     366        1147 :                             userSpaceOnUse != rFillGradient.getGradientUnits(),
     367        2294 :                             rFillGradient.getSpreadMethod()));
     368             :                 }
     369             :                 else
     370             :                 {
     371         100 :                     basegfx::B2DPoint aStart(0.5, 0.5);
     372         200 :                     basegfx::B2DPoint aFocal;
     373         100 :                     double fRadius(0.5);
     374         100 :                     const SvgNumber* pFx = rFillGradient.getFx();
     375         100 :                     const SvgNumber* pFy = rFillGradient.getFy();
     376         100 :                     const bool bFocal(pFx || pFy);
     377             : 
     378         100 :                     if(userSpaceOnUse == rFillGradient.getGradientUnits())
     379             :                     {
     380             :                         // all possible units
     381         100 :                         aStart.setX(rFillGradient.getCx().solve(mrOwner, xcoordinate));
     382         100 :                         aStart.setY(rFillGradient.getCy().solve(mrOwner, ycoordinate));
     383         100 :                         fRadius = rFillGradient.getR().solve(mrOwner, length);
     384             : 
     385         100 :                         if(bFocal)
     386             :                         {
     387           0 :                             aFocal.setX(pFx ? pFx->solve(mrOwner, xcoordinate) : aStart.getX());
     388           0 :                             aFocal.setY(pFy ? pFy->solve(mrOwner, ycoordinate) : aStart.getY());
     389             :                         }
     390             :                     }
     391             :                     else
     392             :                     {
     393             :                         // fractions or percent relative to object bounds
     394           0 :                         const SvgNumber Cx(rFillGradient.getCx());
     395           0 :                         const SvgNumber Cy(rFillGradient.getCy());
     396           0 :                         const SvgNumber R(rFillGradient.getR());
     397             : 
     398           0 :                         aStart.setX(Unit_percent == Cx.getUnit() ? Cx.getNumber() * 0.01 : Cx.getNumber());
     399           0 :                         aStart.setY(Unit_percent == Cy.getUnit() ? Cy.getNumber() * 0.01 : Cy.getNumber());
     400           0 :                         fRadius = (Unit_percent == R.getUnit()) ? R.getNumber() * 0.01 : R.getNumber();
     401             : 
     402           0 :                         if(bFocal)
     403             :                         {
     404           0 :                             aFocal.setX(pFx ? (Unit_percent == pFx->getUnit() ? pFx->getNumber() * 0.01 : pFx->getNumber()) : aStart.getX());
     405           0 :                             aFocal.setY(pFy ? (Unit_percent == pFy->getUnit() ? pFy->getNumber() * 0.01 : pFy->getNumber()) : aStart.getY());
     406             :                         }
     407             :                     }
     408             : 
     409         100 :                     if(!aGeoToUnit.isIdentity())
     410             :                     {
     411         100 :                         aStart *= aGeoToUnit;
     412         100 :                         fRadius = (aGeoToUnit * basegfx::B2DVector(fRadius, 0.0)).getLength();
     413             : 
     414         100 :                         if(bFocal)
     415             :                         {
     416           0 :                             aFocal *= aGeoToUnit;
     417             :                         }
     418             :                     }
     419             : 
     420             :                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
     421             :                         rTarget,
     422             :                         new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D(
     423             :                             aGradientTransform,
     424             :                             rPath,
     425             :                             aSvgGradientEntryVector,
     426             :                             aStart,
     427             :                             fRadius,
     428         100 :                             userSpaceOnUse != rFillGradient.getGradientUnits(),
     429             :                             rFillGradient.getSpreadMethod(),
     430         200 :                             bFocal ? &aFocal : 0));
     431        1247 :                 }
     432        1247 :             }
     433        1247 :         }
     434             : 
     435           0 :         void SvgStyleAttributes::add_fillPatternTransform(
     436             :             const basegfx::B2DPolyPolygon& rPath,
     437             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     438             :             const SvgPatternNode& rFillPattern,
     439             :             const basegfx::B2DRange& rGeoRange) const
     440             :         {
     441             :             // prepare fill polyPolygon with given pattern, check for patternTransform
     442           0 :             if(rFillPattern.getPatternTransform() && !rFillPattern.getPatternTransform()->isIdentity())
     443             :             {
     444             :                 // PatternTransform is active; Handle by filling the inverse transformed
     445             :                 // path and back-transforming the result
     446           0 :                 basegfx::B2DPolyPolygon aPath(rPath);
     447           0 :                 basegfx::B2DHomMatrix aInv(*rFillPattern.getPatternTransform());
     448           0 :                 drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
     449             : 
     450           0 :                 aInv.invert();
     451           0 :                 aPath.transform(aInv);
     452           0 :                 add_fillPattern(aPath, aNewTarget, rFillPattern, aPath.getB2DRange());
     453             : 
     454           0 :                 if(aNewTarget.hasElements())
     455             :                 {
     456             :                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
     457             :                         rTarget,
     458             :                         new drawinglayer::primitive2d::TransformPrimitive2D(
     459             :                             *rFillPattern.getPatternTransform(),
     460           0 :                             aNewTarget));
     461           0 :                 }
     462             :             }
     463             :             else
     464             :             {
     465             :                 // no patternTransform, create fillPattern directly
     466           0 :                 add_fillPattern(rPath, rTarget, rFillPattern, rGeoRange);
     467             :             }
     468           0 :         }
     469             : 
     470           0 :         void SvgStyleAttributes::add_fillPattern(
     471             :             const basegfx::B2DPolyPolygon& rPath,
     472             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     473             :             const SvgPatternNode& rFillPattern,
     474             :             const basegfx::B2DRange& rGeoRange) const
     475             :         {
     476             :             // fill polyPolygon with given pattern
     477           0 :             const drawinglayer::primitive2d::Primitive2DSequence& rPrimitives = rFillPattern.getPatternPrimitives();
     478             : 
     479           0 :             if(rPrimitives.hasElements())
     480             :             {
     481           0 :                 double fTargetWidth(rGeoRange.getWidth());
     482           0 :                 double fTargetHeight(rGeoRange.getHeight());
     483             : 
     484           0 :                 if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
     485             :                 {
     486             :                     // get relative values from pattern
     487           0 :                     double fX(0.0);
     488           0 :                     double fY(0.0);
     489           0 :                     double fW(0.0);
     490           0 :                     double fH(0.0);
     491             : 
     492           0 :                     rFillPattern.getValuesRelative(fX, fY, fW, fH, rGeoRange, mrOwner);
     493             : 
     494           0 :                     if(fW > 0.0 && fH > 0.0)
     495             :                     {
     496             :                         // build the reference range relative to the rGeoRange
     497           0 :                         const basegfx::B2DRange aReferenceRange(fX, fY, fX + fW, fY + fH);
     498             : 
     499             :                         // find out how the content is mapped to the reference range
     500           0 :                         basegfx::B2DHomMatrix aMapPrimitivesToUnitRange;
     501           0 :                         const basegfx::B2DRange* pViewBox = rFillPattern.getViewBox();
     502             : 
     503           0 :                         if(pViewBox)
     504             :                         {
     505             :                             // use viewBox/preserveAspectRatio
     506           0 :                             const SvgAspectRatio& rRatio = rFillPattern.getSvgAspectRatio();
     507           0 :                             const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
     508             : 
     509           0 :                             if(rRatio.isSet())
     510             :                             {
     511             :                                 // let mapping be created from SvgAspectRatio
     512           0 :                                 aMapPrimitivesToUnitRange = rRatio.createMapping(aUnitRange, *pViewBox);
     513             :                             }
     514             :                             else
     515             :                             {
     516             :                                 // choose default mapping
     517           0 :                                 aMapPrimitivesToUnitRange = rRatio.createLinearMapping(aUnitRange, *pViewBox);
     518             :                             }
     519             :                         }
     520             :                         else
     521             :                         {
     522             :                             // use patternContentUnits
     523           0 :                             const SvgUnits aPatternContentUnits(rFillPattern.getPatternContentUnits() ? *rFillPattern.getPatternContentUnits() : userSpaceOnUse);
     524             : 
     525           0 :                             if(userSpaceOnUse == aPatternContentUnits)
     526             :                             {
     527             :                                 // create relative mapping to unit coordinates
     528           0 :                                 aMapPrimitivesToUnitRange.scale(1.0 / (fW * fTargetWidth), 1.0 / (fH * fTargetHeight));
     529             :                             }
     530             :                             else
     531             :                             {
     532           0 :                                 aMapPrimitivesToUnitRange.scale(1.0 / fW, 1.0 / fH);
     533             :                             }
     534             :                         }
     535             : 
     536             :                         // apply aMapPrimitivesToUnitRange to content when used
     537           0 :                         drawinglayer::primitive2d::Primitive2DSequence aPrimitives(rPrimitives);
     538             : 
     539           0 :                         if(!aMapPrimitivesToUnitRange.isIdentity())
     540             :                         {
     541             :                             const drawinglayer::primitive2d::Primitive2DReference xRef(
     542             :                                 new drawinglayer::primitive2d::TransformPrimitive2D(
     543             :                                     aMapPrimitivesToUnitRange,
     544           0 :                                     aPrimitives));
     545             : 
     546           0 :                             aPrimitives = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
     547             :                         }
     548             : 
     549             :                         // embed in PatternFillPrimitive2D
     550             :                         drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
     551             :                             rTarget,
     552             :                             new drawinglayer::primitive2d::PatternFillPrimitive2D(
     553             :                                 rPath,
     554             :                                 aPrimitives,
     555           0 :                                 aReferenceRange));
     556             :                     }
     557             :                 }
     558             :             }
     559           0 :         }
     560             : 
     561        2974 :         void SvgStyleAttributes::add_fill(
     562             :             const basegfx::B2DPolyPolygon& rPath,
     563             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     564             :             const basegfx::B2DRange& rGeoRange) const
     565             :         {
     566        2974 :             const basegfx::BColor* pFill = getFill();
     567        2974 :             const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
     568        2974 :             const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
     569             : 
     570        2974 :             if(pFill || pFillGradient || pFillPattern)
     571             :             {
     572        2888 :                 const double fFillOpacity(getFillOpacity().solve(mrOwner, length));
     573             : 
     574        2888 :                 if(basegfx::fTools::more(fFillOpacity, 0.0))
     575             :                 {
     576        2888 :                     drawinglayer::primitive2d::Primitive2DSequence aNewFill;
     577             : 
     578        2888 :                     if(pFillGradient)
     579             :                     {
     580             :                         // create fill content with SVG gradient primitive
     581        1247 :                         add_fillGradient(rPath, aNewFill, *pFillGradient, rGeoRange);
     582             :                     }
     583        1641 :                     else if(pFillPattern)
     584             :                     {
     585             :                         // create fill content with SVG pattern primitive
     586           0 :                         add_fillPatternTransform(rPath, aNewFill, *pFillPattern, rGeoRange);
     587             :                     }
     588             :                     else // if(pFill)
     589             :                     {
     590             :                         // create fill content
     591        1641 :                         aNewFill.realloc(1);
     592        3282 :                         aNewFill[0] = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
     593             :                             rPath,
     594        3282 :                             *pFill);
     595             :                     }
     596             : 
     597        2888 :                     if(aNewFill.hasElements())
     598             :                     {
     599        2888 :                         if(basegfx::fTools::less(fFillOpacity, 1.0))
     600             :                         {
     601             :                             // embed in UnifiedTransparencePrimitive2D
     602             :                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
     603             :                                 rTarget,
     604             :                                 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
     605             :                                     aNewFill,
     606           0 :                                     1.0 - fFillOpacity));
     607             :                         }
     608             :                         else
     609             :                         {
     610             :                             // append
     611        2888 :                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewFill);
     612             :                         }
     613        2888 :                     }
     614             :                 }
     615             :             }
     616        2974 :         }
     617             : 
     618        2993 :         void SvgStyleAttributes::add_stroke(
     619             :             const basegfx::B2DPolyPolygon& rPath,
     620             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     621             :             const basegfx::B2DRange& rGeoRange) const
     622             :         {
     623        2993 :             const basegfx::BColor* pStroke = getStroke();
     624        2993 :             const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
     625        2993 :             const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
     626             : 
     627        2993 :             if(pStroke || pStrokeGradient || pStrokePattern)
     628             :             {
     629         226 :                 drawinglayer::primitive2d::Primitive2DSequence aNewStroke;
     630         226 :                 const double fStrokeOpacity(getStrokeOpacity().solve(mrOwner, length));
     631             : 
     632         226 :                 if(basegfx::fTools::more(fStrokeOpacity, 0.0))
     633             :                 {
     634             :                     // get stroke width; SVG does not use 0.0 == hairline, so 0.0 is no line at all
     635         226 :                     const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
     636             : 
     637         226 :                     if(basegfx::fTools::more(fStrokeWidth, 0.0))
     638             :                     {
     639             :                         // get LineJoin, LineCap and stroke array
     640         226 :                         const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin()));
     641         226 :                         const com::sun::star::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap()));
     642         226 :                         ::std::vector< double > aDashArray;
     643             : 
     644         226 :                         if(!getStrokeDasharray().empty())
     645             :                         {
     646          15 :                             aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner, length);
     647             :                         }
     648             : 
     649             :                         // todo: Handle getStrokeDashOffset()
     650             : 
     651             :                         // prepare line attribute
     652         452 :                         drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive;
     653             :                         const drawinglayer::attribute::LineAttribute aLineAttribute(
     654             :                             pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0),
     655             :                             fStrokeWidth,
     656             :                             aB2DLineJoin,
     657         452 :                             aLineCap);
     658             : 
     659         226 :                         if(aDashArray.empty())
     660             :                         {
     661         422 :                             aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
     662             :                                 rPath,
     663         422 :                                 aLineAttribute);
     664             :                         }
     665             :                         else
     666             :                         {
     667          15 :                             const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray);
     668             : 
     669          30 :                             aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
     670             :                                 rPath,
     671             :                                 aLineAttribute,
     672          30 :                                 aStrokeAttribute);
     673             :                         }
     674             : 
     675         226 :                         if(pStrokeGradient || pStrokePattern)
     676             :                         {
     677             :                             // put primitive into Primitive2DReference and Primitive2DSequence
     678           0 :                             const drawinglayer::primitive2d::Primitive2DSequence aSeq(&aNewLinePrimitive, 1);
     679             : 
     680             :                             // use neutral ViewInformation and create LineGeometryExtractor2D
     681           0 :                             const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
     682           0 :                             drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
     683             : 
     684             :                             // proccess
     685           0 :                             aExtractor.process(aSeq);
     686             : 
     687             :                             // check for fill rsults
     688           0 :                             const basegfx::B2DPolyPolygonVector& rLineFillVector(aExtractor.getExtractedLineFills());
     689             : 
     690           0 :                             if(!rLineFillVector.empty())
     691             :                             {
     692             :                                 const basegfx::B2DPolyPolygon aMergedArea(
     693             :                                     basegfx::tools::mergeToSinglePolyPolygon(
     694           0 :                                         rLineFillVector));
     695             : 
     696           0 :                                 if(aMergedArea.count())
     697             :                                 {
     698           0 :                                     if(pStrokeGradient)
     699             :                                     {
     700             :                                         // create fill content with SVG gradient primitive. Use original GeoRange,
     701             :                                         // e.g. from circle without LineWidth
     702           0 :                                         add_fillGradient(aMergedArea, aNewStroke, *pStrokeGradient, rGeoRange);
     703             :                                     }
     704             :                                     else // if(pStrokePattern)
     705             :                                     {
     706             :                                         // create fill content with SVG pattern primitive. Use GeoRange
     707             :                                         // from the expanded data, e.g. circle with extended geo by half linewidth
     708           0 :                                         add_fillPatternTransform(aMergedArea, aNewStroke, *pStrokePattern, aMergedArea.getB2DRange());
     709             :                                     }
     710           0 :                                 }
     711           0 :                             }
     712             :                         }
     713             :                         else // if(pStroke)
     714             :                         {
     715         226 :                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aNewStroke, aNewLinePrimitive);
     716             :                         }
     717             : 
     718         226 :                         if(aNewStroke.hasElements())
     719             :                         {
     720         226 :                             if(basegfx::fTools::less(fStrokeOpacity, 1.0))
     721             :                             {
     722             :                                 // embed in UnifiedTransparencePrimitive2D
     723             :                                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
     724             :                                     rTarget,
     725             :                                     new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
     726             :                                         aNewStroke,
     727           0 :                                         1.0 - fStrokeOpacity));
     728             :                             }
     729             :                             else
     730             :                             {
     731             :                                 // append
     732         226 :                                 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewStroke);
     733             :                             }
     734         226 :                         }
     735             :                     }
     736         226 :                 }
     737             :             }
     738        2993 :         }
     739             : 
     740           0 :         bool SvgStyleAttributes::prepare_singleMarker(
     741             :             drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
     742             :             basegfx::B2DHomMatrix& rMarkerTransform,
     743             :             basegfx::B2DRange& rClipRange,
     744             :             const SvgMarkerNode& rMarker) const
     745             :         {
     746             :             // reset return values
     747           0 :             rMarkerTransform.identity();
     748           0 :             rClipRange.reset();
     749             : 
     750             :             // get marker primitive representation
     751           0 :             rMarkerPrimitives = rMarker.getMarkerPrimitives();
     752             : 
     753           0 :             if(rMarkerPrimitives.hasElements())
     754             :             {
     755           0 :                 basegfx::B2DRange aPrimitiveRange(0.0, 0.0, 1.0, 1.0);
     756           0 :                 const basegfx::B2DRange* pViewBox = rMarker.getViewBox();
     757             : 
     758           0 :                 if(pViewBox)
     759             :                 {
     760           0 :                     aPrimitiveRange = *pViewBox;
     761             :                 }
     762             : 
     763           0 :                 if(aPrimitiveRange.getWidth() > 0.0 && aPrimitiveRange.getHeight() > 0.0)
     764             :                 {
     765           0 :                     double fTargetWidth(rMarker.getMarkerWidth().isSet() ? rMarker.getMarkerWidth().solve(mrOwner, xcoordinate) : 3.0);
     766           0 :                     double fTargetHeight(rMarker.getMarkerHeight().isSet() ? rMarker.getMarkerHeight().solve(mrOwner, xcoordinate) : 3.0);
     767           0 :                     const bool bStrokeWidth(SvgMarkerNode::strokeWidth == rMarker.getMarkerUnits());
     768           0 :                     const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
     769             : 
     770           0 :                     if(bStrokeWidth)
     771             :                     {
     772             :                         // relative to strokeWidth
     773           0 :                         fTargetWidth *= fStrokeWidth;
     774           0 :                         fTargetHeight *= fStrokeWidth;
     775             :                     }
     776             : 
     777           0 :                     if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
     778             :                     {
     779             :                         // create mapping
     780           0 :                         const basegfx::B2DRange aTargetRange(0.0, 0.0, fTargetWidth, fTargetHeight);
     781           0 :                         const SvgAspectRatio& rRatio = rMarker.getSvgAspectRatio();
     782             : 
     783           0 :                         if(rRatio.isSet())
     784             :                         {
     785             :                             // let mapping be created from SvgAspectRatio
     786           0 :                             rMarkerTransform = rRatio.createMapping(aTargetRange, aPrimitiveRange);
     787             : 
     788           0 :                             if(rRatio.isMeetOrSlice())
     789             :                             {
     790             :                                 // need to clip
     791           0 :                                 rClipRange = aPrimitiveRange;
     792             :                             }
     793             :                         }
     794             :                         else
     795             :                         {
     796           0 :                             if(!pViewBox)
     797             :                             {
     798           0 :                                 if(bStrokeWidth)
     799             :                                 {
     800             :                                     // adapt to strokewidth if needed
     801           0 :                                     rMarkerTransform.scale(fStrokeWidth, fStrokeWidth);
     802             :                                 }
     803             :                             }
     804             :                             else
     805             :                             {
     806             :                                 // choose default mapping
     807           0 :                                 rMarkerTransform = rRatio.createLinearMapping(aTargetRange, aPrimitiveRange);
     808             :                             }
     809             :                         }
     810             : 
     811             :                         // get and apply reference point. Initially it's in marker local coordinate system
     812             :                         basegfx::B2DPoint aRefPoint(
     813           0 :                             rMarker.getRefX().isSet() ? rMarker.getRefX().solve(mrOwner, xcoordinate) : 0.0,
     814           0 :                             rMarker.getRefY().isSet() ? rMarker.getRefY().solve(mrOwner, ycoordinate) : 0.0);
     815             : 
     816             :                         // apply MarkerTransform to have it in mapped coordinates
     817           0 :                         aRefPoint *= rMarkerTransform;
     818             : 
     819             :                         // apply by moving RepPoint to (0.0)
     820           0 :                         rMarkerTransform.translate(-aRefPoint.getX(), -aRefPoint.getY());
     821             : 
     822           0 :                         return true;
     823             :                     }
     824             :                 }
     825             :             }
     826             : 
     827           0 :             return false;
     828             :         }
     829             : 
     830        2523 :         void SvgStyleAttributes::add_markers(
     831             :             const basegfx::B2DPolyPolygon& rPath,
     832             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
     833             :             const basegfx::tools::PointIndexSet* pHelpPointIndices) const
     834             :         {
     835             :             // try to access linked markers
     836        2523 :             const SvgMarkerNode* pStart = accessMarkerStartXLink();
     837        2523 :             const SvgMarkerNode* pMid = accessMarkerMidXLink();
     838        2523 :             const SvgMarkerNode* pEnd = accessMarkerEndXLink();
     839             : 
     840        2523 :             if(pStart || pMid || pEnd)
     841             :             {
     842           0 :                 const sal_uInt32 nSubPathCount(rPath.count());
     843             : 
     844           0 :                 if(nSubPathCount)
     845             :                 {
     846             :                     // remember prepared marker; pStart, pMid and pEnd may all be equal when
     847             :                     // only 'marker' was used instead of 'marker-start', 'marker-mid' or 'marker-end',
     848             :                     // see 'case SVGTokenMarker' in this file; thus in this case only one common
     849             :                     // marker in primitive form will be prepared
     850           0 :                     const SvgMarkerNode* pPrepared = 0;
     851             : 
     852             :                     // values for the prepared marker, results of prepare_singleMarker
     853           0 :                     drawinglayer::primitive2d::Primitive2DSequence aPreparedMarkerPrimitives;
     854           0 :                     basegfx::B2DHomMatrix aPreparedMarkerTransform;
     855           0 :                     basegfx::B2DRange aPreparedMarkerClipRange;
     856             : 
     857           0 :                     for (sal_uInt32 a(0); a < nSubPathCount; a++)
     858             :                     {
     859             :                         // iterate over sub-paths
     860           0 :                         const basegfx::B2DPolygon aSubPolygonPath(rPath.getB2DPolygon(a));
     861           0 :                         const sal_uInt32 nSubPolygonPointCount(aSubPolygonPath.count());
     862           0 :                         const bool bSubPolygonPathIsClosed(aSubPolygonPath.isClosed());
     863             : 
     864           0 :                         if(nSubPolygonPointCount)
     865             :                         {
     866             :                             // for each sub-path, create one marker per point (when closed, two markers
     867             :                             // need to pe created for the 1st point)
     868           0 :                             const sal_uInt32 nTargetMarkerCount(bSubPolygonPathIsClosed ? nSubPolygonPointCount + 1 : nSubPolygonPointCount);
     869             : 
     870           0 :                             for (sal_uInt32 b(0); b < nTargetMarkerCount; b++)
     871             :                             {
     872           0 :                                 const bool bIsFirstMarker(!a && !b);
     873           0 :                                 const bool bIsLastMarker(nSubPathCount - 1 == a && nTargetMarkerCount - 1 == b);
     874           0 :                                 const SvgMarkerNode* pNeeded = 0;
     875             : 
     876           0 :                                 if(bIsFirstMarker)
     877             :                                 {
     878             :                                     // 1st point in 1st sub-polygon, use pStart
     879           0 :                                     pNeeded = pStart;
     880             :                                 }
     881           0 :                                 else if(bIsLastMarker)
     882             :                                 {
     883             :                                     // last point in last sub-polygon, use pEnd
     884           0 :                                     pNeeded = pEnd;
     885             :                                 }
     886             :                                 else
     887             :                                 {
     888             :                                     // anything in-between, use pMid
     889           0 :                                     pNeeded = pMid;
     890             :                                 }
     891             : 
     892           0 :                                 if(pHelpPointIndices && !pHelpPointIndices->empty())
     893             :                                 {
     894             :                                     const basegfx::tools::PointIndexSet::const_iterator aFound(
     895           0 :                                         pHelpPointIndices->find(basegfx::tools::PointIndex(a, b)));
     896             : 
     897           0 :                                     if(aFound != pHelpPointIndices->end())
     898             :                                     {
     899             :                                         // this point is a pure helper point; do not create a marker for it
     900           0 :                                         continue;
     901             :                                     }
     902             :                                 }
     903             : 
     904           0 :                                 if(!pNeeded)
     905             :                                 {
     906             :                                     // no marker needs to be created for this point
     907           0 :                                     continue;
     908             :                                 }
     909             : 
     910           0 :                                 if(pPrepared != pNeeded)
     911             :                                 {
     912             :                                     // if needed marker is not yet prepared, do it now
     913           0 :                                     if(prepare_singleMarker(aPreparedMarkerPrimitives, aPreparedMarkerTransform, aPreparedMarkerClipRange, *pNeeded))
     914             :                                     {
     915           0 :                                         pPrepared = pNeeded;
     916             :                                     }
     917             :                                     else
     918             :                                     {
     919             :                                         // error: could not prepare given marker
     920             :                                         OSL_ENSURE(false, "OOps, could not prepare given marker as primitives (!)");
     921           0 :                                         pPrepared = 0;
     922           0 :                                         continue;
     923             :                                     }
     924             :                                 }
     925             : 
     926             :                                 // prepare complete transform
     927           0 :                                 basegfx::B2DHomMatrix aCombinedTransform(aPreparedMarkerTransform);
     928             : 
     929             :                                 // get rotation
     930           0 :                                 if(pPrepared->getOrientAuto())
     931             :                                 {
     932           0 :                                     const sal_uInt32 nPointIndex(b % nSubPolygonPointCount);
     933             : 
     934             :                                     // get entering and leaving tangents; this will search backward/froward
     935             :                                     // in the polygon to find tangents unequal to zero, skipping empty edges
     936             :                                     // see basegfx descriptions)
     937             :                                     // Hint: Mozilla, Inkscape and others use only leaving tangent for start marker
     938             :                                     // and entering tangent for end marker. To achieve this (if wanted) it is possibe
     939             :                                     // to make the fetch of aEntering/aLeaving dependent on bIsFirstMarker/bIsLastMarker.
     940             :                                     // This is not done here, see comment 14 in task #1232379#
     941             :                                     // or http://www.w3.org/TR/SVG/painting.html#OrientAttribute
     942             :                                     basegfx::B2DVector aEntering(
     943             :                                         basegfx::tools::getTangentEnteringPoint(
     944             :                                             aSubPolygonPath,
     945           0 :                                             nPointIndex));
     946             :                                     basegfx::B2DVector aLeaving(
     947             :                                         basegfx::tools::getTangentLeavingPoint(
     948             :                                             aSubPolygonPath,
     949           0 :                                             nPointIndex));
     950           0 :                                     const bool bEntering(!aEntering.equalZero());
     951           0 :                                     const bool bLeaving(!aLeaving.equalZero());
     952             : 
     953           0 :                                     if(bEntering || bLeaving)
     954             :                                     {
     955           0 :                                         basegfx::B2DVector aSum(0.0, 0.0);
     956             : 
     957           0 :                                         if(bEntering)
     958             :                                         {
     959           0 :                                             aSum += aEntering.normalize();
     960             :                                         }
     961             : 
     962           0 :                                         if(bLeaving)
     963             :                                         {
     964           0 :                                             aSum += aLeaving.normalize();
     965             :                                         }
     966             : 
     967           0 :                                         if(!aSum.equalZero())
     968             :                                         {
     969           0 :                                             const double fAngle(atan2(aSum.getY(), aSum.getX()));
     970             : 
     971             :                                             // apply rotation
     972           0 :                                             aCombinedTransform.rotate(fAngle);
     973           0 :                                         }
     974           0 :                                     }
     975             :                                 }
     976             :                                 else
     977             :                                 {
     978             :                                     // apply rotation
     979           0 :                                     aCombinedTransform.rotate(pPrepared->getAngle());
     980             :                                 }
     981             : 
     982             :                                 // get and apply target position
     983           0 :                                 const basegfx::B2DPoint aPoint(aSubPolygonPath.getB2DPoint(b % nSubPolygonPointCount));
     984             : 
     985           0 :                                 aCombinedTransform.translate(aPoint.getX(), aPoint.getY());
     986             : 
     987             :                                 // prepare marker
     988             :                                 drawinglayer::primitive2d::Primitive2DReference xMarker(
     989             :                                     new drawinglayer::primitive2d::TransformPrimitive2D(
     990             :                                         aCombinedTransform,
     991           0 :                                         aPreparedMarkerPrimitives));
     992             : 
     993           0 :                                 if(!aPreparedMarkerClipRange.isEmpty())
     994             :                                 {
     995             :                                     // marker needs to be clipped, it's bigger as the mapping
     996           0 :                                     basegfx::B2DPolyPolygon aClipPolygon(basegfx::tools::createPolygonFromRect(aPreparedMarkerClipRange));
     997             : 
     998           0 :                                     aClipPolygon.transform(aCombinedTransform);
     999           0 :                                     xMarker = new drawinglayer::primitive2d::MaskPrimitive2D(
    1000             :                                         aClipPolygon,
    1001           0 :                                         drawinglayer::primitive2d::Primitive2DSequence(&xMarker, 1));
    1002             :                                 }
    1003             : 
    1004             :                                 // add marker
    1005           0 :                                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMarker);
    1006           0 :                             }
    1007             :                         }
    1008           0 :                     }
    1009             :                 }
    1010             :             }
    1011        2523 :         }
    1012             : 
    1013        2993 :         void SvgStyleAttributes::add_path(
    1014             :             const basegfx::B2DPolyPolygon& rPath,
    1015             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
    1016             :             const basegfx::tools::PointIndexSet* pHelpPointIndices) const
    1017             :         {
    1018        2993 :             if(!rPath.count())
    1019             :             {
    1020             :                 // no geometry at all
    1021           0 :                 return;
    1022             :             }
    1023             : 
    1024        2993 :             const basegfx::B2DRange aGeoRange(rPath.getB2DRange());
    1025             : 
    1026        2993 :             if(aGeoRange.isEmpty())
    1027             :             {
    1028             :                 // no geometry range
    1029           0 :                 return;
    1030             :             }
    1031             : 
    1032        2993 :             const double fOpacity(getOpacity().getNumber());
    1033             : 
    1034        2993 :             if(basegfx::fTools::equalZero(fOpacity))
    1035             :             {
    1036             :                 // not visible
    1037           0 :                 return;
    1038             :             }
    1039             : 
    1040             :             // check if it's a line
    1041        2993 :             const bool bNoWidth(basegfx::fTools::equalZero(aGeoRange.getWidth()));
    1042        2993 :             const bool bNoHeight(basegfx::fTools::equalZero(aGeoRange.getHeight()));
    1043        2993 :             const bool bIsTwoPointLine(1 == rPath.count()
    1044        2483 :                 && !rPath.areControlPointsUsed()
    1045        6828 :                 && 2 == rPath.getB2DPolygon(0).count());
    1046        2993 :             const bool bIsLine(bIsTwoPointLine || bNoWidth || bNoHeight);
    1047             : 
    1048        2993 :             if(!bIsLine)
    1049             :             {
    1050             :                 // create fill
    1051        2974 :                 basegfx::B2DPolyPolygon aPath(rPath);
    1052        2974 :                 const bool bNeedToCheckClipRule(SVGTokenPath == mrOwner.getType() || SVGTokenPolygon == mrOwner.getType());
    1053        2974 :                 const bool bClipPathIsNonzero(!bIsLine && bNeedToCheckClipRule && mbIsClipPathContent && FillRule_nonzero == maClipRule);
    1054        2974 :                 const bool bFillRuleIsNonzero(!bIsLine && bNeedToCheckClipRule && !mbIsClipPathContent && FillRule_nonzero == getFillRule());
    1055             : 
    1056        2974 :                 if(bClipPathIsNonzero || bFillRuleIsNonzero)
    1057             :                 {
    1058             :                     // nonzero is wanted, solve geometrically (see description on basegfx)
    1059        2483 :                     aPath = basegfx::tools::createNonzeroConform(aPath);
    1060             :                 }
    1061             : 
    1062        2974 :                 add_fill(aPath, rTarget, aGeoRange);
    1063             :             }
    1064             : 
    1065             :             // create stroke
    1066        2993 :             add_stroke(rPath, rTarget, aGeoRange);
    1067             : 
    1068             :             // Svg supports markers for path, polygon, polyline and line
    1069        7157 :             if(SVGTokenPath == mrOwner.getType() ||         // path
    1070        3466 :                 SVGTokenPolygon == mrOwner.getType() ||     // polygon, polyline
    1071         473 :                 SVGTokenLine == mrOwner.getType())          // line
    1072             :             {
    1073             :                 // try to add markers
    1074        2523 :                 add_markers(rPath, rTarget, pHelpPointIndices);
    1075             :             }
    1076             :         }
    1077             : 
    1078        5004 :         void SvgStyleAttributes::add_postProcess(
    1079             :             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
    1080             :             const drawinglayer::primitive2d::Primitive2DSequence& rSource,
    1081             :             const basegfx::B2DHomMatrix* pTransform) const
    1082             :         {
    1083        5004 :             if(rSource.hasElements())
    1084             :             {
    1085        5004 :                 const double fOpacity(getOpacity().getNumber());
    1086             : 
    1087        5004 :                 if(basegfx::fTools::equalZero(fOpacity))
    1088             :                 {
    1089        5004 :                     return;
    1090             :                 }
    1091             : 
    1092        5004 :                 drawinglayer::primitive2d::Primitive2DSequence aSource(rSource);
    1093             : 
    1094        5004 :                 if(basegfx::fTools::less(fOpacity, 1.0))
    1095             :                 {
    1096             :                     // embed in UnifiedTransparencePrimitive2D
    1097             :                     const drawinglayer::primitive2d::Primitive2DReference xRef(
    1098             :                         new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
    1099             :                             aSource,
    1100         671 :                             1.0 - fOpacity));
    1101             : 
    1102         671 :                     aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
    1103             :                 }
    1104             : 
    1105        5004 :                 if(pTransform)
    1106             :                 {
    1107             :                     // create embedding group element with transformation. This applies the given
    1108             :                     // transformation to the graphical content, but *not* to mask and/or clip (as needed)
    1109             :                     const drawinglayer::primitive2d::Primitive2DReference xRef(
    1110             :                         new drawinglayer::primitive2d::TransformPrimitive2D(
    1111             :                             *pTransform,
    1112         331 :                             aSource));
    1113             : 
    1114         331 :                     aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
    1115             :                 }
    1116             : 
    1117        5004 :                 if(!getClipPathXLink().isEmpty())
    1118             :                 {
    1119             :                     // try to access linked ClipPath
    1120         156 :                     const SvgClipPathNode* mpClip = dynamic_cast< const SvgClipPathNode* >(mrOwner.getDocument().findSvgNodeById(getClipPathXLink()));
    1121             : 
    1122         156 :                     if(mpClip)
    1123             :                     {
    1124         156 :                         mpClip->apply(aSource);
    1125             :                     }
    1126             :                 }
    1127             : 
    1128        5004 :                 if(aSource.hasElements()) // test again, applied clipPath may have lead to empty geometry
    1129             :                 {
    1130        5004 :                     if(!getMaskXLink().isEmpty())
    1131             :                     {
    1132             :                         // try to access linked Mask
    1133         156 :                         const SvgMaskNode* mpMask = dynamic_cast< const SvgMaskNode* >(mrOwner.getDocument().findSvgNodeById(getMaskXLink()));
    1134             : 
    1135         156 :                         if(mpMask)
    1136             :                         {
    1137         156 :                             mpMask->apply(aSource);
    1138             :                         }
    1139             :                     }
    1140             : 
    1141        5004 :                     if(aSource.hasElements()) // test again, applied mask may have lead to empty geometry
    1142             :                     {
    1143             :                         // append to current target
    1144        5002 :                         drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSource);
    1145             :                     }
    1146        5004 :                 }
    1147             :             }
    1148             :         }
    1149             : 
    1150       10759 :         SvgStyleAttributes::SvgStyleAttributes(SvgNode& rOwner)
    1151             :         :   mrOwner(rOwner),
    1152             :             mpCssStyleParent(0),
    1153             :             maFill(),
    1154             :             maStroke(),
    1155             :             maStopColor(basegfx::BColor(0.0, 0.0, 0.0), true),
    1156             :             maStrokeWidth(),
    1157             :             maStopOpacity(),
    1158             :             mpSvgGradientNodeFill(0),
    1159             :             mpSvgGradientNodeStroke(0),
    1160             :             mpSvgPatternNodeFill(0),
    1161             :             mpSvgPatternNodeStroke(0),
    1162             :             maFillOpacity(),
    1163             :             maStrokeDasharray(),
    1164             :             maStrokeDashOffset(),
    1165             :             maStrokeLinecap(StrokeLinecap_notset),
    1166             :             maStrokeLinejoin(StrokeLinejoin_notset),
    1167             :             maStrokeMiterLimit(),
    1168             :             maStrokeOpacity(),
    1169             :             maFontFamily(),
    1170             :             maFontSize(),
    1171             :             maFontStretch(FontStretch_notset),
    1172             :             maFontStyle(FontStyle_notset),
    1173             :             maFontVariant(FontVariant_notset),
    1174             :             maFontWeight(FontWeight_notset),
    1175             :             maTextAlign(TextAlign_notset),
    1176             :             maTextDecoration(TextDecoration_notset),
    1177             :             maTextAnchor(TextAnchor_notset),
    1178             :             maColor(),
    1179             :             maOpacity(1.0),
    1180             :             maTitle(),
    1181             :             maDesc(),
    1182             :             maClipPathXLink(),
    1183             :             maMaskXLink(),
    1184             :             maMarkerStartXLink(),
    1185             :             mpMarkerStartXLink(0),
    1186             :             maMarkerMidXLink(),
    1187             :             mpMarkerMidXLink(0),
    1188             :             maMarkerEndXLink(),
    1189             :             mpMarkerEndXLink(0),
    1190             :             maFillRule(FillRule_notset),
    1191             :             maClipRule(FillRule_nonzero),
    1192             :             maBaselineShift(BaselineShift_Baseline),
    1193             :             maBaselineShiftNumber(0),
    1194       10759 :             mbIsClipPathContent(SVGTokenClipPathNode == mrOwner.getType()),
    1195       21518 :             mbStrokeDasharraySet(false)
    1196             :         {
    1197       10759 :             if(!mbIsClipPathContent)
    1198             :             {
    1199       10666 :                 const SvgStyleAttributes* pParentStyle = getParentStyle();
    1200             : 
    1201       10666 :                 if(pParentStyle)
    1202             :                 {
    1203       10374 :                     mbIsClipPathContent = pParentStyle->mbIsClipPathContent;
    1204             :                 }
    1205             :             }
    1206       10759 :         }
    1207             : 
    1208       10759 :         SvgStyleAttributes::~SvgStyleAttributes()
    1209             :         {
    1210       10759 :         }
    1211             : 
    1212       32907 :         void SvgStyleAttributes::parseStyleAttribute(const OUString& /*rTokenName*/, SVGToken aSVGToken, const OUString& aContent)
    1213             :         {
    1214       32907 :             switch(aSVGToken)
    1215             :             {
    1216             :                 case SVGTokenFill:
    1217             :                 {
    1218        2861 :                     SvgPaint aSvgPaint;
    1219        5722 :                     OUString aURL;
    1220             : 
    1221        2861 :                     if(readSvgPaint(aContent, aSvgPaint, aURL))
    1222             :                     {
    1223        1578 :                         setFill(aSvgPaint);
    1224             :                     }
    1225        1283 :                     else if(!aURL.isEmpty())
    1226             :                     {
    1227        1283 :                         const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL);
    1228             : 
    1229        1283 :                         if(pNode)
    1230             :                         {
    1231        1283 :                             if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient == pNode->getType())
    1232             :                             {
    1233        1283 :                                 setSvgGradientNodeFill(static_cast< const SvgGradientNode* >(pNode));
    1234             :                             }
    1235           0 :                             else if(SVGTokenPattern == pNode->getType())
    1236             :                             {
    1237           0 :                                 setSvgPatternNodeFill(static_cast< const SvgPatternNode* >(pNode));
    1238             :                             }
    1239             :                         }
    1240             :                     }
    1241        5722 :                     break;
    1242             :                 }
    1243             :                 case SVGTokenFillOpacity:
    1244             :                 {
    1245           1 :                     SvgNumber aNum;
    1246             : 
    1247           1 :                     if(readSingleNumber(aContent, aNum))
    1248             :                     {
    1249           1 :                         if(aNum.isPositive())
    1250             :                         {
    1251           1 :                             setFillOpacity(aNum);
    1252             :                         }
    1253             :                     }
    1254           1 :                     break;
    1255             :                 }
    1256             :                 case SVGTokenFillRule:
    1257             :                 {
    1258          21 :                     if(!aContent.isEmpty())
    1259             :                     {
    1260          21 :                         if(aContent.match(commonStrings::aStrNonzero))
    1261             :                         {
    1262           0 :                             maFillRule = FillRule_nonzero;
    1263             :                         }
    1264          21 :                         else if(aContent.match(commonStrings::aStrEvenOdd))
    1265             :                         {
    1266          21 :                             maFillRule = FillRule_evenodd;
    1267             :                         }
    1268             :                     }
    1269          21 :                     break;
    1270             :                 }
    1271             :                 case SVGTokenStroke:
    1272             :                 {
    1273         226 :                     SvgPaint aSvgPaint;
    1274         452 :                     OUString aURL;
    1275             : 
    1276         226 :                     if(readSvgPaint(aContent, aSvgPaint, aURL))
    1277             :                     {
    1278         226 :                         setStroke(aSvgPaint);
    1279             :                     }
    1280           0 :                     else if(!aURL.isEmpty())
    1281             :                     {
    1282           0 :                         const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL);
    1283             : 
    1284           0 :                         if(pNode)
    1285             :                         {
    1286           0 :                             if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient  == pNode->getType())
    1287             :                             {
    1288           0 :                                 setSvgGradientNodeStroke(static_cast< const SvgGradientNode* >(pNode));
    1289             :                             }
    1290           0 :                             else if(SVGTokenPattern == pNode->getType())
    1291             :                             {
    1292           0 :                                 setSvgPatternNodeStroke(static_cast< const SvgPatternNode* >(pNode));
    1293             :                             }
    1294             :                         }
    1295             :                     }
    1296         452 :                     break;
    1297             :                 }
    1298             :                 case SVGTokenStrokeDasharray:
    1299             :                 {
    1300          15 :                     if(!aContent.isEmpty())
    1301             :                     {
    1302          15 :                         SvgNumberVector aVector;
    1303             : 
    1304          15 :                         if(aContent.startsWith("none"))
    1305             :                         {
    1306             :                             // #121221# The special value 'none' needs to be handled
    1307             :                             // in the sense that *when* it is set, the parent shall not
    1308             :                             // be used. Before this was only dependent on the array being
    1309             :                             // empty
    1310           0 :                             setStrokeDasharraySet(true);
    1311             :                         }
    1312          15 :                         else if(readSvgNumberVector(aContent, aVector))
    1313             :                         {
    1314          15 :                             setStrokeDasharray(aVector);
    1315          15 :                         }
    1316             :                     }
    1317          15 :                     break;
    1318             :                 }
    1319             :                 case SVGTokenStrokeDashoffset:
    1320             :                 {
    1321           0 :                     SvgNumber aNum;
    1322             : 
    1323           0 :                     if(readSingleNumber(aContent, aNum))
    1324             :                     {
    1325           0 :                         if(aNum.isPositive())
    1326             :                         {
    1327           0 :                             setStrokeDashOffset(aNum);
    1328             :                         }
    1329             :                     }
    1330           0 :                     break;
    1331             :                 }
    1332             :                 case SVGTokenStrokeLinecap:
    1333             :                 {
    1334          38 :                     if(!aContent.isEmpty())
    1335             :                     {
    1336          38 :                         if(aContent.startsWith("butt"))
    1337             :                         {
    1338           0 :                             setStrokeLinecap(StrokeLinecap_butt);
    1339             :                         }
    1340          38 :                         else if(aContent.startsWith("round"))
    1341             :                         {
    1342          38 :                             setStrokeLinecap(StrokeLinecap_round);
    1343             :                         }
    1344           0 :                         else if(aContent.startsWith("square"))
    1345             :                         {
    1346           0 :                             setStrokeLinecap(StrokeLinecap_square);
    1347             :                         }
    1348             :                     }
    1349          38 :                     break;
    1350             :                 }
    1351             :                 case SVGTokenStrokeLinejoin:
    1352             :                 {
    1353          30 :                     if(!aContent.isEmpty())
    1354             :                     {
    1355          30 :                         if(aContent.startsWith("miter"))
    1356             :                         {
    1357           0 :                             setStrokeLinejoin(StrokeLinejoin_miter);
    1358             :                         }
    1359          30 :                         else if(aContent.startsWith("round"))
    1360             :                         {
    1361          30 :                             setStrokeLinejoin(StrokeLinejoin_round);
    1362             :                         }
    1363           0 :                         else if(aContent.startsWith("bevel"))
    1364             :                         {
    1365           0 :                             setStrokeLinejoin(StrokeLinejoin_bevel);
    1366             :                         }
    1367             :                     }
    1368          30 :                     break;
    1369             :                 }
    1370             :                 case SVGTokenStrokeMiterlimit:
    1371             :                 {
    1372           0 :                     SvgNumber aNum;
    1373             : 
    1374           0 :                     if(readSingleNumber(aContent, aNum))
    1375             :                     {
    1376           0 :                         if(aNum.isPositive())
    1377             :                         {
    1378           0 :                             setStrokeMiterLimit(aNum);
    1379             :                         }
    1380             :                     }
    1381           0 :                     break;
    1382             :                 }
    1383             :                 case SVGTokenStrokeOpacity:
    1384             :                 {
    1385           0 :                     SvgNumber aNum;
    1386             : 
    1387           0 :                     if(readSingleNumber(aContent, aNum))
    1388             :                     {
    1389           0 :                         if(aNum.isPositive())
    1390             :                         {
    1391           0 :                             setStrokeOpacity(aNum);
    1392             :                         }
    1393             :                     }
    1394           0 :                     break;
    1395             :                 }
    1396             :                 case SVGTokenStrokeWidth:
    1397             :                 {
    1398         212 :                     SvgNumber aNum;
    1399             : 
    1400         212 :                     if(readSingleNumber(aContent, aNum))
    1401             :                     {
    1402         212 :                         if(aNum.isPositive())
    1403             :                         {
    1404         212 :                             setStrokeWidth(aNum);
    1405             :                         }
    1406             :                     }
    1407         212 :                     break;
    1408             :                 }
    1409             :                 case SVGTokenStopColor:
    1410             :                 {
    1411        3433 :                     SvgPaint aSvgPaint;
    1412        6866 :                     OUString aURL;
    1413             : 
    1414        3433 :                     if(readSvgPaint(aContent, aSvgPaint, aURL))
    1415             :                     {
    1416        3433 :                         setStopColor(aSvgPaint);
    1417             :                     }
    1418        6866 :                     break;
    1419             :                 }
    1420             :                 case SVGTokenStopOpacity:
    1421             :                 {
    1422           0 :                     SvgNumber aNum;
    1423             : 
    1424           0 :                     if(readSingleNumber(aContent, aNum))
    1425             :                     {
    1426           0 :                         if(aNum.isPositive())
    1427             :                         {
    1428           0 :                             setStopOpacity(aNum);
    1429             :                         }
    1430             :                     }
    1431           0 :                     break;
    1432             :                 }
    1433             :                 case SVGTokenFont:
    1434             :                 {
    1435           0 :                     break;
    1436             :                 }
    1437             :                 case SVGTokenFontFamily:
    1438             :                 {
    1439           0 :                     SvgStringVector aSvgStringVector;
    1440             : 
    1441           0 :                     if(readSvgStringVector(aContent, aSvgStringVector))
    1442             :                     {
    1443           0 :                         setFontFamily(aSvgStringVector);
    1444             :                     }
    1445           0 :                     break;
    1446             :                 }
    1447             :                 case SVGTokenFontSize:
    1448             :                 {
    1449           0 :                     SvgNumber aNum;
    1450             : 
    1451           0 :                     if(readSingleNumber(aContent, aNum))
    1452             :                     {
    1453           0 :                         setFontSize(aNum);
    1454             :                     }
    1455           0 :                     break;
    1456             :                 }
    1457             :                 case SVGTokenFontSizeAdjust:
    1458             :                 {
    1459           0 :                     break;
    1460             :                 }
    1461             :                 case SVGTokenFontStretch:
    1462             :                 {
    1463           0 :                     if(!aContent.isEmpty())
    1464             :                     {
    1465           0 :                         if(aContent.startsWith("normal"))
    1466             :                         {
    1467           0 :                             setFontStretch(FontStretch_normal);
    1468             :                         }
    1469           0 :                         else if(aContent.startsWith("wider"))
    1470             :                         {
    1471           0 :                             setFontStretch(FontStretch_wider);
    1472             :                         }
    1473           0 :                         else if(aContent.startsWith("narrower"))
    1474             :                         {
    1475           0 :                             setFontStretch(FontStretch_narrower);
    1476             :                         }
    1477           0 :                         else if(aContent.startsWith("ultra-condensed"))
    1478             :                         {
    1479           0 :                             setFontStretch(FontStretch_ultra_condensed);
    1480             :                         }
    1481           0 :                         else if(aContent.startsWith("extra-condensed"))
    1482             :                         {
    1483           0 :                             setFontStretch(FontStretch_extra_condensed);
    1484             :                         }
    1485           0 :                         else if(aContent.startsWith("condensed"))
    1486             :                         {
    1487           0 :                             setFontStretch(FontStretch_condensed);
    1488             :                         }
    1489           0 :                         else if(aContent.startsWith("semi-condensed"))
    1490             :                         {
    1491           0 :                             setFontStretch(FontStretch_semi_condensed);
    1492             :                         }
    1493           0 :                         else if(aContent.startsWith("semi-expanded"))
    1494             :                         {
    1495           0 :                             setFontStretch(FontStretch_semi_expanded);
    1496             :                         }
    1497           0 :                         else if(aContent.startsWith("expanded"))
    1498             :                         {
    1499           0 :                             setFontStretch(FontStretch_expanded);
    1500             :                         }
    1501           0 :                         else if(aContent.startsWith("extra-expanded"))
    1502             :                         {
    1503           0 :                             setFontStretch(FontStretch_extra_expanded);
    1504             :                         }
    1505           0 :                         else if(aContent.startsWith("ultra-expanded"))
    1506             :                         {
    1507           0 :                             setFontStretch(FontStretch_ultra_expanded);
    1508             :                         }
    1509             :                     }
    1510           0 :                     break;
    1511             :                 }
    1512             :                 case SVGTokenFontStyle:
    1513             :                 {
    1514           0 :                     if(!aContent.isEmpty())
    1515             :                     {
    1516           0 :                         if(aContent.startsWith("normal"))
    1517             :                         {
    1518           0 :                             setFontStyle(FontStyle_normal);
    1519             :                         }
    1520           0 :                         else if(aContent.startsWith("italic"))
    1521             :                         {
    1522           0 :                             setFontStyle(FontStyle_italic);
    1523             :                         }
    1524           0 :                         else if(aContent.startsWith("oblique"))
    1525             :                         {
    1526           0 :                             setFontStyle(FontStyle_oblique);
    1527             :                         }
    1528             :                     }
    1529           0 :                     break;
    1530             :                 }
    1531             :                 case SVGTokenFontVariant:
    1532             :                 {
    1533           0 :                     if(!aContent.isEmpty())
    1534             :                     {
    1535           0 :                         if(aContent.startsWith("normal"))
    1536             :                         {
    1537           0 :                             setFontVariant(FontVariant_normal);
    1538             :                         }
    1539           0 :                         else if(aContent.startsWith("small-caps"))
    1540             :                         {
    1541           0 :                             setFontVariant(FontVariant_small_caps);
    1542             :                         }
    1543             :                     }
    1544           0 :                     break;
    1545             :                 }
    1546             :                 case SVGTokenFontWeight:
    1547             :                 {
    1548           0 :                     if(!aContent.isEmpty())
    1549             :                     {
    1550           0 :                         if(aContent.startsWith("100"))
    1551             :                         {
    1552           0 :                             setFontWeight(FontWeight_100);
    1553             :                         }
    1554           0 :                         else if(aContent.startsWith("200"))
    1555             :                         {
    1556           0 :                             setFontWeight(FontWeight_200);
    1557             :                         }
    1558           0 :                         else if(aContent.startsWith("300"))
    1559             :                         {
    1560           0 :                             setFontWeight(FontWeight_300);
    1561             :                         }
    1562           0 :                         else if(aContent.startsWith("400") || aContent.startsWith("normal"))
    1563             :                         {
    1564           0 :                             setFontWeight(FontWeight_400);
    1565             :                         }
    1566           0 :                         else if(aContent.startsWith("500"))
    1567             :                         {
    1568           0 :                             setFontWeight(FontWeight_500);
    1569             :                         }
    1570           0 :                         else if(aContent.startsWith("600"))
    1571             :                         {
    1572           0 :                             setFontWeight(FontWeight_600);
    1573             :                         }
    1574           0 :                         else if(aContent.startsWith("700") || aContent.startsWith("bold"))
    1575             :                         {
    1576           0 :                             setFontWeight(FontWeight_700);
    1577             :                         }
    1578           0 :                         else if(aContent.startsWith("800"))
    1579             :                         {
    1580           0 :                             setFontWeight(FontWeight_800);
    1581             :                         }
    1582           0 :                         else if(aContent.startsWith("900"))
    1583             :                         {
    1584           0 :                             setFontWeight(FontWeight_900);
    1585             :                         }
    1586           0 :                         else if(aContent.startsWith("bolder"))
    1587             :                         {
    1588           0 :                             setFontWeight(FontWeight_bolder);
    1589             :                         }
    1590           0 :                         else if(aContent.startsWith("lighter"))
    1591             :                         {
    1592           0 :                             setFontWeight(FontWeight_lighter);
    1593             :                         }
    1594             :                     }
    1595           0 :                     break;
    1596             :                 }
    1597             :                 case SVGTokenDirection:
    1598             :                 {
    1599           0 :                     break;
    1600             :                 }
    1601             :                 case SVGTokenLetterSpacing:
    1602             :                 {
    1603           0 :                     break;
    1604             :                 }
    1605             :                 case SVGTokenTextDecoration:
    1606             :                 {
    1607           0 :                     if(!aContent.isEmpty())
    1608             :                     {
    1609           0 :                         if(aContent.startsWith("none"))
    1610             :                         {
    1611           0 :                             setTextDecoration(TextDecoration_none);
    1612             :                         }
    1613           0 :                         else if(aContent.startsWith("underline"))
    1614             :                         {
    1615           0 :                             setTextDecoration(TextDecoration_underline);
    1616             :                         }
    1617           0 :                         else if(aContent.startsWith("overline"))
    1618             :                         {
    1619           0 :                             setTextDecoration(TextDecoration_overline);
    1620             :                         }
    1621           0 :                         else if(aContent.startsWith("line-through"))
    1622             :                         {
    1623           0 :                             setTextDecoration(TextDecoration_line_through);
    1624             :                         }
    1625           0 :                         else if(aContent.startsWith("blink"))
    1626             :                         {
    1627           0 :                             setTextDecoration(TextDecoration_blink);
    1628             :                         }
    1629             :                     }
    1630           0 :                     break;
    1631             :                 }
    1632             :                 case SVGTokenUnicodeBidi:
    1633             :                 {
    1634           0 :                     break;
    1635             :                 }
    1636             :                 case SVGTokenWordSpacing:
    1637             :                 {
    1638           0 :                     break;
    1639             :                 }
    1640             :                 case SVGTokenTextAnchor:
    1641             :                 {
    1642           0 :                     if(!aContent.isEmpty())
    1643             :                     {
    1644           0 :                         if(aContent.startsWith("start"))
    1645             :                         {
    1646           0 :                             setTextAnchor(TextAnchor_start);
    1647             :                         }
    1648           0 :                         else if(aContent.startsWith("middle"))
    1649             :                         {
    1650           0 :                             setTextAnchor(TextAnchor_middle);
    1651             :                         }
    1652           0 :                         else if(aContent.startsWith("end"))
    1653             :                         {
    1654           0 :                             setTextAnchor(TextAnchor_end);
    1655             :                         }
    1656             :                     }
    1657           0 :                     break;
    1658             :                 }
    1659             :                 case SVGTokenTextAlign:
    1660             :                 {
    1661           0 :                     if(!aContent.isEmpty())
    1662             :                     {
    1663           0 :                         if(aContent.startsWith("left"))
    1664             :                         {
    1665           0 :                             setTextAlign(TextAlign_left);
    1666             :                         }
    1667           0 :                         else if(aContent.startsWith("right"))
    1668             :                         {
    1669           0 :                             setTextAlign(TextAlign_right);
    1670             :                         }
    1671           0 :                         else if(aContent.startsWith("center"))
    1672             :                         {
    1673           0 :                             setTextAlign(TextAlign_center);
    1674             :                         }
    1675           0 :                         else if(aContent.startsWith("justify"))
    1676             :                         {
    1677           0 :                             setTextAlign(TextAlign_justify);
    1678             :                         }
    1679             :                     }
    1680           0 :                     break;
    1681             :                 }
    1682             :                 case SVGTokenColor:
    1683             :                 {
    1684           0 :                     SvgPaint aSvgPaint;
    1685           0 :                     OUString aURL;
    1686             : 
    1687           0 :                     if(readSvgPaint(aContent, aSvgPaint, aURL))
    1688             :                     {
    1689           0 :                         setColor(aSvgPaint);
    1690             :                     }
    1691           0 :                     break;
    1692             :                 }
    1693             :                 case SVGTokenOpacity:
    1694             :                 {
    1695         719 :                     SvgNumber aNum;
    1696             : 
    1697         719 :                     if(readSingleNumber(aContent, aNum))
    1698             :                     {
    1699         719 :                         setOpacity(SvgNumber(basegfx::clamp(aNum.getNumber(), 0.0, 1.0), aNum.getUnit(), aNum.isSet()));
    1700             :                     }
    1701         719 :                     break;
    1702             :                 }
    1703             :                 case SVGTokenTitle:
    1704             :                 {
    1705           0 :                     setTitle(aContent);
    1706           0 :                     break;
    1707             :                 }
    1708             :                 case SVGTokenDesc:
    1709             :                 {
    1710           0 :                     setDesc(aContent);
    1711           0 :                     break;
    1712             :                 }
    1713             :                 case SVGTokenClipPathProperty:
    1714             :                 {
    1715         156 :                     readLocalUrl(aContent, maClipPathXLink);
    1716         156 :                     break;
    1717             :                 }
    1718             :                 case SVGTokenMask:
    1719             :                 {
    1720         171 :                     readLocalUrl(aContent, maMaskXLink);
    1721         171 :                     break;
    1722             :                 }
    1723             :                 case SVGTokenClipRule:
    1724             :                 {
    1725          21 :                     if(!aContent.isEmpty())
    1726             :                     {
    1727          21 :                         if(aContent.match(commonStrings::aStrNonzero))
    1728             :                         {
    1729           0 :                             maClipRule = FillRule_nonzero;
    1730             :                         }
    1731          21 :                         else if(aContent.match(commonStrings::aStrEvenOdd))
    1732             :                         {
    1733          21 :                             maClipRule = FillRule_evenodd;
    1734             :                         }
    1735             :                     }
    1736          21 :                     break;
    1737             :                 }
    1738             :                 case SVGTokenMarker:
    1739             :                 {
    1740           0 :                     readLocalUrl(aContent, maMarkerEndXLink);
    1741           0 :                     maMarkerStartXLink = maMarkerMidXLink = maMarkerEndXLink;
    1742           0 :                     break;
    1743             :                 }
    1744             :                 case SVGTokenMarkerStart:
    1745             :                 {
    1746           0 :                     readLocalUrl(aContent, maMarkerStartXLink);
    1747           0 :                     break;
    1748             :                 }
    1749             :                 case SVGTokenMarkerMid:
    1750             :                 {
    1751           0 :                     readLocalUrl(aContent, maMarkerMidXLink);
    1752           0 :                     break;
    1753             :                 }
    1754             :                 case SVGTokenMarkerEnd:
    1755             :                 {
    1756           0 :                     readLocalUrl(aContent, maMarkerEndXLink);
    1757           0 :                     break;
    1758             :                 }
    1759             :                 case SVGTokenDisplay:
    1760             :                 {
    1761             :                     // There may be display:none statements inside of style defines, e.g. the following line:
    1762             :                     // style="display:none"
    1763             :                     // taken from a svg example; this needs to be parsed and set at the owning node. Do not call
    1764             :                     // mrOwner.parseAttribute(...) here, this would lead to a recursion
    1765           0 :                     if(!aContent.isEmpty())
    1766             :                     {
    1767           0 :                         mrOwner.setDisplay(getDisplayFromContent(aContent));
    1768             :                     }
    1769           0 :                     break;
    1770             :                 }
    1771             :                 case SVGTokenBaselineShift:
    1772             :                 {
    1773           0 :                     if(!aContent.isEmpty())
    1774             :                     {
    1775           0 :                         SvgNumber aNum;
    1776             : 
    1777           0 :                         if(aContent.startsWith("sub"))
    1778             :                         {
    1779           0 :                             setBaselineShift(BaselineShift_Sub);
    1780             :                         }
    1781           0 :                         else if(aContent.startsWith("super"))
    1782             :                         {
    1783           0 :                             setBaselineShift(BaselineShift_Super);
    1784             :                         }
    1785           0 :                         else if(readSingleNumber(aContent, aNum))
    1786             :                         {
    1787           0 :                             setBaselineShiftNumber(aNum);
    1788             : 
    1789           0 :                             if(Unit_percent == aNum.getUnit())
    1790             :                             {
    1791           0 :                                 setBaselineShift(BaselineShift_Percentage);
    1792             :                             }
    1793             :                             else
    1794             :                             {
    1795           0 :                                 setBaselineShift(BaselineShift_Length);
    1796             :                             }
    1797             :                         }
    1798             :                         else
    1799             :                         {
    1800             :                             // no BaselineShift or inherit (which is automatically)
    1801           0 :                             setBaselineShift(BaselineShift_Baseline);
    1802             :                         }
    1803             :                     }
    1804           0 :                     break;
    1805             :                 }
    1806             :                 default:
    1807             :                 {
    1808       25003 :                     break;
    1809             :                 }
    1810             :             }
    1811       32907 :         }
    1812             : 
    1813        7323 :         const basegfx::BColor* SvgStyleAttributes::getFill() const
    1814             :         {
    1815        7323 :             if(mbIsClipPathContent)
    1816             :             {
    1817         156 :                 static basegfx::BColor aBlack(0.0, 0.0, 0.0);
    1818             : 
    1819         156 :                 return &aBlack;
    1820             :             }
    1821        7167 :             else if(maFill.isSet())
    1822             :             {
    1823        2818 :                 if(maFill.isCurrent())
    1824             :                 {
    1825           0 :                     return getColor();
    1826             :                 }
    1827        2818 :                 else if(maFill.isOn())
    1828             :                 {
    1829        2732 :                     return &maFill.getBColor();
    1830             :                 }
    1831             :             }
    1832             :             else
    1833             :             {
    1834        4349 :                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    1835             : 
    1836        4349 :                 if(pSvgStyleAttributes)
    1837             :                 {
    1838        4349 :                     return pSvgStyleAttributes->getFill();
    1839             :                 }
    1840             :             }
    1841             : 
    1842          86 :             return 0;
    1843             :         }
    1844             : 
    1845       11734 :         const basegfx::BColor* SvgStyleAttributes::getStroke() const
    1846             :         {
    1847       11734 :             if(mbIsClipPathContent)
    1848             :             {
    1849         156 :                 return 0;
    1850             :             }
    1851       11578 :             else if(maStroke.isSet())
    1852             :             {
    1853         226 :                 if(maStroke.isCurrent())
    1854             :                 {
    1855           0 :                     return getColor();
    1856             :                 }
    1857         226 :                 else if(maStroke.isOn())
    1858             :                 {
    1859         226 :                     return &maStroke.getBColor();
    1860             :                 }
    1861             :             }
    1862             :             else
    1863             :             {
    1864       11352 :                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    1865             : 
    1866       11352 :                 if(pSvgStyleAttributes)
    1867             :                 {
    1868        8741 :                     return pSvgStyleAttributes->getStroke();
    1869             :                 }
    1870             :             }
    1871             : 
    1872        2611 :             return 0;
    1873             :         }
    1874             : 
    1875        3319 :         const basegfx::BColor& SvgStyleAttributes::getStopColor() const
    1876             :         {
    1877        3319 :             if(maStopColor.isCurrent())
    1878             :             {
    1879           0 :                 return *getColor();
    1880             :             }
    1881             :             else
    1882             :             {
    1883        3319 :                 return maStopColor.getBColor();
    1884             :             }
    1885             :         }
    1886             : 
    1887        8139 :         const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeFill() const
    1888             :         {
    1889        8139 :             if(mbIsClipPathContent)
    1890             :             {
    1891         156 :                 return 0;
    1892             :             }
    1893        7983 :             else if(mpSvgGradientNodeFill)
    1894             :             {
    1895        1247 :                 return mpSvgGradientNodeFill;
    1896             :             }
    1897             :             else
    1898             :             {
    1899        6736 :                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    1900             : 
    1901        6736 :                 if(pSvgStyleAttributes)
    1902             :                 {
    1903        5165 :                     return pSvgStyleAttributes->getSvgGradientNodeFill();
    1904             :                 }
    1905             :             }
    1906             : 
    1907        1571 :             return 0;
    1908             :         }
    1909             : 
    1910       12344 :         const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeStroke() const
    1911             :         {
    1912       12344 :             if(mbIsClipPathContent)
    1913             :             {
    1914         156 :                 return 0;
    1915             :             }
    1916       12188 :             else if(mpSvgGradientNodeStroke)
    1917             :             {
    1918           0 :                 return mpSvgGradientNodeStroke;
    1919             :             }
    1920             :             else
    1921             :             {
    1922       12188 :                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    1923             : 
    1924       12188 :                 if(pSvgStyleAttributes)
    1925             :                 {
    1926        9351 :                     return pSvgStyleAttributes->getSvgGradientNodeStroke();
    1927             :                 }
    1928             :             }
    1929             : 
    1930        2837 :             return 0;
    1931             :         }
    1932             : 
    1933       12259 :         const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeFill() const
    1934             :         {
    1935       12259 :             if(mbIsClipPathContent)
    1936             :             {
    1937         156 :                 return 0;
    1938             :             }
    1939       12103 :             else if(mpSvgPatternNodeFill)
    1940             :             {
    1941           0 :                 return mpSvgPatternNodeFill;
    1942             :             }
    1943             :             else
    1944             :             {
    1945       12103 :                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    1946             : 
    1947       12103 :                 if(pSvgStyleAttributes)
    1948             :                 {
    1949        9285 :                     return pSvgStyleAttributes->getSvgPatternNodeFill();
    1950             :                 }
    1951             :             }
    1952             : 
    1953        2818 :             return 0;
    1954             :         }
    1955             : 
    1956       12344 :         const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeStroke() const
    1957             :         {
    1958       12344 :             if(mbIsClipPathContent)
    1959             :             {
    1960         156 :                 return 0;
    1961             :             }
    1962       12188 :             else if(mpSvgPatternNodeStroke)
    1963             :             {
    1964           0 :                 return mpSvgPatternNodeStroke;
    1965             :             }
    1966             :             else
    1967             :             {
    1968       12188 :                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    1969             : 
    1970       12188 :                 if(pSvgStyleAttributes)
    1971             :                 {
    1972        9351 :                     return pSvgStyleAttributes->getSvgPatternNodeStroke();
    1973             :                 }
    1974             :             }
    1975             : 
    1976        2837 :             return 0;
    1977             :         }
    1978             : 
    1979         508 :         SvgNumber SvgStyleAttributes::getStrokeWidth() const
    1980             :         {
    1981         508 :             if(mbIsClipPathContent)
    1982             :             {
    1983           0 :                 return SvgNumber(0.0);
    1984             :             }
    1985         508 :             else if(maStrokeWidth.isSet())
    1986             :             {
    1987         424 :                 return maStrokeWidth;
    1988             :             }
    1989             : 
    1990          84 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    1991             : 
    1992          84 :             if(pSvgStyleAttributes)
    1993             :             {
    1994          56 :                 return pSvgStyleAttributes->getStrokeWidth();
    1995             :             }
    1996             : 
    1997             :             // default is 1
    1998          28 :             return SvgNumber(1.0);
    1999             :         }
    2000             : 
    2001        3319 :         SvgNumber SvgStyleAttributes::getStopOpacity() const
    2002             :         {
    2003        3319 :             if(maStopOpacity.isSet())
    2004             :             {
    2005           0 :                 return maStopOpacity;
    2006             :             }
    2007             : 
    2008             :             // default is 1
    2009        3319 :             return SvgNumber(1.0);
    2010             :         }
    2011             : 
    2012       11998 :         SvgNumber SvgStyleAttributes::getFillOpacity() const
    2013             :         {
    2014       11998 :             if(mbIsClipPathContent)
    2015             :             {
    2016         156 :                 return SvgNumber(1.0);
    2017             :             }
    2018       11842 :             else if(maFillOpacity.isSet())
    2019             :             {
    2020           1 :                 return maFillOpacity;
    2021             :             }
    2022             : 
    2023       11841 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2024             : 
    2025       11841 :             if(pSvgStyleAttributes)
    2026             :             {
    2027        9110 :                 return pSvgStyleAttributes->getFillOpacity();
    2028             :             }
    2029             : 
    2030             :             // default is 1
    2031        2731 :             return SvgNumber(1.0);
    2032             :         }
    2033             : 
    2034       10727 :         FillRule SvgStyleAttributes::getFillRule() const
    2035             :         {
    2036       10727 :             if(FillRule_notset != maFillRule)
    2037             :             {
    2038          21 :                 return maFillRule;
    2039             :             }
    2040             : 
    2041       10706 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2042             : 
    2043       10706 :             if(pSvgStyleAttributes)
    2044             :             {
    2045        8223 :                 return pSvgStyleAttributes->getFillRule();
    2046             :             }
    2047             : 
    2048             :             // default is NonZero
    2049        2483 :             return FillRule_nonzero;
    2050             :         }
    2051             : 
    2052         816 :         const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const
    2053             :         {
    2054         816 :             if(!maStrokeDasharray.empty())
    2055             :             {
    2056          30 :                 return maStrokeDasharray;
    2057             :             }
    2058         786 :             else if(getStrokeDasharraySet())
    2059             :             {
    2060             :                 // #121221# is set to empty *by purpose*, do not visit parent styles
    2061           0 :                 return maStrokeDasharray;
    2062             :             }
    2063             : 
    2064         786 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2065             : 
    2066         786 :             if(pSvgStyleAttributes)
    2067             :             {
    2068         575 :                 return pSvgStyleAttributes->getStrokeDasharray();
    2069             :             }
    2070             : 
    2071             :             // default empty
    2072         211 :             return maStrokeDasharray;
    2073             :         }
    2074             : 
    2075           0 :         SvgNumber SvgStyleAttributes::getStrokeDashOffset() const
    2076             :         {
    2077           0 :             if(maStrokeDashOffset.isSet())
    2078             :             {
    2079           0 :                 return maStrokeDashOffset;
    2080             :             }
    2081             : 
    2082           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2083             : 
    2084           0 :             if(pSvgStyleAttributes)
    2085             :             {
    2086           0 :                 return pSvgStyleAttributes->getStrokeDashOffset();
    2087             :             }
    2088             : 
    2089             :             // default is 0
    2090           0 :             return SvgNumber(0.0);
    2091             :         }
    2092             : 
    2093         731 :         StrokeLinecap SvgStyleAttributes::getStrokeLinecap() const
    2094             :         {
    2095         731 :             if(maStrokeLinecap != StrokeLinecap_notset)
    2096             :             {
    2097          38 :                 return maStrokeLinecap;
    2098             :             }
    2099             : 
    2100         693 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2101             : 
    2102         693 :             if(pSvgStyleAttributes)
    2103             :             {
    2104         505 :                 return pSvgStyleAttributes->getStrokeLinecap();
    2105             :             }
    2106             : 
    2107             :             // default is StrokeLinecap_butt
    2108         188 :             return StrokeLinecap_butt;
    2109             :         }
    2110             : 
    2111         754 :         StrokeLinejoin SvgStyleAttributes::getStrokeLinejoin() const
    2112             :         {
    2113         754 :             if(maStrokeLinejoin != StrokeLinejoin_notset)
    2114             :             {
    2115          30 :                 return maStrokeLinejoin;
    2116             :             }
    2117             : 
    2118         724 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2119             : 
    2120         724 :             if(pSvgStyleAttributes)
    2121             :             {
    2122         528 :                 return pSvgStyleAttributes->getStrokeLinejoin();
    2123             :             }
    2124             : 
    2125             :             // default is StrokeLinejoin_butt
    2126         196 :             return StrokeLinejoin_miter;
    2127             :         }
    2128             : 
    2129           0 :         SvgNumber SvgStyleAttributes::getStrokeMiterLimit() const
    2130             :         {
    2131           0 :             if(maStrokeMiterLimit.isSet())
    2132             :             {
    2133           0 :                 return maStrokeMiterLimit;
    2134             :             }
    2135             : 
    2136           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2137             : 
    2138           0 :             if(pSvgStyleAttributes)
    2139             :             {
    2140           0 :                 return pSvgStyleAttributes->getStrokeMiterLimit();
    2141             :             }
    2142             : 
    2143             :             // default is 4
    2144           0 :             return SvgNumber(4.0);
    2145             :         }
    2146             : 
    2147         836 :         SvgNumber SvgStyleAttributes::getStrokeOpacity() const
    2148             :         {
    2149         836 :             if(maStrokeOpacity.isSet())
    2150             :             {
    2151           0 :                 return maStrokeOpacity;
    2152             :             }
    2153             : 
    2154         836 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2155             : 
    2156         836 :             if(pSvgStyleAttributes)
    2157             :             {
    2158         610 :                 return pSvgStyleAttributes->getStrokeOpacity();
    2159             :             }
    2160             : 
    2161             :             // default is 1
    2162         226 :             return SvgNumber(1.0);
    2163             :         }
    2164             : 
    2165           0 :         const SvgStringVector& SvgStyleAttributes::getFontFamily() const
    2166             :         {
    2167           0 :             if(!maFontFamily.empty())
    2168             :             {
    2169           0 :                 return maFontFamily;
    2170             :             }
    2171             : 
    2172           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2173             : 
    2174           0 :             if(pSvgStyleAttributes)
    2175             :             {
    2176           0 :                 return pSvgStyleAttributes->getFontFamily();
    2177             :             }
    2178             : 
    2179             :             // default is empty
    2180           0 :             return maFontFamily;
    2181             :         }
    2182             : 
    2183           0 :         SvgNumber SvgStyleAttributes::getFontSize() const
    2184             :         {
    2185           0 :             if(maFontSize.isSet())
    2186             :             {
    2187             :                 // #122524# Handle Unit_percent realtive to parent FontSize (see SVG1.1
    2188             :                 // spec 10.10 Font selection properties \91font-size\92, lastline (klick 'normative
    2189             :                 // definition of the property')
    2190           0 :                 if(Unit_percent == maFontSize.getUnit())
    2191             :                 {
    2192           0 :                     const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2193             : 
    2194           0 :                     if(pSvgStyleAttributes)
    2195             :                     {
    2196           0 :                         const SvgNumber aParentNumber = pSvgStyleAttributes->getFontSize();
    2197             : 
    2198             :                         return SvgNumber(
    2199           0 :                             aParentNumber.getNumber() * maFontSize.getNumber() * 0.01,
    2200             :                             aParentNumber.getUnit(),
    2201           0 :                             true);
    2202             :                     }
    2203             :                 }
    2204             : 
    2205           0 :                 return maFontSize;
    2206             :             }
    2207             : 
    2208           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2209             : 
    2210           0 :             if(pSvgStyleAttributes)
    2211             :             {
    2212           0 :                 return pSvgStyleAttributes->getFontSize();
    2213             :             }
    2214             : 
    2215             :             // default is 'medium'
    2216           0 :             return SvgNumber(12.0);
    2217             :         }
    2218             : 
    2219           0 :         FontStretch SvgStyleAttributes::getFontStretch() const
    2220             :         {
    2221           0 :             if(maFontStretch != FontStretch_notset)
    2222             :             {
    2223           0 :                 if(FontStretch_wider != maFontStretch && FontStretch_narrower != maFontStretch)
    2224             :                 {
    2225           0 :                     return maFontStretch;
    2226             :                 }
    2227             :             }
    2228             : 
    2229           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2230             : 
    2231           0 :             if(pSvgStyleAttributes)
    2232             :             {
    2233           0 :                 FontStretch aInherited = pSvgStyleAttributes->getFontStretch();
    2234             : 
    2235           0 :                 if(FontStretch_wider == maFontStretch)
    2236             :                 {
    2237           0 :                     aInherited = getWider(aInherited);
    2238             :                 }
    2239           0 :                 else if(FontStretch_narrower == maFontStretch)
    2240             :                 {
    2241           0 :                     aInherited = getNarrower(aInherited);
    2242             :                 }
    2243             : 
    2244           0 :                 return aInherited;
    2245             :             }
    2246             : 
    2247             :             // default is FontStretch_normal
    2248           0 :             return FontStretch_normal;
    2249             :         }
    2250             : 
    2251           0 :         FontStyle SvgStyleAttributes::getFontStyle() const
    2252             :         {
    2253           0 :             if(maFontStyle != FontStyle_notset)
    2254             :             {
    2255           0 :                 return maFontStyle;
    2256             :             }
    2257             : 
    2258           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2259             : 
    2260           0 :             if(pSvgStyleAttributes)
    2261             :             {
    2262           0 :                 return pSvgStyleAttributes->getFontStyle();
    2263             :             }
    2264             : 
    2265             :             // default is FontStyle_normal
    2266           0 :             return FontStyle_normal;
    2267             :         }
    2268             : 
    2269           0 :         FontWeight SvgStyleAttributes::getFontWeight() const
    2270             :         {
    2271           0 :             if(maFontWeight != FontWeight_notset)
    2272             :             {
    2273           0 :                 if(FontWeight_bolder != maFontWeight && FontWeight_lighter != maFontWeight)
    2274             :                 {
    2275           0 :                     return maFontWeight;
    2276             :                 }
    2277             :             }
    2278             : 
    2279           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2280             : 
    2281           0 :             if(pSvgStyleAttributes)
    2282             :             {
    2283           0 :                 FontWeight aInherited = pSvgStyleAttributes->getFontWeight();
    2284             : 
    2285           0 :                 if(FontWeight_bolder == maFontWeight)
    2286             :                 {
    2287           0 :                     aInherited = getBolder(aInherited);
    2288             :                 }
    2289           0 :                 else if(FontWeight_lighter == maFontWeight)
    2290             :                 {
    2291           0 :                     aInherited = getLighter(aInherited);
    2292             :                 }
    2293             : 
    2294           0 :                 return aInherited;
    2295             :             }
    2296             : 
    2297             :             // default is FontWeight_400 (FontWeight_normal)
    2298           0 :             return FontWeight_400;
    2299             :         }
    2300             : 
    2301           0 :         TextAlign SvgStyleAttributes::getTextAlign() const
    2302             :         {
    2303           0 :             if(maTextAlign != TextAlign_notset)
    2304             :             {
    2305           0 :                 return maTextAlign;
    2306             :             }
    2307             : 
    2308           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2309             : 
    2310           0 :             if(pSvgStyleAttributes)
    2311             :             {
    2312           0 :                 return pSvgStyleAttributes->getTextAlign();
    2313             :             }
    2314             : 
    2315             :             // default is TextAlign_left
    2316           0 :             return TextAlign_left;
    2317             :         }
    2318             : 
    2319           0 :         const SvgStyleAttributes* SvgStyleAttributes::getTextDecorationDefiningSvgStyleAttributes() const
    2320             :         {
    2321           0 :             if(maTextDecoration != TextDecoration_notset)
    2322             :             {
    2323           0 :                 return this;
    2324             :             }
    2325             : 
    2326           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2327             : 
    2328           0 :             if(pSvgStyleAttributes)
    2329             :             {
    2330           0 :                 return pSvgStyleAttributes->getTextDecorationDefiningSvgStyleAttributes();
    2331             :             }
    2332             : 
    2333             :             // default is 0
    2334           0 :             return 0;
    2335             :         }
    2336             : 
    2337           0 :         TextDecoration SvgStyleAttributes::getTextDecoration() const
    2338             :         {
    2339           0 :             const SvgStyleAttributes* pDefining = getTextDecorationDefiningSvgStyleAttributes();
    2340             : 
    2341           0 :             if(pDefining)
    2342             :             {
    2343           0 :                 return pDefining->maTextDecoration;
    2344             :             }
    2345             :             else
    2346             :             {
    2347             :                 // default is TextDecoration_none
    2348           0 :                 return TextDecoration_none;
    2349             :             }
    2350             :         }
    2351             : 
    2352           0 :         TextAnchor SvgStyleAttributes::getTextAnchor() const
    2353             :         {
    2354           0 :             if(maTextAnchor != TextAnchor_notset)
    2355             :             {
    2356           0 :                 return maTextAnchor;
    2357             :             }
    2358             : 
    2359           0 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2360             : 
    2361           0 :             if(pSvgStyleAttributes)
    2362             :             {
    2363           0 :                 return pSvgStyleAttributes->getTextAnchor();
    2364             :             }
    2365             : 
    2366             :             // default is TextAnchor_start
    2367           0 :             return TextAnchor_start;
    2368             :         }
    2369             : 
    2370           0 :         const basegfx::BColor* SvgStyleAttributes::getColor() const
    2371             :         {
    2372           0 :             if(maColor.isSet())
    2373             :             {
    2374           0 :                 if(maColor.isCurrent())
    2375             :                 {
    2376             :                     OSL_ENSURE(false, "Svg error: current color uses current color (!)");
    2377           0 :                     return 0;
    2378             :                 }
    2379           0 :                 else if(maColor.isOn())
    2380             :                 {
    2381           0 :                     return &maColor.getBColor();
    2382             :                 }
    2383             :             }
    2384             :             else
    2385             :             {
    2386           0 :                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2387             : 
    2388           0 :                 if(pSvgStyleAttributes)
    2389             :                 {
    2390           0 :                     return pSvgStyleAttributes->getColor();
    2391             :                 }
    2392             :             }
    2393             : 
    2394           0 :             return 0;
    2395             :         }
    2396             : 
    2397       10852 :         OUString SvgStyleAttributes::getMarkerStartXLink() const
    2398             :         {
    2399       10852 :             if(!maMarkerStartXLink.isEmpty())
    2400             :             {
    2401           0 :                 return maMarkerStartXLink;
    2402             :             }
    2403             : 
    2404       10852 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2405             : 
    2406       10852 :             if(pSvgStyleAttributes)
    2407             :             {
    2408        8329 :                 return pSvgStyleAttributes->getMarkerStartXLink();
    2409             :             }
    2410             : 
    2411        2523 :             return OUString();
    2412             :         }
    2413             : 
    2414        2523 :         const SvgMarkerNode* SvgStyleAttributes::accessMarkerStartXLink() const
    2415             :         {
    2416        2523 :             if(!mpMarkerStartXLink)
    2417             :             {
    2418        2523 :                 const OUString aMarker(getMarkerStartXLink());
    2419             : 
    2420        2523 :                 if(!aMarker.isEmpty())
    2421             :                 {
    2422           0 :                     const_cast< SvgStyleAttributes* >(this)->mpMarkerStartXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerStartXLink()));
    2423        2523 :                 }
    2424             :             }
    2425             : 
    2426        2523 :             return mpMarkerStartXLink;
    2427             :         }
    2428             : 
    2429       10852 :         OUString SvgStyleAttributes::getMarkerMidXLink() const
    2430             :         {
    2431       10852 :             if(!maMarkerMidXLink.isEmpty())
    2432             :             {
    2433           0 :                 return maMarkerMidXLink;
    2434             :             }
    2435             : 
    2436       10852 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2437             : 
    2438       10852 :             if(pSvgStyleAttributes)
    2439             :             {
    2440        8329 :                 return pSvgStyleAttributes->getMarkerMidXLink();
    2441             :             }
    2442             : 
    2443        2523 :             return OUString();
    2444             :         }
    2445             : 
    2446        2523 :         const SvgMarkerNode* SvgStyleAttributes::accessMarkerMidXLink() const
    2447             :         {
    2448        2523 :             if(!mpMarkerMidXLink)
    2449             :             {
    2450        2523 :                 const OUString aMarker(getMarkerMidXLink());
    2451             : 
    2452        2523 :                 if(!aMarker.isEmpty())
    2453             :                 {
    2454           0 :                     const_cast< SvgStyleAttributes* >(this)->mpMarkerMidXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerMidXLink()));
    2455        2523 :                 }
    2456             :             }
    2457             : 
    2458        2523 :             return mpMarkerMidXLink;
    2459             :         }
    2460             : 
    2461       10852 :         OUString SvgStyleAttributes::getMarkerEndXLink() const
    2462             :         {
    2463       10852 :             if(!maMarkerEndXLink.isEmpty())
    2464             :             {
    2465           0 :                 return maMarkerEndXLink;
    2466             :             }
    2467             : 
    2468       10852 :             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2469             : 
    2470       10852 :             if(pSvgStyleAttributes)
    2471             :             {
    2472        8329 :                 return pSvgStyleAttributes->getMarkerEndXLink();
    2473             :             }
    2474             : 
    2475        2523 :             return OUString();
    2476             :         }
    2477             : 
    2478        2523 :         const SvgMarkerNode* SvgStyleAttributes::accessMarkerEndXLink() const
    2479             :         {
    2480        2523 :             if(!mpMarkerEndXLink)
    2481             :             {
    2482        2523 :                 const OUString aMarker(getMarkerEndXLink());
    2483             : 
    2484        2523 :                 if(!aMarker.isEmpty())
    2485             :                 {
    2486           0 :                     const_cast< SvgStyleAttributes* >(this)->mpMarkerEndXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerEndXLink()));
    2487        2523 :                 }
    2488             :             }
    2489             : 
    2490        2523 :             return mpMarkerEndXLink;
    2491             :         }
    2492             : 
    2493           0 :         SvgNumber SvgStyleAttributes::getBaselineShiftNumber() const
    2494             :         {
    2495             :             // #122524# Handle Unit_percent realtive to parent BaselineShift
    2496           0 :             if(Unit_percent == maBaselineShiftNumber.getUnit())
    2497             :             {
    2498           0 :                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
    2499             : 
    2500           0 :                 if(pSvgStyleAttributes)
    2501             :                 {
    2502           0 :                     const SvgNumber aParentNumber = pSvgStyleAttributes->getBaselineShiftNumber();
    2503             : 
    2504             :                     return SvgNumber(
    2505           0 :                         aParentNumber.getNumber() * maBaselineShiftNumber.getNumber() * 0.01,
    2506             :                         aParentNumber.getUnit(),
    2507           0 :                         true);
    2508             :                 }
    2509             :             }
    2510             : 
    2511           0 :             return maBaselineShiftNumber;
    2512             :         }
    2513             :     } // end of namespace svgreader
    2514             : } // end of namespace svgio
    2515             : 
    2516             : 
    2517             : // eof
    2518             : 
    2519             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10