LCOV - code coverage report
Current view: top level - drawinglayer/source/primitive2d - svggradientprimitive2d.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 193 429 45.0 %
Date: 2014-11-03 Functions: 27 40 67.5 %
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 <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
      21             : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
      22             : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
      23             : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
      24             : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
      25             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      26             : #include <basegfx/polygon/b2dpolygontools.hxx>
      27             : #include <basegfx/polygon/b2dpolygon.hxx>
      28             : #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
      29             : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
      30             : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
      31             : #include <drawinglayer/geometry/viewinformation2d.hxx>
      32             : 
      33             : 
      34             : 
      35             : using namespace com::sun::star;
      36             : 
      37             : 
      38             : 
      39             : namespace
      40             : {
      41           0 :     sal_uInt32 calculateStepsForSvgGradient(const basegfx::BColor& rColorA, const basegfx::BColor& rColorB, double fDelta, double fDiscreteUnit)
      42             :     {
      43             :         // use color distance, assume to do every color step (full quality)
      44           0 :         sal_uInt32 nSteps(basegfx::fround(rColorA.getDistance(rColorB) * 255.0));
      45             : 
      46           0 :         if(nSteps)
      47             :         {
      48             :             // calc discrete length to change color all 1.5 disctete units (pixels)
      49           0 :             const sal_uInt32 nDistSteps(basegfx::fround(fDelta / (fDiscreteUnit * 1.5)));
      50             : 
      51           0 :             nSteps = std::min(nSteps, nDistSteps);
      52             :         }
      53             : 
      54             :         // roughly cut when too big or too small
      55           0 :         nSteps = std::min(nSteps, sal_uInt32(255));
      56           0 :         nSteps = std::max(nSteps, sal_uInt32(1));
      57             : 
      58           0 :         return nSteps;
      59             :     }
      60             : } // end of anonymous namespace
      61             : 
      62             : 
      63             : 
      64             : namespace drawinglayer
      65             : {
      66             :     namespace primitive2d
      67             :     {
      68           0 :         Primitive2DSequence SvgGradientHelper::createSingleGradientEntryFill() const
      69             :         {
      70           0 :             const SvgGradientEntryVector& rEntries = getGradientEntries();
      71           0 :             const sal_uInt32 nCount(rEntries.size());
      72           0 :             Primitive2DSequence xRetval;
      73             : 
      74           0 :             if(nCount)
      75             :             {
      76           0 :                 const SvgGradientEntry& rSingleEntry = rEntries[nCount - 1];
      77           0 :                 const double fOpacity(rSingleEntry.getOpacity());
      78             : 
      79           0 :                 if(fOpacity > 0.0)
      80             :                 {
      81             :                     Primitive2DReference xRef(
      82             :                         new PolyPolygonColorPrimitive2D(
      83             :                             getPolyPolygon(),
      84           0 :                             rSingleEntry.getColor()));
      85             : 
      86           0 :                     if(fOpacity < 1.0)
      87             :                     {
      88           0 :                         const Primitive2DSequence aContent(&xRef, 1);
      89             : 
      90           0 :                         xRef = Primitive2DReference(
      91             :                             new UnifiedTransparencePrimitive2D(
      92             :                                 aContent,
      93           0 :                                 1.0 - fOpacity));
      94             :                     }
      95             : 
      96           0 :                     xRetval = Primitive2DSequence(&xRef, 1);
      97             :                 }
      98             :             }
      99             :             else
     100             :             {
     101             :                 OSL_ENSURE(false, "Single gradient entry construction without entry (!)");
     102             :             }
     103             : 
     104           0 :             return xRetval;
     105             :         }
     106             : 
     107        1244 :         void SvgGradientHelper::checkPreconditions()
     108             :         {
     109        1244 :             mbPreconditionsChecked = true;
     110        1244 :             const SvgGradientEntryVector& rEntries = getGradientEntries();
     111             : 
     112        1244 :             if(rEntries.empty())
     113             :             {
     114             :                 // no fill at all
     115             :             }
     116             :             else
     117             :             {
     118        1244 :                 const sal_uInt32 nCount(rEntries.size());
     119             : 
     120        1244 :                 if(1 == nCount)
     121             :                 {
     122             :                     // fill with single existing color
     123           0 :                     setSingleEntry();
     124             :                 }
     125             :                 else
     126             :                 {
     127             :                     // sort maGradientEntries when more than one
     128        1244 :                     std::sort(maGradientEntries.begin(), maGradientEntries.end());
     129             : 
     130             :                     // gradient with at least two colors
     131        1244 :                     bool bAllInvisible(true);
     132             : 
     133        4557 :                     for(sal_uInt32 a(0); a < nCount; a++)
     134             :                     {
     135        3313 :                         const SvgGradientEntry& rCandidate = rEntries[a];
     136             : 
     137        3313 :                         if(basegfx::fTools::equalZero(rCandidate.getOpacity()))
     138             :                         {
     139             :                             // invisible
     140           0 :                             mbFullyOpaque = false;
     141             :                         }
     142        3313 :                         else if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0))
     143             :                         {
     144             :                             // completely opaque
     145        3313 :                             bAllInvisible = false;
     146             :                         }
     147             :                         else
     148             :                         {
     149             :                             // opacity
     150           0 :                             bAllInvisible = false;
     151           0 :                             mbFullyOpaque = false;
     152             :                         }
     153             :                     }
     154             : 
     155        1244 :                     if(bAllInvisible)
     156             :                     {
     157             :                         // all invisible, nothing to do
     158             :                     }
     159             :                     else
     160             :                     {
     161        1244 :                         const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
     162             : 
     163        1244 :                         if(aPolyRange.isEmpty())
     164             :                         {
     165             :                             // no range to fill, nothing to do
     166             :                         }
     167             :                         else
     168             :                         {
     169        1244 :                             const double fPolyWidth(aPolyRange.getWidth());
     170        1244 :                             const double fPolyHeight(aPolyRange.getHeight());
     171             : 
     172        1244 :                             if(basegfx::fTools::equalZero(fPolyWidth) || basegfx::fTools::equalZero(fPolyHeight))
     173             :                             {
     174             :                                 // no width/height to fill, nothing to do
     175             :                             }
     176             :                             else
     177             :                             {
     178        1244 :                                 mbCreatesContent = true;
     179             :                             }
     180             :                         }
     181             :                     }
     182             :                 }
     183             :             }
     184        1244 :         }
     185             : 
     186        1244 :         double SvgGradientHelper::createRun(
     187             :             Primitive2DVector& rTargetColor,
     188             :             Primitive2DVector& rTargetOpacity,
     189             :             double fPos,
     190             :             double fMax,
     191             :             const SvgGradientEntryVector& rEntries,
     192             :             sal_Int32 nOffset) const
     193             :         {
     194        1244 :             const sal_uInt32 nCount(rEntries.size());
     195             : 
     196        1244 :             if(nCount)
     197             :             {
     198        1244 :                 const SvgGradientEntry& rStart = rEntries[0];
     199        1244 :                 const bool bCreateStartPad(fPos < 0.0 && Spread_pad == getSpreadMethod());
     200        1244 :                 const bool bCreateStartFill(rStart.getOffset() > 0.0);
     201        1244 :                 sal_uInt32 nIndex(0);
     202             : 
     203        1244 :                 if(bCreateStartPad || bCreateStartFill)
     204             :                 {
     205         671 :                     const SvgGradientEntry aTemp(bCreateStartPad ? fPos : 0.0, rStart.getColor(), rStart.getOpacity());
     206             : 
     207         671 :                     createAtom(rTargetColor, rTargetOpacity, aTemp, rStart, nOffset);
     208         671 :                     fPos = rStart.getOffset();
     209             :                 }
     210             : 
     211        4548 :                 while(fPos < 1.0 && nIndex + 1 < nCount)
     212             :                 {
     213        2060 :                     const SvgGradientEntry& rCandidateA = rEntries[nIndex++];
     214        2060 :                     const SvgGradientEntry& rCandidateB = rEntries[nIndex];
     215             : 
     216        2060 :                     createAtom(rTargetColor, rTargetOpacity, rCandidateA, rCandidateB, nOffset);
     217        2060 :                     fPos = rCandidateB.getOffset();
     218             :                 }
     219             : 
     220        1244 :                 const SvgGradientEntry& rEnd = rEntries[nCount - 1];
     221        1244 :                 const bool bCreateEndPad(fPos < fMax && Spread_pad == getSpreadMethod());
     222        1244 :                 const bool bCreateEndFill(rEnd.getOffset() < 1.0);
     223             : 
     224        1244 :                 if(bCreateEndPad || bCreateEndFill)
     225             :                 {
     226         584 :                     fPos = bCreateEndPad ? fMax : 1.0;
     227         584 :                     const SvgGradientEntry aTemp(fPos, rEnd.getColor(), rEnd.getOpacity());
     228             : 
     229         584 :                     createAtom(rTargetColor, rTargetOpacity, rEnd, aTemp, nOffset);
     230             :                 }
     231             :             }
     232             :             else
     233             :             {
     234             :                 OSL_ENSURE(false, "GradientAtom creation without ColorStops (!)");
     235           0 :                 fPos = fMax;
     236             :             }
     237             : 
     238        1244 :             return fPos;
     239             :         }
     240             : 
     241        1244 :         Primitive2DSequence SvgGradientHelper::createResult(
     242             :             const Primitive2DVector& rTargetColor,
     243             :             const Primitive2DVector& rTargetOpacity,
     244             :             const basegfx::B2DHomMatrix& rUnitGradientToObject,
     245             :             bool bInvert) const
     246             :         {
     247        1244 :             Primitive2DSequence xRetval;
     248        2488 :             const Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(rTargetColor, bInvert));
     249        2488 :             const Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(rTargetOpacity, bInvert));
     250             : 
     251        1244 :             if(aTargetColorEntries.hasElements())
     252             :             {
     253        1244 :                 Primitive2DReference xRefContent;
     254             : 
     255        1244 :                 if(aTargetOpacityEntries.hasElements())
     256             :                 {
     257             :                     const Primitive2DReference xRefOpacity = new TransparencePrimitive2D(
     258             :                         aTargetColorEntries,
     259           0 :                         aTargetOpacityEntries);
     260             : 
     261           0 :                     xRefContent = new TransformPrimitive2D(
     262             :                         rUnitGradientToObject,
     263           0 :                         Primitive2DSequence(&xRefOpacity, 1));
     264             :                 }
     265             :                 else
     266             :                 {
     267        2488 :                     xRefContent = new TransformPrimitive2D(
     268             :                         rUnitGradientToObject,
     269        2488 :                         aTargetColorEntries);
     270             :                 }
     271             : 
     272        3732 :                 xRefContent = new MaskPrimitive2D(
     273             :                     getPolyPolygon(),
     274        2488 :                     Primitive2DSequence(&xRefContent, 1));
     275             : 
     276        1244 :                 xRetval = Primitive2DSequence(&xRefContent, 1);
     277             :             }
     278             : 
     279        2488 :             return xRetval;
     280             :         }
     281             : 
     282        1244 :         SvgGradientHelper::SvgGradientHelper(
     283             :             const basegfx::B2DHomMatrix& rGradientTransform,
     284             :             const basegfx::B2DPolyPolygon& rPolyPolygon,
     285             :             const SvgGradientEntryVector& rGradientEntries,
     286             :             const basegfx::B2DPoint& rStart,
     287             :             bool bUseUnitCoordinates,
     288             :             SpreadMethod aSpreadMethod)
     289             :         :   maGradientTransform(rGradientTransform),
     290             :             maPolyPolygon(rPolyPolygon),
     291             :             maGradientEntries(rGradientEntries),
     292             :             maStart(rStart),
     293             :             maSpreadMethod(aSpreadMethod),
     294             :             mbPreconditionsChecked(false),
     295             :             mbCreatesContent(false),
     296             :             mbSingleEntry(false),
     297             :             mbFullyOpaque(true),
     298        1244 :             mbUseUnitCoordinates(bUseUnitCoordinates)
     299             :         {
     300        1244 :         }
     301             : 
     302        1244 :         SvgGradientHelper::~SvgGradientHelper()
     303             :         {
     304        1244 :         }
     305             : 
     306           0 :         bool SvgGradientHelper::operator==(const SvgGradientHelper& rSvgGradientHelper) const
     307             :         {
     308           0 :             const SvgGradientHelper& rCompare = static_cast< const SvgGradientHelper& >(rSvgGradientHelper);
     309             : 
     310           0 :             return (getGradientTransform() == rCompare.getGradientTransform()
     311           0 :                 && getPolyPolygon() == rCompare.getPolyPolygon()
     312           0 :                 && getGradientEntries() == rCompare.getGradientEntries()
     313           0 :                 && getStart() == rCompare.getStart()
     314           0 :                 && getUseUnitCoordinates() == rCompare.getUseUnitCoordinates()
     315           0 :                 && getSpreadMethod() == rCompare.getSpreadMethod());
     316             :         }
     317             : 
     318             :     } // end of namespace primitive2d
     319             : } // end of namespace drawinglayer
     320             : 
     321             : 
     322             : 
     323             : namespace drawinglayer
     324             : {
     325             :     namespace primitive2d
     326             :     {
     327        1145 :         void SvgLinearGradientPrimitive2D::checkPreconditions()
     328             :         {
     329             :             // call parent
     330        1145 :             SvgGradientHelper::checkPreconditions();
     331             : 
     332        1145 :             if(getCreatesContent())
     333             :             {
     334             :                 // Check Vector
     335        1145 :                 const basegfx::B2DVector aVector(getEnd() - getStart());
     336             : 
     337        1145 :                 if(basegfx::fTools::equalZero(aVector.getX()) && basegfx::fTools::equalZero(aVector.getY()))
     338             :                 {
     339             :                     // fill with single color using last stop color
     340           0 :                     setSingleEntry();
     341        1145 :                 }
     342             :             }
     343        1145 :         }
     344             : 
     345        3084 :         void SvgLinearGradientPrimitive2D::createAtom(
     346             :             Primitive2DVector& rTargetColor,
     347             :             Primitive2DVector& rTargetOpacity,
     348             :             const SvgGradientEntry& rFrom,
     349             :             const SvgGradientEntry& rTo,
     350             :             sal_Int32 nOffset) const
     351             :         {
     352             :             // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset())
     353        3084 :             if(rFrom.getOffset() == rTo.getOffset())
     354             :             {
     355             :                 OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)");
     356             :             }
     357             :             else
     358             :             {
     359             :                 rTargetColor.push_back(
     360             :                     new SvgLinearAtomPrimitive2D(
     361        3084 :                         rFrom.getColor(), rFrom.getOffset() + nOffset,
     362        6168 :                         rTo.getColor(), rTo.getOffset() + nOffset));
     363             : 
     364        3084 :                 if(!getFullyOpaque())
     365             :                 {
     366           0 :                     const double fTransFrom(1.0 - rFrom.getOpacity());
     367           0 :                     const double fTransTo(1.0 - rTo.getOpacity());
     368           0 :                     const basegfx::BColor aColorFrom(fTransFrom, fTransFrom, fTransFrom);
     369           0 :                     const basegfx::BColor aColorTo(fTransTo, fTransTo, fTransTo);
     370             : 
     371             :                     rTargetOpacity.push_back(
     372             :                         new SvgLinearAtomPrimitive2D(
     373           0 :                             aColorFrom, rFrom.getOffset() + nOffset,
     374           0 :                             aColorTo, rTo.getOffset() + nOffset));
     375             :                 }
     376             :             }
     377        3084 :         }
     378             : 
     379        1145 :         Primitive2DSequence SvgLinearGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
     380             :         {
     381        1145 :             Primitive2DSequence xRetval;
     382             : 
     383        1145 :             if(!getPreconditionsChecked())
     384             :             {
     385        1145 :                 const_cast< SvgLinearGradientPrimitive2D* >(this)->checkPreconditions();
     386             :             }
     387             : 
     388        1145 :             if(getSingleEntry())
     389             :             {
     390             :                 // fill with last existing color
     391           0 :                 xRetval = createSingleGradientEntryFill();
     392             :             }
     393        1145 :             else if(getCreatesContent())
     394             :             {
     395             :                 // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely
     396             :                 // invisible, width and height to fill are not empty
     397        1145 :                 const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
     398        1145 :                 const double fPolyWidth(aPolyRange.getWidth());
     399        1145 :                 const double fPolyHeight(aPolyRange.getHeight());
     400             : 
     401             :                 // create ObjectTransform based on polygon range
     402             :                 const basegfx::B2DHomMatrix aObjectTransform(
     403             :                     basegfx::tools::createScaleTranslateB2DHomMatrix(
     404             :                         fPolyWidth, fPolyHeight,
     405        1145 :                         aPolyRange.getMinX(), aPolyRange.getMinY()));
     406        2290 :                 basegfx::B2DHomMatrix aUnitGradientToObject;
     407             : 
     408        1145 :                 if(getUseUnitCoordinates())
     409             :                 {
     410             :                     // interpret in unit coordinate system -> object aspect ratio will scale result
     411             :                     // create unit transform from unit vector [0.0 .. 1.0] along the X-Axis to given
     412             :                     // gradient vector defined by Start,End
     413           0 :                     const basegfx::B2DVector aVector(getEnd() - getStart());
     414           0 :                     const double fVectorLength(aVector.getLength());
     415             : 
     416           0 :                     aUnitGradientToObject.scale(fVectorLength, 1.0);
     417           0 :                     aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX()));
     418           0 :                     aUnitGradientToObject.translate(getStart().getX(), getStart().getY());
     419             : 
     420           0 :                     if(!getGradientTransform().isIdentity())
     421             :                     {
     422           0 :                         aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject;
     423             :                     }
     424             : 
     425             :                     // create full transform from unit gradient coordinates to object coordinates
     426             :                     // including the SvgGradient transformation
     427           0 :                     aUnitGradientToObject = aObjectTransform * aUnitGradientToObject;
     428             :                 }
     429             :                 else
     430             :                 {
     431             :                     // interpret in object coordinate system -> object aspect ratio will not scale result
     432        1145 :                     const basegfx::B2DPoint aStart(aObjectTransform * getStart());
     433        2290 :                     const basegfx::B2DPoint aEnd(aObjectTransform * getEnd());
     434        2290 :                     const basegfx::B2DVector aVector(aEnd - aStart);
     435             : 
     436        1145 :                     aUnitGradientToObject.scale(aVector.getLength(), 1.0);
     437        1145 :                     aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX()));
     438        1145 :                     aUnitGradientToObject.translate(aStart.getX(), aStart.getY());
     439             : 
     440        1145 :                     if(!getGradientTransform().isIdentity())
     441             :                     {
     442         185 :                         aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject;
     443        1145 :                     }
     444             :                 }
     445             : 
     446             :                 // create inverse from it
     447        2290 :                 basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject);
     448        1145 :                 aObjectToUnitGradient.invert();
     449             : 
     450             :                 // back-transform polygon to unit gradient coordinates and get
     451             :                 // UnitRage. This is the range the gradient has to cover
     452        2290 :                 basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon());
     453        1145 :                 aUnitPoly.transform(aObjectToUnitGradient);
     454        1145 :                 const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange());
     455             : 
     456             :                 // prepare result vectors
     457        2290 :                 Primitive2DVector aTargetColor;
     458        2290 :                 Primitive2DVector aTargetOpacity;
     459             : 
     460        1145 :                 if(basegfx::fTools::more(aUnitRange.getWidth(), 0.0))
     461             :                 {
     462             :                     // add a pre-multiply to aUnitGradientToObject to allow
     463             :                     // multiplication of the polygon(xl, 0.0, xr, 1.0)
     464             :                     const basegfx::B2DHomMatrix aPreMultiply(
     465             :                         basegfx::tools::createScaleTranslateB2DHomMatrix(
     466        1145 :                             1.0, aUnitRange.getHeight(), 0.0, aUnitRange.getMinY()));
     467        1145 :                     aUnitGradientToObject = aUnitGradientToObject * aPreMultiply;
     468             : 
     469             :                     // create central run, may also already do all necessary when
     470             :                     // Spread_pad is set as SpreadMethod and/or the range is smaller
     471        1145 :                     double fPos(createRun(aTargetColor, aTargetOpacity, aUnitRange.getMinX(), aUnitRange.getMaxX(), getGradientEntries(), 0));
     472             : 
     473        1145 :                     if(fPos < aUnitRange.getMaxX())
     474             :                     {
     475             :                         // can only happen when SpreadMethod is Spread_reflect or Spread_repeat,
     476             :                         // else the start and end pads are already created and fPos == aUnitRange.getMaxX().
     477             :                         // Its possible to express the repeated linear gradient by adding the
     478             :                         // transformed central run. Crete it this way
     479           0 :                         Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(aTargetColor));
     480           0 :                         Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(aTargetOpacity));
     481           0 :                         aTargetColor.clear();
     482           0 :                         aTargetOpacity.clear();
     483             : 
     484           0 :                         if(aTargetColorEntries.hasElements())
     485             :                         {
     486             :                             // add original central run as group primitive
     487           0 :                             aTargetColor.push_back(new GroupPrimitive2D(aTargetColorEntries));
     488             : 
     489           0 :                             if(aTargetOpacityEntries.hasElements())
     490             :                             {
     491           0 :                                 aTargetOpacity.push_back(new GroupPrimitive2D(aTargetOpacityEntries));
     492             :                             }
     493             : 
     494             :                             // add negative runs
     495           0 :                             fPos = 0.0;
     496           0 :                             sal_Int32 nOffset(0);
     497             : 
     498           0 :                             while(fPos > aUnitRange.getMinX())
     499             :                             {
     500           0 :                                 fPos -= 1.0;
     501           0 :                                 nOffset++;
     502             : 
     503           0 :                                 basegfx::B2DHomMatrix aTransform;
     504           0 :                                 const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
     505             : 
     506           0 :                                 if(bMirror)
     507             :                                 {
     508           0 :                                     aTransform.scale(-1.0, 1.0);
     509           0 :                                     aTransform.translate(fPos + 1.0, 0.0);
     510             :                                 }
     511             :                                 else
     512             :                                 {
     513           0 :                                     aTransform.translate(fPos, 0.0);
     514             :                                 }
     515             : 
     516           0 :                                 aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries));
     517             : 
     518           0 :                                 if(aTargetOpacityEntries.hasElements())
     519             :                                 {
     520           0 :                                     aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries));
     521             :                                 }
     522           0 :                             }
     523             : 
     524             :                             // add positive runs
     525           0 :                             fPos = 1.0;
     526           0 :                             nOffset = 1;
     527             : 
     528           0 :                             while(fPos < aUnitRange.getMaxX())
     529             :                             {
     530           0 :                                 basegfx::B2DHomMatrix aTransform;
     531           0 :                                 const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
     532             : 
     533           0 :                                 if(bMirror)
     534             :                                 {
     535           0 :                                     aTransform.scale(-1.0, 1.0);
     536           0 :                                     aTransform.translate(fPos + 1.0, 0.0);
     537             :                                 }
     538             :                                 else
     539             :                                 {
     540           0 :                                     aTransform.translate(fPos, 0.0);
     541             :                                 }
     542             : 
     543           0 :                                 aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries));
     544             : 
     545           0 :                                 if(aTargetOpacityEntries.hasElements())
     546             :                                 {
     547           0 :                                     aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries));
     548             :                                 }
     549             : 
     550           0 :                                 fPos += 1.0;
     551           0 :                                 nOffset++;
     552           0 :                             }
     553           0 :                         }
     554        1145 :                     }
     555             :                 }
     556             : 
     557        2290 :                 xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject);
     558             :             }
     559             : 
     560        1145 :             return xRetval;
     561             :         }
     562             : 
     563        1145 :         SvgLinearGradientPrimitive2D::SvgLinearGradientPrimitive2D(
     564             :             const basegfx::B2DHomMatrix& rGradientTransform,
     565             :             const basegfx::B2DPolyPolygon& rPolyPolygon,
     566             :             const SvgGradientEntryVector& rGradientEntries,
     567             :             const basegfx::B2DPoint& rStart,
     568             :             const basegfx::B2DPoint& rEnd,
     569             :             bool bUseUnitCoordinates,
     570             :             SpreadMethod aSpreadMethod)
     571             :         :   BufferedDecompositionPrimitive2D(),
     572             :             SvgGradientHelper(rGradientTransform, rPolyPolygon, rGradientEntries, rStart, bUseUnitCoordinates, aSpreadMethod),
     573        1145 :             maEnd(rEnd)
     574             :         {
     575        1145 :         }
     576             : 
     577        2290 :         SvgLinearGradientPrimitive2D::~SvgLinearGradientPrimitive2D()
     578             :         {
     579        2290 :         }
     580             : 
     581           0 :         bool SvgLinearGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
     582             :         {
     583           0 :             const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive);
     584             : 
     585           0 :             if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper))
     586             :             {
     587           0 :                 const SvgLinearGradientPrimitive2D& rCompare = static_cast< const SvgLinearGradientPrimitive2D& >(rPrimitive);
     588             : 
     589           0 :                 return (getEnd() == rCompare.getEnd());
     590             :             }
     591             : 
     592           0 :             return false;
     593             :         }
     594             : 
     595        1762 :         basegfx::B2DRange SvgLinearGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
     596             :         {
     597             :             // return ObjectRange
     598        1762 :             return getPolyPolygon().getB2DRange();
     599             :         }
     600             : 
     601             :         // provide unique ID
     602        2310 :         ImplPrimitive2DIDBlock(SvgLinearGradientPrimitive2D, PRIMITIVE2D_ID_SVGLINEARGRADIENTPRIMITIVE2D)
     603             : 
     604             :     } // end of namespace primitive2d
     605             : } // end of namespace drawinglayer
     606             : 
     607             : 
     608             : 
     609             : namespace drawinglayer
     610             : {
     611             :     namespace primitive2d
     612             :     {
     613          99 :         void SvgRadialGradientPrimitive2D::checkPreconditions()
     614             :         {
     615             :             // call parent
     616          99 :             SvgGradientHelper::checkPreconditions();
     617             : 
     618          99 :             if(getCreatesContent())
     619             :             {
     620             :                 // Check Radius
     621          99 :                 if(basegfx::fTools::equalZero(getRadius()))
     622             :                 {
     623             :                     // fill with single color using last stop color
     624           0 :                     setSingleEntry();
     625             :                 }
     626             :             }
     627          99 :         }
     628             : 
     629         231 :         void SvgRadialGradientPrimitive2D::createAtom(
     630             :             Primitive2DVector& rTargetColor,
     631             :             Primitive2DVector& rTargetOpacity,
     632             :             const SvgGradientEntry& rFrom,
     633             :             const SvgGradientEntry& rTo,
     634             :             sal_Int32 nOffset) const
     635             :         {
     636             :             // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset())
     637         231 :             if(rFrom.getOffset() == rTo.getOffset())
     638             :             {
     639             :                 OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)");
     640             :             }
     641             :             else
     642             :             {
     643         231 :                 const double fScaleFrom(rFrom.getOffset() + nOffset);
     644         231 :                 const double fScaleTo(rTo.getOffset() + nOffset);
     645             : 
     646         231 :                 if(isFocalSet())
     647             :                 {
     648           0 :                     const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom));
     649           0 :                     const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo));
     650             : 
     651             :                     rTargetColor.push_back(
     652             :                         new SvgRadialAtomPrimitive2D(
     653             :                             rFrom.getColor(), fScaleFrom, aTranslateFrom,
     654           0 :                             rTo.getColor(), fScaleTo, aTranslateTo));
     655             :                 }
     656             :                 else
     657             :                 {
     658             :                     rTargetColor.push_back(
     659             :                         new SvgRadialAtomPrimitive2D(
     660             :                             rFrom.getColor(), fScaleFrom,
     661         231 :                             rTo.getColor(), fScaleTo));
     662             :                 }
     663             : 
     664         231 :                 if(!getFullyOpaque())
     665             :                 {
     666           0 :                     const double fTransFrom(1.0 - rFrom.getOpacity());
     667           0 :                     const double fTransTo(1.0 - rTo.getOpacity());
     668           0 :                     const basegfx::BColor aColorFrom(fTransFrom, fTransFrom, fTransFrom);
     669           0 :                     const basegfx::BColor aColorTo(fTransTo, fTransTo, fTransTo);
     670             : 
     671           0 :                     if(isFocalSet())
     672             :                     {
     673           0 :                         const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom));
     674           0 :                         const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo));
     675             : 
     676             :                         rTargetOpacity.push_back(
     677             :                             new SvgRadialAtomPrimitive2D(
     678             :                                 aColorFrom, fScaleFrom, aTranslateFrom,
     679           0 :                                 aColorTo, fScaleTo, aTranslateTo));
     680             :                     }
     681             :                     else
     682             :                     {
     683             :                         rTargetOpacity.push_back(
     684             :                             new SvgRadialAtomPrimitive2D(
     685             :                                 aColorFrom, fScaleFrom,
     686           0 :                                 aColorTo, fScaleTo));
     687           0 :                     }
     688             :                 }
     689             :             }
     690         231 :         }
     691             : 
     692           0 :         const SvgGradientEntryVector& SvgRadialGradientPrimitive2D::getMirroredGradientEntries() const
     693             :         {
     694           0 :             if(maMirroredGradientEntries.empty() && !getGradientEntries().empty())
     695             :             {
     696           0 :                 const_cast< SvgRadialGradientPrimitive2D* >(this)->createMirroredGradientEntries();
     697             :             }
     698             : 
     699           0 :             return maMirroredGradientEntries;
     700             :         }
     701             : 
     702           0 :         void SvgRadialGradientPrimitive2D::createMirroredGradientEntries()
     703             :         {
     704           0 :             if(maMirroredGradientEntries.empty() && !getGradientEntries().empty())
     705             :             {
     706           0 :                 const sal_uInt32 nCount(getGradientEntries().size());
     707           0 :                 maMirroredGradientEntries.clear();
     708           0 :                 maMirroredGradientEntries.reserve(nCount);
     709             : 
     710           0 :                 for(sal_uInt32 a(0); a < nCount; a++)
     711             :                 {
     712           0 :                     const SvgGradientEntry& rCandidate = getGradientEntries()[nCount - 1 - a];
     713             : 
     714             :                     maMirroredGradientEntries.push_back(
     715             :                         SvgGradientEntry(
     716           0 :                             1.0 - rCandidate.getOffset(),
     717           0 :                             rCandidate.getColor(),
     718           0 :                             rCandidate.getOpacity()));
     719             :                 }
     720             :             }
     721           0 :         }
     722             : 
     723          99 :         Primitive2DSequence SvgRadialGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
     724             :         {
     725          99 :             Primitive2DSequence xRetval;
     726             : 
     727          99 :             if(!getPreconditionsChecked())
     728             :             {
     729          99 :                 const_cast< SvgRadialGradientPrimitive2D* >(this)->checkPreconditions();
     730             :             }
     731             : 
     732          99 :             if(getSingleEntry())
     733             :             {
     734             :                 // fill with last existing color
     735           0 :                 xRetval = createSingleGradientEntryFill();
     736             :             }
     737          99 :             else if(getCreatesContent())
     738             :             {
     739             :                 // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely
     740             :                 // invisible, width and height to fill are not empty
     741          99 :                 const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
     742          99 :                 const double fPolyWidth(aPolyRange.getWidth());
     743          99 :                 const double fPolyHeight(aPolyRange.getHeight());
     744             : 
     745             :                 // create ObjectTransform based on polygon range
     746             :                 const basegfx::B2DHomMatrix aObjectTransform(
     747             :                     basegfx::tools::createScaleTranslateB2DHomMatrix(
     748             :                         fPolyWidth, fPolyHeight,
     749          99 :                         aPolyRange.getMinX(), aPolyRange.getMinY()));
     750         198 :                 basegfx::B2DHomMatrix aUnitGradientToObject;
     751             : 
     752          99 :                 if(getUseUnitCoordinates())
     753             :                 {
     754             :                     // interpret in unit coordinate system -> object aspect ratio will scale result
     755             :                     // create unit transform from unit vector to given linear gradient vector
     756           0 :                     aUnitGradientToObject.scale(getRadius(), getRadius());
     757           0 :                     aUnitGradientToObject.translate(getStart().getX(), getStart().getY());
     758             : 
     759           0 :                     if(!getGradientTransform().isIdentity())
     760             :                     {
     761           0 :                         aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject;
     762             :                     }
     763             : 
     764             :                     // create full transform from unit gradient coordinates to object coordinates
     765             :                     // including the SvgGradient transformation
     766           0 :                     aUnitGradientToObject = aObjectTransform * aUnitGradientToObject;
     767             :                 }
     768             :                 else
     769             :                 {
     770             :                     // interpret in object coordinate system -> object aspect ratio will not scale result
     771             :                     // use X-Axis with radius, it was already made relative to object width when coming from
     772             :                     // SVG import
     773          99 :                     const double fRadius((aObjectTransform * basegfx::B2DVector(getRadius(), 0.0)).getLength());
     774          99 :                     const basegfx::B2DPoint aStart(aObjectTransform * getStart());
     775             : 
     776          99 :                     aUnitGradientToObject.scale(fRadius, fRadius);
     777          99 :                     aUnitGradientToObject.translate(aStart.getX(), aStart.getY());
     778             : 
     779          99 :                     if(!getGradientTransform().isIdentity())
     780             :                     {
     781          19 :                         aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject;
     782          99 :                     }
     783             :                 }
     784             : 
     785             :                 // create inverse from it
     786         198 :                 basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject);
     787          99 :                 aObjectToUnitGradient.invert();
     788             : 
     789             :                 // back-transform polygon to unit gradient coordinates and get
     790             :                 // UnitRage. This is the range the gradient has to cover
     791         198 :                 basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon());
     792          99 :                 aUnitPoly.transform(aObjectToUnitGradient);
     793          99 :                 const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange());
     794             : 
     795             :                 // create range which the gradient has to cover to cover the whole given geometry.
     796             :                 // For circle, go from 0.0 to max radius in all directions (the corners)
     797          99 :                 double fMax(basegfx::B2DVector(aUnitRange.getMinimum()).getLength());
     798          99 :                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaximum()).getLength());
     799          99 :                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMinX(), aUnitRange.getMaxY()).getLength());
     800          99 :                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaxX(), aUnitRange.getMinY()).getLength());
     801             : 
     802             :                 // prepare result vectors
     803         198 :                 Primitive2DVector aTargetColor;
     804         198 :                 Primitive2DVector aTargetOpacity;
     805             : 
     806          99 :                 if(0.0 < fMax)
     807             :                 {
     808             :                     // prepare maFocalVector
     809          99 :                     if(isFocalSet())
     810             :                     {
     811           0 :                         const_cast< SvgRadialGradientPrimitive2D* >(this)->maFocalLength = fMax;
     812             :                     }
     813             : 
     814             :                     // create central run, may also already do all necessary when
     815             :                     // Spread_pad is set as SpreadMethod and/or the range is smaller
     816          99 :                     double fPos(createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), 0));
     817             : 
     818          99 :                     if(fPos < fMax)
     819             :                     {
     820             :                         // can only happen when SpreadMethod is Spread_reflect or Spread_repeat,
     821             :                         // else the start and end pads are already created and fPos == fMax.
     822             :                         // For radial there is no way to transform the already created
     823             :                         // central run, it needs to be created from 1.0 to fMax
     824           0 :                         sal_Int32 nOffset(1);
     825             : 
     826           0 :                         while(fPos < fMax)
     827             :                         {
     828           0 :                             const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
     829             : 
     830           0 :                             if(bMirror)
     831             :                             {
     832           0 :                                 createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getMirroredGradientEntries(), nOffset);
     833             :                             }
     834             :                             else
     835             :                             {
     836           0 :                                 createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), nOffset);
     837             :                             }
     838             : 
     839           0 :                             nOffset++;
     840           0 :                             fPos += 1.0;
     841             :                         }
     842             :                     }
     843             :                 }
     844             : 
     845         198 :                 xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject, true);
     846             :             }
     847             : 
     848          99 :             return xRetval;
     849             :         }
     850             : 
     851          99 :         SvgRadialGradientPrimitive2D::SvgRadialGradientPrimitive2D(
     852             :             const basegfx::B2DHomMatrix& rGradientTransform,
     853             :             const basegfx::B2DPolyPolygon& rPolyPolygon,
     854             :             const SvgGradientEntryVector& rGradientEntries,
     855             :             const basegfx::B2DPoint& rStart,
     856             :             double fRadius,
     857             :             bool bUseUnitCoordinates,
     858             :             SpreadMethod aSpreadMethod,
     859             :             const basegfx::B2DPoint* pFocal)
     860             :         :   BufferedDecompositionPrimitive2D(),
     861             :             SvgGradientHelper(rGradientTransform, rPolyPolygon, rGradientEntries, rStart, bUseUnitCoordinates, aSpreadMethod),
     862             :             mfRadius(fRadius),
     863             :             maFocal(rStart),
     864             :             maFocalVector(0.0, 0.0),
     865             :             maFocalLength(0.0),
     866             :             maMirroredGradientEntries(),
     867          99 :             mbFocalSet(false)
     868             :         {
     869          99 :             if(pFocal && !pFocal->equal(getStart()))
     870             :             {
     871           0 :                 maFocal = *pFocal;
     872           0 :                 maFocalVector = maFocal - getStart();
     873           0 :                 mbFocalSet = true;
     874             :             }
     875          99 :         }
     876             : 
     877         198 :         SvgRadialGradientPrimitive2D::~SvgRadialGradientPrimitive2D()
     878             :         {
     879         198 :         }
     880             : 
     881           0 :         bool SvgRadialGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
     882             :         {
     883           0 :             const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive);
     884             : 
     885           0 :             if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper))
     886             :             {
     887           0 :                 const SvgRadialGradientPrimitive2D& rCompare = static_cast< const SvgRadialGradientPrimitive2D& >(rPrimitive);
     888             : 
     889           0 :                 if(getRadius() == rCompare.getRadius())
     890             :                 {
     891           0 :                     if(isFocalSet() == rCompare.isFocalSet())
     892             :                     {
     893           0 :                         if(isFocalSet())
     894             :                         {
     895           0 :                             return getFocal() == rCompare.getFocal();
     896             :                         }
     897             :                         else
     898             :                         {
     899           0 :                             return true;
     900             :                         }
     901             :                     }
     902             :                 }
     903             :             }
     904             : 
     905           0 :             return false;
     906             :         }
     907             : 
     908         101 :         basegfx::B2DRange SvgRadialGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
     909             :         {
     910             :             // return ObjectRange
     911         101 :             return getPolyPolygon().getB2DRange();
     912             :         }
     913             : 
     914             :         // provide unique ID
     915         226 :         ImplPrimitive2DIDBlock(SvgRadialGradientPrimitive2D, PRIMITIVE2D_ID_SVGRADIALGRADIENTPRIMITIVE2D)
     916             : 
     917             :     } // end of namespace primitive2d
     918             : } // end of namespace drawinglayer
     919             : 
     920             : 
     921             : // SvgLinearAtomPrimitive2D class
     922             : 
     923             : namespace drawinglayer
     924             : {
     925             :     namespace primitive2d
     926             :     {
     927           0 :         Primitive2DSequence SvgLinearAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
     928             :         {
     929           0 :             Primitive2DSequence xRetval;
     930           0 :             const double fDelta(getOffsetB() - getOffsetA());
     931             : 
     932           0 :             if(!basegfx::fTools::equalZero(fDelta))
     933             :             {
     934             :                 // use one discrete unit for overlap (one pixel)
     935           0 :                 const double fDiscreteUnit(getDiscreteUnit());
     936             : 
     937             :                 // use color distance and discrete lengths to calculate step count
     938           0 :                 const sal_uInt32 nSteps(calculateStepsForSvgGradient(getColorA(), getColorB(), fDelta, fDiscreteUnit));
     939             : 
     940             :                 // prepare polygon in needed width at start position (with discrete overlap)
     941             :                 const basegfx::B2DPolygon aPolygon(
     942             :                     basegfx::tools::createPolygonFromRect(
     943             :                         basegfx::B2DRange(
     944           0 :                             getOffsetA() - fDiscreteUnit,
     945             :                             0.0,
     946           0 :                             getOffsetA() + (fDelta / nSteps) + fDiscreteUnit,
     947           0 :                             1.0)));
     948             : 
     949             :                 // prepare loop (inside to outside, [0.0 .. 1.0[)
     950           0 :                 double fUnitScale(0.0);
     951           0 :                 const double fUnitStep(1.0 / nSteps);
     952             : 
     953             :                 // prepare result set (known size)
     954           0 :                 xRetval.realloc(nSteps);
     955             : 
     956           0 :                 for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep)
     957             :                 {
     958           0 :                     basegfx::B2DPolygon aNew(aPolygon);
     959             : 
     960           0 :                     aNew.transform(basegfx::tools::createTranslateB2DHomMatrix(fDelta * fUnitScale, 0.0));
     961           0 :                     xRetval[a] = new PolyPolygonColorPrimitive2D(
     962             :                         basegfx::B2DPolyPolygon(aNew),
     963           0 :                         basegfx::interpolate(getColorA(), getColorB(), fUnitScale));
     964           0 :                 }
     965             :             }
     966             : 
     967           0 :             return xRetval;
     968             :         }
     969             : 
     970        3084 :         SvgLinearAtomPrimitive2D::SvgLinearAtomPrimitive2D(
     971             :             const basegfx::BColor& aColorA, double fOffsetA,
     972             :             const basegfx::BColor& aColorB, double fOffsetB)
     973             :         :   DiscreteMetricDependentPrimitive2D(),
     974             :             maColorA(aColorA),
     975             :             maColorB(aColorB),
     976             :             mfOffsetA(fOffsetA),
     977        3084 :             mfOffsetB(fOffsetB)
     978             :         {
     979        3084 :             if(mfOffsetA > mfOffsetB)
     980             :             {
     981             :                 OSL_ENSURE(false, "Wrong offset order (!)");
     982           0 :                 ::std::swap(mfOffsetA, mfOffsetB);
     983             :             }
     984        3084 :         }
     985             : 
     986           0 :         bool SvgLinearAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
     987             :         {
     988           0 :             if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
     989             :             {
     990           0 :                 const SvgLinearAtomPrimitive2D& rCompare = static_cast< const SvgLinearAtomPrimitive2D& >(rPrimitive);
     991             : 
     992           0 :                 return (getColorA() == rCompare.getColorA()
     993           0 :                     && getColorB() == rCompare.getColorB()
     994           0 :                     && getOffsetA() == rCompare.getOffsetA()
     995           0 :                     && getOffsetB() == rCompare.getOffsetB());
     996             :             }
     997             : 
     998           0 :             return false;
     999             :         }
    1000             : 
    1001             :         // provide unique ID
    1002        6144 :         ImplPrimitive2DIDBlock(SvgLinearAtomPrimitive2D, PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D)
    1003             : 
    1004             :     } // end of namespace primitive2d
    1005             : } // end of namespace drawinglayer
    1006             : 
    1007             : 
    1008             : // SvgRadialAtomPrimitive2D class
    1009             : 
    1010             : namespace drawinglayer
    1011             : {
    1012             :     namespace primitive2d
    1013             :     {
    1014           0 :         Primitive2DSequence SvgRadialAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
    1015             :         {
    1016           0 :             Primitive2DSequence xRetval;
    1017           0 :             const double fDeltaScale(getScaleB() - getScaleA());
    1018             : 
    1019           0 :             if(!basegfx::fTools::equalZero(fDeltaScale))
    1020             :             {
    1021             :                 // use one discrete unit for overlap (one pixel)
    1022           0 :                 const double fDiscreteUnit(getDiscreteUnit());
    1023             : 
    1024             :                 // use color distance and discrete lengths to calculate step count
    1025           0 :                 const sal_uInt32 nSteps(calculateStepsForSvgGradient(getColorA(), getColorB(), fDeltaScale, fDiscreteUnit));
    1026             : 
    1027             :                 // prepare loop ([0.0 .. 1.0[, full polygons, no polypolygons with holes)
    1028           0 :                 double fUnitScale(0.0);
    1029           0 :                 const double fUnitStep(1.0 / nSteps);
    1030             : 
    1031             :                 // prepare result set (known size)
    1032           0 :                 xRetval.realloc(nSteps);
    1033             : 
    1034           0 :                 for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep)
    1035             :                 {
    1036           0 :                     basegfx::B2DHomMatrix aTransform;
    1037           0 :                     const double fEndScale(getScaleB() - (fDeltaScale * fUnitScale));
    1038             : 
    1039           0 :                     if(isTranslateSet())
    1040             :                     {
    1041             :                         const basegfx::B2DVector aTranslate(
    1042             :                             basegfx::interpolate(
    1043             :                                 getTranslateB(),
    1044             :                                 getTranslateA(),
    1045           0 :                                 fUnitScale));
    1046             : 
    1047           0 :                         aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
    1048             :                             fEndScale,
    1049             :                             fEndScale,
    1050             :                             aTranslate.getX(),
    1051           0 :                             aTranslate.getY());
    1052             :                     }
    1053             :                     else
    1054             :                     {
    1055           0 :                         aTransform = basegfx::tools::createScaleB2DHomMatrix(
    1056             :                             fEndScale,
    1057           0 :                             fEndScale);
    1058             :                     }
    1059             : 
    1060           0 :                     basegfx::B2DPolygon aNew(basegfx::tools::createPolygonFromUnitCircle());
    1061             : 
    1062           0 :                     aNew.transform(aTransform);
    1063           0 :                     xRetval[a] = new PolyPolygonColorPrimitive2D(
    1064             :                         basegfx::B2DPolyPolygon(aNew),
    1065           0 :                         basegfx::interpolate(getColorB(), getColorA(), fUnitScale));
    1066           0 :                 }
    1067             :             }
    1068             : 
    1069           0 :             return xRetval;
    1070             :         }
    1071             : 
    1072           0 :         SvgRadialAtomPrimitive2D::SvgRadialAtomPrimitive2D(
    1073             :             const basegfx::BColor& aColorA, double fScaleA, const basegfx::B2DVector& rTranslateA,
    1074             :             const basegfx::BColor& aColorB, double fScaleB, const basegfx::B2DVector& rTranslateB)
    1075             :         :   DiscreteMetricDependentPrimitive2D(),
    1076             :             maColorA(aColorA),
    1077             :             maColorB(aColorB),
    1078             :             mfScaleA(fScaleA),
    1079             :             mfScaleB(fScaleB),
    1080           0 :             mpTranslate(0)
    1081             :         {
    1082             :             // check and evtl. set translations
    1083           0 :             if(!rTranslateA.equal(rTranslateB))
    1084             :             {
    1085           0 :                 mpTranslate = new VectorPair(rTranslateA, rTranslateB);
    1086             :             }
    1087             : 
    1088             :             // scale A and B have to be positive
    1089           0 :             mfScaleA = ::std::max(mfScaleA, 0.0);
    1090           0 :             mfScaleB = ::std::max(mfScaleB, 0.0);
    1091             : 
    1092             :             // scale B has to be bigger than scale A; swap if different
    1093           0 :             if(mfScaleA > mfScaleB)
    1094             :             {
    1095             :                 OSL_ENSURE(false, "Wrong offset order (!)");
    1096           0 :                 ::std::swap(mfScaleA, mfScaleB);
    1097             : 
    1098           0 :                 if(mpTranslate)
    1099             :                 {
    1100           0 :                     ::std::swap(mpTranslate->maTranslateA, mpTranslate->maTranslateB);
    1101             :                 }
    1102             :             }
    1103           0 :         }
    1104             : 
    1105         231 :         SvgRadialAtomPrimitive2D::SvgRadialAtomPrimitive2D(
    1106             :             const basegfx::BColor& aColorA, double fScaleA,
    1107             :             const basegfx::BColor& aColorB, double fScaleB)
    1108             :         :   DiscreteMetricDependentPrimitive2D(),
    1109             :             maColorA(aColorA),
    1110             :             maColorB(aColorB),
    1111             :             mfScaleA(fScaleA),
    1112             :             mfScaleB(fScaleB),
    1113         231 :             mpTranslate(0)
    1114             :         {
    1115             :             // scale A and B have to be positive
    1116         231 :             mfScaleA = ::std::max(mfScaleA, 0.0);
    1117         231 :             mfScaleB = ::std::max(mfScaleB, 0.0);
    1118             : 
    1119             :             // scale B has to be bigger than scale A; swap if different
    1120         231 :             if(mfScaleA > mfScaleB)
    1121             :             {
    1122             :                 OSL_ENSURE(false, "Wrong offset order (!)");
    1123           0 :                 ::std::swap(mfScaleA, mfScaleB);
    1124             :             }
    1125         231 :         }
    1126             : 
    1127         693 :         SvgRadialAtomPrimitive2D::~SvgRadialAtomPrimitive2D()
    1128             :         {
    1129         231 :             if(mpTranslate)
    1130             :             {
    1131           0 :                 delete mpTranslate;
    1132           0 :                 mpTranslate = 0;
    1133             :             }
    1134         462 :         }
    1135             : 
    1136           0 :         bool SvgRadialAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
    1137             :         {
    1138           0 :             if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
    1139             :             {
    1140           0 :                 const SvgRadialAtomPrimitive2D& rCompare = static_cast< const SvgRadialAtomPrimitive2D& >(rPrimitive);
    1141             : 
    1142           0 :                 if(getColorA() == rCompare.getColorA()
    1143           0 :                     && getColorB() == rCompare.getColorB()
    1144           0 :                     && getScaleA() == rCompare.getScaleA()
    1145           0 :                     && getScaleB() == rCompare.getScaleB())
    1146             :                 {
    1147           0 :                     if(isTranslateSet() && rCompare.isTranslateSet())
    1148             :                     {
    1149           0 :                         return (getTranslateA() == rCompare.getTranslateA()
    1150           0 :                             && getTranslateB() == rCompare.getTranslateB());
    1151             :                     }
    1152           0 :                     else if(!isTranslateSet() && !rCompare.isTranslateSet())
    1153             :                     {
    1154           0 :                         return true;
    1155             :                     }
    1156             :                 }
    1157             :             }
    1158             : 
    1159           0 :             return false;
    1160             :         }
    1161             : 
    1162             :         // provide unique ID
    1163         462 :         ImplPrimitive2DIDBlock(SvgRadialAtomPrimitive2D, PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D)
    1164             : 
    1165             :     } // end of namespace primitive2d
    1166             : } // end of namespace drawinglayer
    1167             : 
    1168             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10