LCOV - code coverage report
Current view: top level - svgio/source/svgreader - svgstyleattributes.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 420 1028 40.9 %
Date: 2015-06-13 12:38:46 Functions: 35 58 60.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11