1ddde725dSArmin Le Grand /************************************************************** 2ddde725dSArmin Le Grand * 3ddde725dSArmin Le Grand * Licensed to the Apache Software Foundation (ASF) under one 4ddde725dSArmin Le Grand * or more contributor license agreements. See the NOTICE file 5ddde725dSArmin Le Grand * distributed with this work for additional information 6ddde725dSArmin Le Grand * regarding copyright ownership. The ASF licenses this file 7ddde725dSArmin Le Grand * to you under the Apache License, Version 2.0 (the 8ddde725dSArmin Le Grand * "License"); you may not use this file except in compliance 9ddde725dSArmin Le Grand * with the License. You may obtain a copy of the License at 10ddde725dSArmin Le Grand * 112b45cf47SArmin Le Grand * http://www.apache.org/licenses/LICENSE-2.0 12ddde725dSArmin Le Grand * 13ddde725dSArmin Le Grand * Unless required by applicable law or agreed to in writing, 14ddde725dSArmin Le Grand * software distributed under the License is distributed on an 15ddde725dSArmin Le Grand * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16ddde725dSArmin Le Grand * KIND, either express or implied. See the License for the 17ddde725dSArmin Le Grand * specific language governing permissions and limitations 18ddde725dSArmin Le Grand * under the License. 19ddde725dSArmin Le Grand * 20ddde725dSArmin Le Grand *************************************************************/ 21ddde725dSArmin Le Grand 22ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove 23ddde725dSArmin Le Grand #include "precompiled_drawinglayer.hxx" 24ddde725dSArmin Le Grand 25ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> 26ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 27ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> 28ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> 29ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 30ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrixtools.hxx> 31ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygontools.hxx> 32ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygon.hxx> 33ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> 34ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 35ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 36ddde725dSArmin Le Grand #include <drawinglayer/geometry/viewinformation2d.hxx> 37ddde725dSArmin Le Grand 38ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 39ddde725dSArmin Le Grand 40ddde725dSArmin Le Grand using namespace com::sun::star; 41ddde725dSArmin Le Grand 42ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 43ddde725dSArmin Le Grand 4439551d71SArmin Le Grand namespace 4539551d71SArmin Le Grand { calculateStepsForSvgGradient(const basegfx::BColor & rColorA,const basegfx::BColor & rColorB,double fDelta,double fDiscreteUnit)4639551d71SArmin Le Grand sal_uInt32 calculateStepsForSvgGradient(const basegfx::BColor& rColorA, const basegfx::BColor& rColorB, double fDelta, double fDiscreteUnit) 4739551d71SArmin Le Grand { 4839551d71SArmin Le Grand // use color distance, assume to do every color step (full quality) 4939551d71SArmin Le Grand sal_uInt32 nSteps(basegfx::fround(rColorA.getDistance(rColorB) * 255.0)); 5039551d71SArmin Le Grand 5139551d71SArmin Le Grand if(nSteps) 5239551d71SArmin Le Grand { 5339551d71SArmin Le Grand // calc discrete length to change color all 1.5 disctete units (pixels) 5439551d71SArmin Le Grand const sal_uInt32 nDistSteps(basegfx::fround(fDelta / (fDiscreteUnit * 1.5))); 5539551d71SArmin Le Grand 5639551d71SArmin Le Grand nSteps = std::min(nSteps, nDistSteps); 5739551d71SArmin Le Grand } 5839551d71SArmin Le Grand 5939551d71SArmin Le Grand // roughly cut when too big or too small 6039551d71SArmin Le Grand nSteps = std::min(nSteps, sal_uInt32(255)); 6139551d71SArmin Le Grand nSteps = std::max(nSteps, sal_uInt32(1)); 6239551d71SArmin Le Grand 6339551d71SArmin Le Grand return nSteps; 6439551d71SArmin Le Grand } 6539551d71SArmin Le Grand } // end of anonymous namespace 6639551d71SArmin Le Grand 6739551d71SArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 6839551d71SArmin Le Grand 69ddde725dSArmin Le Grand namespace drawinglayer 70ddde725dSArmin Le Grand { 71ddde725dSArmin Le Grand namespace primitive2d 72ddde725dSArmin Le Grand { createSingleGradientEntryFill() const73ddde725dSArmin Le Grand Primitive2DSequence SvgGradientHelper::createSingleGradientEntryFill() const 74ddde725dSArmin Le Grand { 75ddde725dSArmin Le Grand const SvgGradientEntryVector& rEntries = getGradientEntries(); 76ddde725dSArmin Le Grand const sal_uInt32 nCount(rEntries.size()); 77ddde725dSArmin Le Grand Primitive2DSequence xRetval; 78ddde725dSArmin Le Grand 79ddde725dSArmin Le Grand if(nCount) 80ddde725dSArmin Le Grand { 81ddde725dSArmin Le Grand const SvgGradientEntry& rSingleEntry = rEntries[nCount - 1]; 82ddde725dSArmin Le Grand const double fOpacity(rSingleEntry.getOpacity()); 83ddde725dSArmin Le Grand 84ddde725dSArmin Le Grand if(fOpacity > 0.0) 85ddde725dSArmin Le Grand { 86ddde725dSArmin Le Grand Primitive2DReference xRef( 87ddde725dSArmin Le Grand new PolyPolygonColorPrimitive2D( 88ddde725dSArmin Le Grand getPolyPolygon(), 89ddde725dSArmin Le Grand rSingleEntry.getColor())); 90ddde725dSArmin Le Grand 91ddde725dSArmin Le Grand if(fOpacity < 1.0) 92ddde725dSArmin Le Grand { 93ddde725dSArmin Le Grand const Primitive2DSequence aContent(&xRef, 1); 94ddde725dSArmin Le Grand 95ddde725dSArmin Le Grand xRef = Primitive2DReference( 96ddde725dSArmin Le Grand new UnifiedTransparencePrimitive2D( 97ddde725dSArmin Le Grand aContent, 98ddde725dSArmin Le Grand 1.0 - fOpacity)); 99ddde725dSArmin Le Grand } 100ddde725dSArmin Le Grand 101ddde725dSArmin Le Grand xRetval = Primitive2DSequence(&xRef, 1); 102ddde725dSArmin Le Grand } 103ddde725dSArmin Le Grand } 104ddde725dSArmin Le Grand else 105ddde725dSArmin Le Grand { 106ddde725dSArmin Le Grand OSL_ENSURE(false, "Single gradient entry construction without entry (!)"); 107ddde725dSArmin Le Grand } 108ddde725dSArmin Le Grand 109ddde725dSArmin Le Grand return xRetval; 110ddde725dSArmin Le Grand } 111ddde725dSArmin Le Grand checkPreconditions()112ddde725dSArmin Le Grand void SvgGradientHelper::checkPreconditions() 113ddde725dSArmin Le Grand { 114ddde725dSArmin Le Grand mbPreconditionsChecked = true; 115ddde725dSArmin Le Grand const SvgGradientEntryVector& rEntries = getGradientEntries(); 116ddde725dSArmin Le Grand 117ddde725dSArmin Le Grand if(rEntries.empty()) 118ddde725dSArmin Le Grand { 119ddde725dSArmin Le Grand // no fill at all 120ddde725dSArmin Le Grand } 121ddde725dSArmin Le Grand else 122ddde725dSArmin Le Grand { 123ddde725dSArmin Le Grand const sal_uInt32 nCount(rEntries.size()); 124ddde725dSArmin Le Grand 125ddde725dSArmin Le Grand if(1 == nCount) 126ddde725dSArmin Le Grand { 127ddde725dSArmin Le Grand // fill with single existing color 128ddde725dSArmin Le Grand setSingleEntry(); 129ddde725dSArmin Le Grand } 130ddde725dSArmin Le Grand else 131ddde725dSArmin Le Grand { 132ddde725dSArmin Le Grand // sort maGradientEntries when more than one 133ddde725dSArmin Le Grand std::sort(maGradientEntries.begin(), maGradientEntries.end()); 134ddde725dSArmin Le Grand 135ddde725dSArmin Le Grand // gradient with at least two colors 136ddde725dSArmin Le Grand bool bAllInvisible(true); 137ddde725dSArmin Le Grand 138ddde725dSArmin Le Grand for(sal_uInt32 a(0); a < nCount; a++) 139ddde725dSArmin Le Grand { 140ddde725dSArmin Le Grand const SvgGradientEntry& rCandidate = rEntries[a]; 141ddde725dSArmin Le Grand 142ddde725dSArmin Le Grand if(basegfx::fTools::equalZero(rCandidate.getOpacity())) 143ddde725dSArmin Le Grand { 144ddde725dSArmin Le Grand // invisible 145ddde725dSArmin Le Grand mbFullyOpaque = false; 146ddde725dSArmin Le Grand } 147ddde725dSArmin Le Grand else if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0)) 148ddde725dSArmin Le Grand { 149ddde725dSArmin Le Grand // completely opaque 150ddde725dSArmin Le Grand bAllInvisible = false; 151ddde725dSArmin Le Grand } 152ddde725dSArmin Le Grand else 153ddde725dSArmin Le Grand { 154ddde725dSArmin Le Grand // opacity 155ddde725dSArmin Le Grand bAllInvisible = false; 156ddde725dSArmin Le Grand mbFullyOpaque = false; 157ddde725dSArmin Le Grand } 158ddde725dSArmin Le Grand } 159ddde725dSArmin Le Grand 160ddde725dSArmin Le Grand if(bAllInvisible) 161ddde725dSArmin Le Grand { 162ddde725dSArmin Le Grand // all invisible, nothing to do 163ddde725dSArmin Le Grand } 164ddde725dSArmin Le Grand else 165ddde725dSArmin Le Grand { 166ddde725dSArmin Le Grand const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); 167ddde725dSArmin Le Grand 168ddde725dSArmin Le Grand if(aPolyRange.isEmpty()) 169ddde725dSArmin Le Grand { 170ddde725dSArmin Le Grand // no range to fill, nothing to do 171ddde725dSArmin Le Grand } 172ddde725dSArmin Le Grand else 173ddde725dSArmin Le Grand { 174ddde725dSArmin Le Grand const double fPolyWidth(aPolyRange.getWidth()); 175ddde725dSArmin Le Grand const double fPolyHeight(aPolyRange.getHeight()); 176ddde725dSArmin Le Grand 177ddde725dSArmin Le Grand if(basegfx::fTools::equalZero(fPolyWidth) || basegfx::fTools::equalZero(fPolyHeight)) 178ddde725dSArmin Le Grand { 179ddde725dSArmin Le Grand // no width/height to fill, nothing to do 180ddde725dSArmin Le Grand } 181ddde725dSArmin Le Grand else 182ddde725dSArmin Le Grand { 183ddde725dSArmin Le Grand mbCreatesContent = true; 184ddde725dSArmin Le Grand } 185ddde725dSArmin Le Grand } 186ddde725dSArmin Le Grand } 187ddde725dSArmin Le Grand } 188ddde725dSArmin Le Grand } 189ddde725dSArmin Le Grand } 190ddde725dSArmin Le Grand createRun(Primitive2DVector & rTargetColor,Primitive2DVector & rTargetOpacity,double fPos,double fMax,const SvgGradientEntryVector & rEntries,sal_Int32 nOffset) const191ddde725dSArmin Le Grand double SvgGradientHelper::createRun( 192ddde725dSArmin Le Grand Primitive2DVector& rTargetColor, 193ddde725dSArmin Le Grand Primitive2DVector& rTargetOpacity, 194ddde725dSArmin Le Grand double fPos, 195ddde725dSArmin Le Grand double fMax, 196ddde725dSArmin Le Grand const SvgGradientEntryVector& rEntries, 197ddde725dSArmin Le Grand sal_Int32 nOffset) const 198ddde725dSArmin Le Grand { 199ddde725dSArmin Le Grand const sal_uInt32 nCount(rEntries.size()); 200ddde725dSArmin Le Grand 201ddde725dSArmin Le Grand if(nCount) 202ddde725dSArmin Le Grand { 203ddde725dSArmin Le Grand const SvgGradientEntry& rStart = rEntries[0]; 204ddde725dSArmin Le Grand const bool bCreateStartPad(fPos < 0.0 && Spread_pad == getSpreadMethod()); 205ddde725dSArmin Le Grand const bool bCreateStartFill(rStart.getOffset() > 0.0); 206ddde725dSArmin Le Grand sal_uInt32 nIndex(0); 207ddde725dSArmin Le Grand 208ddde725dSArmin Le Grand if(bCreateStartPad || bCreateStartFill) 209ddde725dSArmin Le Grand { 210ddde725dSArmin Le Grand const SvgGradientEntry aTemp(bCreateStartPad ? fPos : 0.0, rStart.getColor(), rStart.getOpacity()); 211ddde725dSArmin Le Grand 212ddde725dSArmin Le Grand createAtom(rTargetColor, rTargetOpacity, aTemp, rStart, nOffset); 213ddde725dSArmin Le Grand fPos = rStart.getOffset(); 214ddde725dSArmin Le Grand } 215ddde725dSArmin Le Grand 216ddde725dSArmin Le Grand while(fPos < 1.0 && nIndex + 1 < nCount) 217ddde725dSArmin Le Grand { 218ddde725dSArmin Le Grand const SvgGradientEntry& rCandidateA = rEntries[nIndex++]; 219ddde725dSArmin Le Grand const SvgGradientEntry& rCandidateB = rEntries[nIndex]; 220ddde725dSArmin Le Grand 221ddde725dSArmin Le Grand createAtom(rTargetColor, rTargetOpacity, rCandidateA, rCandidateB, nOffset); 222ddde725dSArmin Le Grand fPos = rCandidateB.getOffset(); 223ddde725dSArmin Le Grand } 224ddde725dSArmin Le Grand 225ddde725dSArmin Le Grand const SvgGradientEntry& rEnd = rEntries[nCount - 1]; 226ddde725dSArmin Le Grand const bool bCreateEndPad(fPos < fMax && Spread_pad == getSpreadMethod()); 227ddde725dSArmin Le Grand const bool bCreateEndFill(rEnd.getOffset() < 1.0); 228ddde725dSArmin Le Grand 229ddde725dSArmin Le Grand if(bCreateEndPad || bCreateEndFill) 230ddde725dSArmin Le Grand { 231ddde725dSArmin Le Grand fPos = bCreateEndPad ? fMax : 1.0; 232ddde725dSArmin Le Grand const SvgGradientEntry aTemp(fPos, rEnd.getColor(), rEnd.getOpacity()); 233ddde725dSArmin Le Grand 234ddde725dSArmin Le Grand createAtom(rTargetColor, rTargetOpacity, rEnd, aTemp, nOffset); 235ddde725dSArmin Le Grand } 236ddde725dSArmin Le Grand } 237ddde725dSArmin Le Grand else 238ddde725dSArmin Le Grand { 239ddde725dSArmin Le Grand OSL_ENSURE(false, "GradientAtom creation without ColorStops (!)"); 240ddde725dSArmin Le Grand fPos = fMax; 241ddde725dSArmin Le Grand } 242ddde725dSArmin Le Grand 243ddde725dSArmin Le Grand return fPos; 244ddde725dSArmin Le Grand } 245ddde725dSArmin Le Grand createResult(const Primitive2DVector & rTargetColor,const Primitive2DVector & rTargetOpacity,const basegfx::B2DHomMatrix & rUnitGradientToObject,bool bInvert) const246ddde725dSArmin Le Grand Primitive2DSequence SvgGradientHelper::createResult( 247ddde725dSArmin Le Grand const Primitive2DVector& rTargetColor, 248ddde725dSArmin Le Grand const Primitive2DVector& rTargetOpacity, 249ddde725dSArmin Le Grand const basegfx::B2DHomMatrix& rUnitGradientToObject, 250ddde725dSArmin Le Grand bool bInvert) const 251ddde725dSArmin Le Grand { 252ddde725dSArmin Le Grand Primitive2DSequence xRetval; 253ddde725dSArmin Le Grand const Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(rTargetColor, bInvert)); 254ddde725dSArmin Le Grand const Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(rTargetOpacity, bInvert)); 255ddde725dSArmin Le Grand 256ddde725dSArmin Le Grand if(aTargetColorEntries.hasElements()) 257ddde725dSArmin Le Grand { 258ddde725dSArmin Le Grand Primitive2DReference xRefContent; 259ddde725dSArmin Le Grand 260ddde725dSArmin Le Grand if(aTargetOpacityEntries.hasElements()) 261ddde725dSArmin Le Grand { 262ddde725dSArmin Le Grand const Primitive2DReference xRefOpacity = new TransparencePrimitive2D( 263ddde725dSArmin Le Grand aTargetColorEntries, 264ddde725dSArmin Le Grand aTargetOpacityEntries); 265ddde725dSArmin Le Grand 266ddde725dSArmin Le Grand xRefContent = new TransformPrimitive2D( 267ddde725dSArmin Le Grand rUnitGradientToObject, 268ddde725dSArmin Le Grand Primitive2DSequence(&xRefOpacity, 1)); 269ddde725dSArmin Le Grand } 270ddde725dSArmin Le Grand else 271ddde725dSArmin Le Grand { 272ddde725dSArmin Le Grand xRefContent = new TransformPrimitive2D( 273ddde725dSArmin Le Grand rUnitGradientToObject, 274ddde725dSArmin Le Grand aTargetColorEntries); 275ddde725dSArmin Le Grand } 276ddde725dSArmin Le Grand 277ddde725dSArmin Le Grand xRefContent = new MaskPrimitive2D( 278ddde725dSArmin Le Grand getPolyPolygon(), 279ddde725dSArmin Le Grand Primitive2DSequence(&xRefContent, 1)); 280ddde725dSArmin Le Grand 281ddde725dSArmin Le Grand xRetval = Primitive2DSequence(&xRefContent, 1); 282ddde725dSArmin Le Grand } 283ddde725dSArmin Le Grand 284ddde725dSArmin Le Grand return xRetval; 285ddde725dSArmin Le Grand } 286ddde725dSArmin Le Grand SvgGradientHelper(const basegfx::B2DHomMatrix & rGradientTransform,const basegfx::B2DPolyPolygon & rPolyPolygon,const SvgGradientEntryVector & rGradientEntries,const basegfx::B2DPoint & rStart,bool bUseUnitCoordinates,SpreadMethod aSpreadMethod)287ddde725dSArmin Le Grand SvgGradientHelper::SvgGradientHelper( 28801e92ad6SArmin Le Grand const basegfx::B2DHomMatrix& rGradientTransform, 289ddde725dSArmin Le Grand const basegfx::B2DPolyPolygon& rPolyPolygon, 290ddde725dSArmin Le Grand const SvgGradientEntryVector& rGradientEntries, 291ddde725dSArmin Le Grand const basegfx::B2DPoint& rStart, 292804e0487SArmin Le Grand bool bUseUnitCoordinates, 29339551d71SArmin Le Grand SpreadMethod aSpreadMethod) 29401e92ad6SArmin Le Grand : maGradientTransform(rGradientTransform), 29501e92ad6SArmin Le Grand maPolyPolygon(rPolyPolygon), 296ddde725dSArmin Le Grand maGradientEntries(rGradientEntries), 297ddde725dSArmin Le Grand maStart(rStart), 298ddde725dSArmin Le Grand maSpreadMethod(aSpreadMethod), 299ddde725dSArmin Le Grand mbPreconditionsChecked(false), 300ddde725dSArmin Le Grand mbCreatesContent(false), 301ddde725dSArmin Le Grand mbSingleEntry(false), 302804e0487SArmin Le Grand mbFullyOpaque(true), 303804e0487SArmin Le Grand mbUseUnitCoordinates(bUseUnitCoordinates) 304ddde725dSArmin Le Grand { 305ddde725dSArmin Le Grand } 306ddde725dSArmin Le Grand ~SvgGradientHelper()307*895ed544SArmin Le Grand SvgGradientHelper::~SvgGradientHelper() 308*895ed544SArmin Le Grand { 309*895ed544SArmin Le Grand } 310*895ed544SArmin Le Grand operator ==(const SvgGradientHelper & rSvgGradientHelper) const311ddde725dSArmin Le Grand bool SvgGradientHelper::operator==(const SvgGradientHelper& rSvgGradientHelper) const 312ddde725dSArmin Le Grand { 313ddde725dSArmin Le Grand const SvgGradientHelper& rCompare = static_cast< const SvgGradientHelper& >(rSvgGradientHelper); 314ddde725dSArmin Le Grand 31501e92ad6SArmin Le Grand return (getGradientTransform() == rCompare.getGradientTransform() 31601e92ad6SArmin Le Grand && getPolyPolygon() == rCompare.getPolyPolygon() 317ddde725dSArmin Le Grand && getGradientEntries() == rCompare.getGradientEntries() 318ddde725dSArmin Le Grand && getStart() == rCompare.getStart() 319804e0487SArmin Le Grand && getUseUnitCoordinates() == rCompare.getUseUnitCoordinates() 32039551d71SArmin Le Grand && getSpreadMethod() == rCompare.getSpreadMethod()); 321ddde725dSArmin Le Grand } 322ddde725dSArmin Le Grand 323ddde725dSArmin Le Grand } // end of namespace primitive2d 324ddde725dSArmin Le Grand } // end of namespace drawinglayer 325ddde725dSArmin Le Grand 326ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 327ddde725dSArmin Le Grand 328ddde725dSArmin Le Grand namespace drawinglayer 329ddde725dSArmin Le Grand { 330ddde725dSArmin Le Grand namespace primitive2d 331ddde725dSArmin Le Grand { checkPreconditions()332ddde725dSArmin Le Grand void SvgLinearGradientPrimitive2D::checkPreconditions() 333ddde725dSArmin Le Grand { 334ddde725dSArmin Le Grand // call parent 335ddde725dSArmin Le Grand SvgGradientHelper::checkPreconditions(); 336ddde725dSArmin Le Grand 337ddde725dSArmin Le Grand if(getCreatesContent()) 338ddde725dSArmin Le Grand { 339ddde725dSArmin Le Grand // Check Vector 340ddde725dSArmin Le Grand const basegfx::B2DVector aVector(getEnd() - getStart()); 341ddde725dSArmin Le Grand 342ddde725dSArmin Le Grand if(basegfx::fTools::equalZero(aVector.getX()) && basegfx::fTools::equalZero(aVector.getY())) 343ddde725dSArmin Le Grand { 344ddde725dSArmin Le Grand // fill with single color using last stop color 345ddde725dSArmin Le Grand setSingleEntry(); 346ddde725dSArmin Le Grand } 347ddde725dSArmin Le Grand } 348ddde725dSArmin Le Grand } 349ddde725dSArmin Le Grand createAtom(Primitive2DVector & rTargetColor,Primitive2DVector & rTargetOpacity,const SvgGradientEntry & rFrom,const SvgGradientEntry & rTo,sal_Int32 nOffset) const350ddde725dSArmin Le Grand void SvgLinearGradientPrimitive2D::createAtom( 351ddde725dSArmin Le Grand Primitive2DVector& rTargetColor, 352ddde725dSArmin Le Grand Primitive2DVector& rTargetOpacity, 353ddde725dSArmin Le Grand const SvgGradientEntry& rFrom, 354ddde725dSArmin Le Grand const SvgGradientEntry& rTo, 355ddde725dSArmin Le Grand sal_Int32 nOffset) const 356ddde725dSArmin Le Grand { 357ddde725dSArmin Le Grand // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset()) 358ddde725dSArmin Le Grand if(rFrom.getOffset() == rTo.getOffset()) 359ddde725dSArmin Le Grand { 360ddde725dSArmin Le Grand OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)"); 361ddde725dSArmin Le Grand } 362ddde725dSArmin Le Grand else 363ddde725dSArmin Le Grand { 364ddde725dSArmin Le Grand rTargetColor.push_back( 365ddde725dSArmin Le Grand new SvgLinearAtomPrimitive2D( 366ddde725dSArmin Le Grand rFrom.getColor(), rFrom.getOffset() + nOffset, 36739551d71SArmin Le Grand rTo.getColor(), rTo.getOffset() + nOffset)); 368ddde725dSArmin Le Grand 369025b0597SArmin Le Grand if(!getFullyOpaque()) 370025b0597SArmin Le Grand { 371ddde725dSArmin Le Grand const double fTransFrom(1.0 - rFrom.getOpacity()); 372ddde725dSArmin Le Grand const double fTransTo(1.0 - rTo.getOpacity()); 373025b0597SArmin Le Grand const basegfx::BColor aColorFrom(fTransFrom, fTransFrom, fTransFrom); 374025b0597SArmin Le Grand const basegfx::BColor aColorTo(fTransTo, fTransTo, fTransTo); 375ddde725dSArmin Le Grand 376ddde725dSArmin Le Grand rTargetOpacity.push_back( 377ddde725dSArmin Le Grand new SvgLinearAtomPrimitive2D( 378025b0597SArmin Le Grand aColorFrom, rFrom.getOffset() + nOffset, 379025b0597SArmin Le Grand aColorTo, rTo.getOffset() + nOffset)); 380025b0597SArmin Le Grand } 381ddde725dSArmin Le Grand } 382ddde725dSArmin Le Grand } 383ddde725dSArmin Le Grand create2DDecomposition(const geometry::ViewInformation2D &) const384ddde725dSArmin Le Grand Primitive2DSequence SvgLinearGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 385ddde725dSArmin Le Grand { 386ddde725dSArmin Le Grand Primitive2DSequence xRetval; 387ddde725dSArmin Le Grand 388ddde725dSArmin Le Grand if(!getPreconditionsChecked()) 389ddde725dSArmin Le Grand { 390ddde725dSArmin Le Grand const_cast< SvgLinearGradientPrimitive2D* >(this)->checkPreconditions(); 391ddde725dSArmin Le Grand } 392ddde725dSArmin Le Grand 393ddde725dSArmin Le Grand if(getSingleEntry()) 394ddde725dSArmin Le Grand { 395ddde725dSArmin Le Grand // fill with last existing color 396ddde725dSArmin Le Grand xRetval = createSingleGradientEntryFill(); 397ddde725dSArmin Le Grand } 398ddde725dSArmin Le Grand else if(getCreatesContent()) 399ddde725dSArmin Le Grand { 400ddde725dSArmin Le Grand // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely 401ddde725dSArmin Le Grand // invisible, width and height to fill are not empty 402ddde725dSArmin Le Grand const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); 403ddde725dSArmin Le Grand const double fPolyWidth(aPolyRange.getWidth()); 404ddde725dSArmin Le Grand const double fPolyHeight(aPolyRange.getHeight()); 405ddde725dSArmin Le Grand 406ddde725dSArmin Le Grand // create ObjectTransform based on polygon range 407ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aObjectTransform( 408ddde725dSArmin Le Grand basegfx::tools::createScaleTranslateB2DHomMatrix( 409ddde725dSArmin Le Grand fPolyWidth, fPolyHeight, 410ddde725dSArmin Le Grand aPolyRange.getMinX(), aPolyRange.getMinY())); 411804e0487SArmin Le Grand basegfx::B2DHomMatrix aUnitGradientToObject; 412ddde725dSArmin Le Grand 413804e0487SArmin Le Grand if(getUseUnitCoordinates()) 414804e0487SArmin Le Grand { 415804e0487SArmin Le Grand // interpret in unit coordinate system -> object aspect ratio will scale result 416804e0487SArmin Le Grand // create unit transform from unit vector [0.0 .. 1.0] along the X-Axis to given 417804e0487SArmin Le Grand // gradient vector defined by Start,End 418804e0487SArmin Le Grand const basegfx::B2DVector aVector(getEnd() - getStart()); 419804e0487SArmin Le Grand const double fVectorLength(aVector.getLength()); 420804e0487SArmin Le Grand 421915dc3acSArmin Le Grand aUnitGradientToObject.scale(fVectorLength, 1.0); 422915dc3acSArmin Le Grand aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX())); 423915dc3acSArmin Le Grand aUnitGradientToObject.translate(getStart().getX(), getStart().getY()); 424915dc3acSArmin Le Grand 425915dc3acSArmin Le Grand if(!getGradientTransform().isIdentity()) 426915dc3acSArmin Le Grand { 427915dc3acSArmin Le Grand aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject; 428915dc3acSArmin Le Grand } 429804e0487SArmin Le Grand 430804e0487SArmin Le Grand // create full transform from unit gradient coordinates to object coordinates 431804e0487SArmin Le Grand // including the SvgGradient transformation 432915dc3acSArmin Le Grand aUnitGradientToObject = aObjectTransform * aUnitGradientToObject; 433804e0487SArmin Le Grand } 434804e0487SArmin Le Grand else 435804e0487SArmin Le Grand { 436804e0487SArmin Le Grand // interpret in object coordinate system -> object aspect ratio will not scale result 43786d97322SArmin Le Grand const basegfx::B2DPoint aStart(aObjectTransform * getStart()); 43886d97322SArmin Le Grand const basegfx::B2DPoint aEnd(aObjectTransform * getEnd()); 43986d97322SArmin Le Grand const basegfx::B2DVector aVector(aEnd - aStart); 440ddde725dSArmin Le Grand 441804e0487SArmin Le Grand aUnitGradientToObject.scale(aVector.getLength(), 1.0); 44286d97322SArmin Le Grand aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX())); 44386d97322SArmin Le Grand aUnitGradientToObject.translate(aStart.getX(), aStart.getY()); 444ddde725dSArmin Le Grand 44501e92ad6SArmin Le Grand if(!getGradientTransform().isIdentity()) 44601e92ad6SArmin Le Grand { 44701e92ad6SArmin Le Grand aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject; 44801e92ad6SArmin Le Grand } 449915dc3acSArmin Le Grand } 45001e92ad6SArmin Le Grand 451ddde725dSArmin Le Grand // create inverse from it 452ddde725dSArmin Le Grand basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject); 453ddde725dSArmin Le Grand aObjectToUnitGradient.invert(); 454ddde725dSArmin Le Grand 455ddde725dSArmin Le Grand // back-transform polygon to unit gradient coordinates and get 456ddde725dSArmin Le Grand // UnitRage. This is the range the gradient has to cover 457ddde725dSArmin Le Grand basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon()); 458ddde725dSArmin Le Grand aUnitPoly.transform(aObjectToUnitGradient); 459ddde725dSArmin Le Grand const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange()); 460ddde725dSArmin Le Grand 461ddde725dSArmin Le Grand // prepare result vectors 462ddde725dSArmin Le Grand Primitive2DVector aTargetColor; 463ddde725dSArmin Le Grand Primitive2DVector aTargetOpacity; 464ddde725dSArmin Le Grand 465ddde725dSArmin Le Grand if(basegfx::fTools::more(aUnitRange.getWidth(), 0.0)) 466ddde725dSArmin Le Grand { 467ddde725dSArmin Le Grand // add a pre-multiply to aUnitGradientToObject to allow 468ddde725dSArmin Le Grand // multiplication of the polygon(xl, 0.0, xr, 1.0) 469ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aPreMultiply( 470ddde725dSArmin Le Grand basegfx::tools::createScaleTranslateB2DHomMatrix( 471ddde725dSArmin Le Grand 1.0, aUnitRange.getHeight(), 0.0, aUnitRange.getMinY())); 472ddde725dSArmin Le Grand aUnitGradientToObject = aUnitGradientToObject * aPreMultiply; 473ddde725dSArmin Le Grand 474ddde725dSArmin Le Grand // create central run, may also already do all necessary when 475ddde725dSArmin Le Grand // Spread_pad is set as SpreadMethod and/or the range is smaller 476ddde725dSArmin Le Grand double fPos(createRun(aTargetColor, aTargetOpacity, aUnitRange.getMinX(), aUnitRange.getMaxX(), getGradientEntries(), 0)); 477ddde725dSArmin Le Grand 478ddde725dSArmin Le Grand if(fPos < aUnitRange.getMaxX()) 479ddde725dSArmin Le Grand { 480ddde725dSArmin Le Grand // can only happen when SpreadMethod is Spread_reflect or Spread_repeat, 481ddde725dSArmin Le Grand // else the start and end pads are already created and fPos == aUnitRange.getMaxX(). 482ddde725dSArmin Le Grand // Its possible to express the repeated linear gradient by adding the 483ddde725dSArmin Le Grand // transformed central run. Crete it this way 484ddde725dSArmin Le Grand Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(aTargetColor)); 485ddde725dSArmin Le Grand Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(aTargetOpacity)); 486ddde725dSArmin Le Grand aTargetColor.clear(); 487ddde725dSArmin Le Grand aTargetOpacity.clear(); 488ddde725dSArmin Le Grand 489ddde725dSArmin Le Grand if(aTargetColorEntries.hasElements()) 490ddde725dSArmin Le Grand { 491ddde725dSArmin Le Grand // add original central run as group primitive 492ddde725dSArmin Le Grand aTargetColor.push_back(new GroupPrimitive2D(aTargetColorEntries)); 493ddde725dSArmin Le Grand 494ddde725dSArmin Le Grand if(aTargetOpacityEntries.hasElements()) 495ddde725dSArmin Le Grand { 496ddde725dSArmin Le Grand aTargetOpacity.push_back(new GroupPrimitive2D(aTargetOpacityEntries)); 497ddde725dSArmin Le Grand } 498ddde725dSArmin Le Grand 499ddde725dSArmin Le Grand // add negative runs 500ddde725dSArmin Le Grand fPos = 0.0; 501ddde725dSArmin Le Grand sal_Int32 nOffset(0); 502ddde725dSArmin Le Grand 503ddde725dSArmin Le Grand while(fPos > aUnitRange.getMinX()) 504ddde725dSArmin Le Grand { 505ddde725dSArmin Le Grand fPos -= 1.0; 506ddde725dSArmin Le Grand nOffset++; 507ddde725dSArmin Le Grand 508ddde725dSArmin Le Grand basegfx::B2DHomMatrix aTransform; 509ddde725dSArmin Le Grand const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2)); 510ddde725dSArmin Le Grand 511ddde725dSArmin Le Grand if(bMirror) 512ddde725dSArmin Le Grand { 513ddde725dSArmin Le Grand aTransform.scale(-1.0, 1.0); 514ddde725dSArmin Le Grand aTransform.translate(fPos + 1.0, 0.0); 515ddde725dSArmin Le Grand } 516ddde725dSArmin Le Grand else 517ddde725dSArmin Le Grand { 518ddde725dSArmin Le Grand aTransform.translate(fPos, 0.0); 519ddde725dSArmin Le Grand } 520ddde725dSArmin Le Grand 521ddde725dSArmin Le Grand aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries)); 522ddde725dSArmin Le Grand 523ddde725dSArmin Le Grand if(aTargetOpacityEntries.hasElements()) 524ddde725dSArmin Le Grand { 525ddde725dSArmin Le Grand aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries)); 526ddde725dSArmin Le Grand } 527ddde725dSArmin Le Grand } 528ddde725dSArmin Le Grand 529ddde725dSArmin Le Grand // add positive runs 530ddde725dSArmin Le Grand fPos = 1.0; 531ddde725dSArmin Le Grand nOffset = 1; 532ddde725dSArmin Le Grand 533ddde725dSArmin Le Grand while(fPos < aUnitRange.getMaxX()) 534ddde725dSArmin Le Grand { 535ddde725dSArmin Le Grand basegfx::B2DHomMatrix aTransform; 536ddde725dSArmin Le Grand const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2)); 537ddde725dSArmin Le Grand 538ddde725dSArmin Le Grand if(bMirror) 539ddde725dSArmin Le Grand { 540ddde725dSArmin Le Grand aTransform.scale(-1.0, 1.0); 541ddde725dSArmin Le Grand aTransform.translate(fPos + 1.0, 0.0); 542ddde725dSArmin Le Grand } 543ddde725dSArmin Le Grand else 544ddde725dSArmin Le Grand { 545ddde725dSArmin Le Grand aTransform.translate(fPos, 0.0); 546ddde725dSArmin Le Grand } 547ddde725dSArmin Le Grand 548ddde725dSArmin Le Grand aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries)); 549ddde725dSArmin Le Grand 550ddde725dSArmin Le Grand if(aTargetOpacityEntries.hasElements()) 551ddde725dSArmin Le Grand { 552ddde725dSArmin Le Grand aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries)); 553ddde725dSArmin Le Grand } 554ddde725dSArmin Le Grand 555ddde725dSArmin Le Grand fPos += 1.0; 556ddde725dSArmin Le Grand nOffset++; 557ddde725dSArmin Le Grand } 558ddde725dSArmin Le Grand } 559ddde725dSArmin Le Grand } 560ddde725dSArmin Le Grand } 561ddde725dSArmin Le Grand 562ddde725dSArmin Le Grand xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject); 563ddde725dSArmin Le Grand } 564ddde725dSArmin Le Grand 565ddde725dSArmin Le Grand return xRetval; 566ddde725dSArmin Le Grand } 567ddde725dSArmin Le Grand SvgLinearGradientPrimitive2D(const basegfx::B2DHomMatrix & rGradientTransform,const basegfx::B2DPolyPolygon & rPolyPolygon,const SvgGradientEntryVector & rGradientEntries,const basegfx::B2DPoint & rStart,const basegfx::B2DPoint & rEnd,bool bUseUnitCoordinates,SpreadMethod aSpreadMethod)568ddde725dSArmin Le Grand SvgLinearGradientPrimitive2D::SvgLinearGradientPrimitive2D( 56901e92ad6SArmin Le Grand const basegfx::B2DHomMatrix& rGradientTransform, 570ddde725dSArmin Le Grand const basegfx::B2DPolyPolygon& rPolyPolygon, 571ddde725dSArmin Le Grand const SvgGradientEntryVector& rGradientEntries, 572ddde725dSArmin Le Grand const basegfx::B2DPoint& rStart, 573ddde725dSArmin Le Grand const basegfx::B2DPoint& rEnd, 574804e0487SArmin Le Grand bool bUseUnitCoordinates, 57539551d71SArmin Le Grand SpreadMethod aSpreadMethod) 576ddde725dSArmin Le Grand : BufferedDecompositionPrimitive2D(), 57701e92ad6SArmin Le Grand SvgGradientHelper(rGradientTransform, rPolyPolygon, rGradientEntries, rStart, bUseUnitCoordinates, aSpreadMethod), 578ddde725dSArmin Le Grand maEnd(rEnd) 579ddde725dSArmin Le Grand { 580ddde725dSArmin Le Grand } 581ddde725dSArmin Le Grand ~SvgLinearGradientPrimitive2D()582025b0597SArmin Le Grand SvgLinearGradientPrimitive2D::~SvgLinearGradientPrimitive2D() 583025b0597SArmin Le Grand { 584025b0597SArmin Le Grand } 585025b0597SArmin Le Grand operator ==(const BasePrimitive2D & rPrimitive) const586ddde725dSArmin Le Grand bool SvgLinearGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 587ddde725dSArmin Le Grand { 588ddde725dSArmin Le Grand const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive); 589ddde725dSArmin Le Grand 590ddde725dSArmin Le Grand if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper)) 591ddde725dSArmin Le Grand { 592ddde725dSArmin Le Grand const SvgLinearGradientPrimitive2D& rCompare = static_cast< const SvgLinearGradientPrimitive2D& >(rPrimitive); 593ddde725dSArmin Le Grand 594ddde725dSArmin Le Grand return (getEnd() == rCompare.getEnd()); 595ddde725dSArmin Le Grand } 596ddde725dSArmin Le Grand 597ddde725dSArmin Le Grand return false; 598ddde725dSArmin Le Grand } 599ddde725dSArmin Le Grand getB2DRange(const geometry::ViewInformation2D &) const600ddde725dSArmin Le Grand basegfx::B2DRange SvgLinearGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const 601ddde725dSArmin Le Grand { 602ddde725dSArmin Le Grand // return ObjectRange 603ddde725dSArmin Le Grand return getPolyPolygon().getB2DRange(); 604ddde725dSArmin Le Grand } 605ddde725dSArmin Le Grand 606ddde725dSArmin Le Grand // provide unique ID 607ddde725dSArmin Le Grand ImplPrimitrive2DIDBlock(SvgLinearGradientPrimitive2D, PRIMITIVE2D_ID_SVGLINEARGRADIENTPRIMITIVE2D) 608ddde725dSArmin Le Grand 609ddde725dSArmin Le Grand } // end of namespace primitive2d 610ddde725dSArmin Le Grand } // end of namespace drawinglayer 611ddde725dSArmin Le Grand 612ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 613ddde725dSArmin Le Grand 614ddde725dSArmin Le Grand namespace drawinglayer 615ddde725dSArmin Le Grand { 616ddde725dSArmin Le Grand namespace primitive2d 617ddde725dSArmin Le Grand { checkPreconditions()618ddde725dSArmin Le Grand void SvgRadialGradientPrimitive2D::checkPreconditions() 619ddde725dSArmin Le Grand { 620ddde725dSArmin Le Grand // call parent 621ddde725dSArmin Le Grand SvgGradientHelper::checkPreconditions(); 622ddde725dSArmin Le Grand 623ddde725dSArmin Le Grand if(getCreatesContent()) 624ddde725dSArmin Le Grand { 625ddde725dSArmin Le Grand // Check Radius 626ddde725dSArmin Le Grand if(basegfx::fTools::equalZero(getRadius())) 627ddde725dSArmin Le Grand { 628ddde725dSArmin Le Grand // fill with single color using last stop color 629ddde725dSArmin Le Grand setSingleEntry(); 630ddde725dSArmin Le Grand } 631ddde725dSArmin Le Grand } 632ddde725dSArmin Le Grand } 633ddde725dSArmin Le Grand createAtom(Primitive2DVector & rTargetColor,Primitive2DVector & rTargetOpacity,const SvgGradientEntry & rFrom,const SvgGradientEntry & rTo,sal_Int32 nOffset) const634ddde725dSArmin Le Grand void SvgRadialGradientPrimitive2D::createAtom( 635ddde725dSArmin Le Grand Primitive2DVector& rTargetColor, 636ddde725dSArmin Le Grand Primitive2DVector& rTargetOpacity, 637ddde725dSArmin Le Grand const SvgGradientEntry& rFrom, 638ddde725dSArmin Le Grand const SvgGradientEntry& rTo, 639ddde725dSArmin Le Grand sal_Int32 nOffset) const 640ddde725dSArmin Le Grand { 641ddde725dSArmin Le Grand // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset()) 642ddde725dSArmin Le Grand if(rFrom.getOffset() == rTo.getOffset()) 643ddde725dSArmin Le Grand { 644ddde725dSArmin Le Grand OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)"); 645ddde725dSArmin Le Grand } 646ddde725dSArmin Le Grand else 647ddde725dSArmin Le Grand { 648ddde725dSArmin Le Grand const double fScaleFrom(rFrom.getOffset() + nOffset); 649ddde725dSArmin Le Grand const double fScaleTo(rTo.getOffset() + nOffset); 650ddde725dSArmin Le Grand 651ddde725dSArmin Le Grand if(isFocalSet()) 652ddde725dSArmin Le Grand { 653ddde725dSArmin Le Grand const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom)); 654ddde725dSArmin Le Grand const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo)); 655ddde725dSArmin Le Grand 656ddde725dSArmin Le Grand rTargetColor.push_back( 657ddde725dSArmin Le Grand new SvgRadialAtomPrimitive2D( 658ddde725dSArmin Le Grand rFrom.getColor(), fScaleFrom, aTranslateFrom, 65939551d71SArmin Le Grand rTo.getColor(), fScaleTo, aTranslateTo)); 660ddde725dSArmin Le Grand } 661ddde725dSArmin Le Grand else 662ddde725dSArmin Le Grand { 663ddde725dSArmin Le Grand rTargetColor.push_back( 664ddde725dSArmin Le Grand new SvgRadialAtomPrimitive2D( 665ddde725dSArmin Le Grand rFrom.getColor(), fScaleFrom, 66639551d71SArmin Le Grand rTo.getColor(), fScaleTo)); 667ddde725dSArmin Le Grand } 668ddde725dSArmin Le Grand 669025b0597SArmin Le Grand if(!getFullyOpaque()) 670025b0597SArmin Le Grand { 671ddde725dSArmin Le Grand const double fTransFrom(1.0 - rFrom.getOpacity()); 672ddde725dSArmin Le Grand const double fTransTo(1.0 - rTo.getOpacity()); 673ddde725dSArmin Le Grand const basegfx::BColor aColorFrom(fTransFrom, fTransFrom, fTransFrom); 674ddde725dSArmin Le Grand const basegfx::BColor aColorTo(fTransTo, fTransTo, fTransTo); 675ddde725dSArmin Le Grand 676ddde725dSArmin Le Grand if(isFocalSet()) 677ddde725dSArmin Le Grand { 678ddde725dSArmin Le Grand const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom)); 679ddde725dSArmin Le Grand const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo)); 680ddde725dSArmin Le Grand 681ddde725dSArmin Le Grand rTargetOpacity.push_back( 682ddde725dSArmin Le Grand new SvgRadialAtomPrimitive2D( 683ddde725dSArmin Le Grand aColorFrom, fScaleFrom, aTranslateFrom, 68439551d71SArmin Le Grand aColorTo, fScaleTo, aTranslateTo)); 685ddde725dSArmin Le Grand } 686ddde725dSArmin Le Grand else 687ddde725dSArmin Le Grand { 688ddde725dSArmin Le Grand rTargetOpacity.push_back( 689ddde725dSArmin Le Grand new SvgRadialAtomPrimitive2D( 690ddde725dSArmin Le Grand aColorFrom, fScaleFrom, 69139551d71SArmin Le Grand aColorTo, fScaleTo)); 692ddde725dSArmin Le Grand } 693ddde725dSArmin Le Grand } 694ddde725dSArmin Le Grand } 695025b0597SArmin Le Grand } 696ddde725dSArmin Le Grand getMirroredGradientEntries() const697ddde725dSArmin Le Grand const SvgGradientEntryVector& SvgRadialGradientPrimitive2D::getMirroredGradientEntries() const 698ddde725dSArmin Le Grand { 699ddde725dSArmin Le Grand if(maMirroredGradientEntries.empty() && !getGradientEntries().empty()) 700ddde725dSArmin Le Grand { 701ddde725dSArmin Le Grand const_cast< SvgRadialGradientPrimitive2D* >(this)->createMirroredGradientEntries(); 702ddde725dSArmin Le Grand } 703ddde725dSArmin Le Grand 704ddde725dSArmin Le Grand return maMirroredGradientEntries; 705ddde725dSArmin Le Grand } 706ddde725dSArmin Le Grand createMirroredGradientEntries()707ddde725dSArmin Le Grand void SvgRadialGradientPrimitive2D::createMirroredGradientEntries() 708ddde725dSArmin Le Grand { 709ddde725dSArmin Le Grand if(maMirroredGradientEntries.empty() && !getGradientEntries().empty()) 710ddde725dSArmin Le Grand { 711ddde725dSArmin Le Grand const sal_uInt32 nCount(getGradientEntries().size()); 712ddde725dSArmin Le Grand maMirroredGradientEntries.clear(); 713ddde725dSArmin Le Grand maMirroredGradientEntries.reserve(nCount); 714ddde725dSArmin Le Grand 715ddde725dSArmin Le Grand for(sal_uInt32 a(0); a < nCount; a++) 716ddde725dSArmin Le Grand { 717ddde725dSArmin Le Grand const SvgGradientEntry& rCandidate = getGradientEntries()[nCount - 1 - a]; 718ddde725dSArmin Le Grand 719ddde725dSArmin Le Grand maMirroredGradientEntries.push_back( 720ddde725dSArmin Le Grand SvgGradientEntry( 721ddde725dSArmin Le Grand 1.0 - rCandidate.getOffset(), 722ddde725dSArmin Le Grand rCandidate.getColor(), 723ddde725dSArmin Le Grand rCandidate.getOpacity())); 724ddde725dSArmin Le Grand } 725ddde725dSArmin Le Grand } 726ddde725dSArmin Le Grand } 727ddde725dSArmin Le Grand create2DDecomposition(const geometry::ViewInformation2D &) const728ddde725dSArmin Le Grand Primitive2DSequence SvgRadialGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 729ddde725dSArmin Le Grand { 730ddde725dSArmin Le Grand Primitive2DSequence xRetval; 731ddde725dSArmin Le Grand 732ddde725dSArmin Le Grand if(!getPreconditionsChecked()) 733ddde725dSArmin Le Grand { 734ddde725dSArmin Le Grand const_cast< SvgRadialGradientPrimitive2D* >(this)->checkPreconditions(); 735ddde725dSArmin Le Grand } 736ddde725dSArmin Le Grand 737ddde725dSArmin Le Grand if(getSingleEntry()) 738ddde725dSArmin Le Grand { 739ddde725dSArmin Le Grand // fill with last existing color 740ddde725dSArmin Le Grand xRetval = createSingleGradientEntryFill(); 741ddde725dSArmin Le Grand } 742ddde725dSArmin Le Grand else if(getCreatesContent()) 743ddde725dSArmin Le Grand { 744ddde725dSArmin Le Grand // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely 745ddde725dSArmin Le Grand // invisible, width and height to fill are not empty 746ddde725dSArmin Le Grand const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); 747ddde725dSArmin Le Grand const double fPolyWidth(aPolyRange.getWidth()); 748ddde725dSArmin Le Grand const double fPolyHeight(aPolyRange.getHeight()); 749ddde725dSArmin Le Grand 750ddde725dSArmin Le Grand // create ObjectTransform based on polygon range 751ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aObjectTransform( 752ddde725dSArmin Le Grand basegfx::tools::createScaleTranslateB2DHomMatrix( 753ddde725dSArmin Le Grand fPolyWidth, fPolyHeight, 754ddde725dSArmin Le Grand aPolyRange.getMinX(), aPolyRange.getMinY())); 755804e0487SArmin Le Grand basegfx::B2DHomMatrix aUnitGradientToObject; 756ddde725dSArmin Le Grand 757804e0487SArmin Le Grand if(getUseUnitCoordinates()) 758804e0487SArmin Le Grand { 759804e0487SArmin Le Grand // interpret in unit coordinate system -> object aspect ratio will scale result 760ddde725dSArmin Le Grand // create unit transform from unit vector to given linear gradient vector 761915dc3acSArmin Le Grand aUnitGradientToObject.scale(getRadius(), getRadius()); 762915dc3acSArmin Le Grand aUnitGradientToObject.translate(getStart().getX(), getStart().getY()); 763ddde725dSArmin Le Grand 764915dc3acSArmin Le Grand if(!getGradientTransform().isIdentity()) 765915dc3acSArmin Le Grand { 766915dc3acSArmin Le Grand aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject; 767915dc3acSArmin Le Grand } 768ddde725dSArmin Le Grand 769ddde725dSArmin Le Grand // create full transform from unit gradient coordinates to object coordinates 770ddde725dSArmin Le Grand // including the SvgGradient transformation 771915dc3acSArmin Le Grand aUnitGradientToObject = aObjectTransform * aUnitGradientToObject; 772804e0487SArmin Le Grand } 773804e0487SArmin Le Grand else 774804e0487SArmin Le Grand { 775804e0487SArmin Le Grand // interpret in object coordinate system -> object aspect ratio will not scale result 77601e92ad6SArmin Le Grand // use X-Axis with radius, it was already made relative to object width when coming from 77701e92ad6SArmin Le Grand // SVG import 778804e0487SArmin Le Grand const double fRadius((aObjectTransform * basegfx::B2DVector(getRadius(), 0.0)).getLength()); 779804e0487SArmin Le Grand const basegfx::B2DPoint aStart(aObjectTransform * getStart()); 780804e0487SArmin Le Grand 781804e0487SArmin Le Grand aUnitGradientToObject.scale(fRadius, fRadius); 782804e0487SArmin Le Grand aUnitGradientToObject.translate(aStart.getX(), aStart.getY()); 783ddde725dSArmin Le Grand 78401e92ad6SArmin Le Grand if(!getGradientTransform().isIdentity()) 78501e92ad6SArmin Le Grand { 78601e92ad6SArmin Le Grand aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject; 78701e92ad6SArmin Le Grand } 788915dc3acSArmin Le Grand } 78901e92ad6SArmin Le Grand 790ddde725dSArmin Le Grand // create inverse from it 791ddde725dSArmin Le Grand basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject); 792ddde725dSArmin Le Grand aObjectToUnitGradient.invert(); 793ddde725dSArmin Le Grand 794ddde725dSArmin Le Grand // back-transform polygon to unit gradient coordinates and get 795ddde725dSArmin Le Grand // UnitRage. This is the range the gradient has to cover 796ddde725dSArmin Le Grand basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon()); 797ddde725dSArmin Le Grand aUnitPoly.transform(aObjectToUnitGradient); 798ddde725dSArmin Le Grand const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange()); 799ddde725dSArmin Le Grand 800ddde725dSArmin Le Grand // create range which the gradient has to cover to cover the whole given geometry. 801ddde725dSArmin Le Grand // For circle, go from 0.0 to max radius in all directions (the corners) 802ddde725dSArmin Le Grand double fMax(basegfx::B2DVector(aUnitRange.getMinimum()).getLength()); 803ddde725dSArmin Le Grand fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaximum()).getLength()); 804ddde725dSArmin Le Grand fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMinX(), aUnitRange.getMaxY()).getLength()); 805ddde725dSArmin Le Grand fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaxX(), aUnitRange.getMinY()).getLength()); 806ddde725dSArmin Le Grand 807ddde725dSArmin Le Grand // prepare result vectors 808ddde725dSArmin Le Grand Primitive2DVector aTargetColor; 809ddde725dSArmin Le Grand Primitive2DVector aTargetOpacity; 810ddde725dSArmin Le Grand 811ddde725dSArmin Le Grand if(0.0 < fMax) 812ddde725dSArmin Le Grand { 813ddde725dSArmin Le Grand // prepare maFocalVector 814ddde725dSArmin Le Grand if(isFocalSet()) 815ddde725dSArmin Le Grand { 816ddde725dSArmin Le Grand const_cast< SvgRadialGradientPrimitive2D* >(this)->maFocalLength = fMax; 817ddde725dSArmin Le Grand } 818ddde725dSArmin Le Grand 819ddde725dSArmin Le Grand // create central run, may also already do all necessary when 820ddde725dSArmin Le Grand // Spread_pad is set as SpreadMethod and/or the range is smaller 821ddde725dSArmin Le Grand double fPos(createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), 0)); 822ddde725dSArmin Le Grand 823ddde725dSArmin Le Grand if(fPos < fMax) 824ddde725dSArmin Le Grand { 825ddde725dSArmin Le Grand // can only happen when SpreadMethod is Spread_reflect or Spread_repeat, 826ddde725dSArmin Le Grand // else the start and end pads are already created and fPos == fMax. 827ddde725dSArmin Le Grand // For radial there is no way to transform the already created 828ddde725dSArmin Le Grand // central run, it needs to be created from 1.0 to fMax 829ddde725dSArmin Le Grand sal_Int32 nOffset(1); 830ddde725dSArmin Le Grand 831ddde725dSArmin Le Grand while(fPos < fMax) 832ddde725dSArmin Le Grand { 833ddde725dSArmin Le Grand const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2)); 834ddde725dSArmin Le Grand 835ddde725dSArmin Le Grand if(bMirror) 836ddde725dSArmin Le Grand { 837ddde725dSArmin Le Grand createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getMirroredGradientEntries(), nOffset); 838ddde725dSArmin Le Grand } 839ddde725dSArmin Le Grand else 840ddde725dSArmin Le Grand { 841ddde725dSArmin Le Grand createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), nOffset); 842ddde725dSArmin Le Grand } 843ddde725dSArmin Le Grand 844ddde725dSArmin Le Grand nOffset++; 845ddde725dSArmin Le Grand fPos += 1.0; 846ddde725dSArmin Le Grand } 847ddde725dSArmin Le Grand } 848ddde725dSArmin Le Grand } 849ddde725dSArmin Le Grand 850ddde725dSArmin Le Grand xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject, true); 851ddde725dSArmin Le Grand } 852ddde725dSArmin Le Grand 853ddde725dSArmin Le Grand return xRetval; 854ddde725dSArmin Le Grand } 855ddde725dSArmin Le Grand SvgRadialGradientPrimitive2D(const basegfx::B2DHomMatrix & rGradientTransform,const basegfx::B2DPolyPolygon & rPolyPolygon,const SvgGradientEntryVector & rGradientEntries,const basegfx::B2DPoint & rStart,double fRadius,bool bUseUnitCoordinates,SpreadMethod aSpreadMethod,const basegfx::B2DPoint * pFocal)856ddde725dSArmin Le Grand SvgRadialGradientPrimitive2D::SvgRadialGradientPrimitive2D( 85701e92ad6SArmin Le Grand const basegfx::B2DHomMatrix& rGradientTransform, 858ddde725dSArmin Le Grand const basegfx::B2DPolyPolygon& rPolyPolygon, 859ddde725dSArmin Le Grand const SvgGradientEntryVector& rGradientEntries, 860ddde725dSArmin Le Grand const basegfx::B2DPoint& rStart, 861ddde725dSArmin Le Grand double fRadius, 862804e0487SArmin Le Grand bool bUseUnitCoordinates, 863ddde725dSArmin Le Grand SpreadMethod aSpreadMethod, 86439551d71SArmin Le Grand const basegfx::B2DPoint* pFocal) 865ddde725dSArmin Le Grand : BufferedDecompositionPrimitive2D(), 86601e92ad6SArmin Le Grand SvgGradientHelper(rGradientTransform, rPolyPolygon, rGradientEntries, rStart, bUseUnitCoordinates, aSpreadMethod), 867ddde725dSArmin Le Grand mfRadius(fRadius), 868ddde725dSArmin Le Grand maFocal(rStart), 869ddde725dSArmin Le Grand maFocalVector(0.0, 0.0), 870ddde725dSArmin Le Grand maFocalLength(0.0), 871ddde725dSArmin Le Grand maMirroredGradientEntries(), 872ddde725dSArmin Le Grand mbFocalSet(false) 873ddde725dSArmin Le Grand { 874025b0597SArmin Le Grand if(pFocal && !pFocal->equal(getStart())) 875ddde725dSArmin Le Grand { 876ddde725dSArmin Le Grand maFocal = *pFocal; 877ddde725dSArmin Le Grand maFocalVector = maFocal - getStart(); 878ddde725dSArmin Le Grand mbFocalSet = true; 879ddde725dSArmin Le Grand } 880ddde725dSArmin Le Grand } 881ddde725dSArmin Le Grand ~SvgRadialGradientPrimitive2D()882025b0597SArmin Le Grand SvgRadialGradientPrimitive2D::~SvgRadialGradientPrimitive2D() 883025b0597SArmin Le Grand { 884025b0597SArmin Le Grand } 885025b0597SArmin Le Grand operator ==(const BasePrimitive2D & rPrimitive) const886ddde725dSArmin Le Grand bool SvgRadialGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 887ddde725dSArmin Le Grand { 888ddde725dSArmin Le Grand const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive); 889ddde725dSArmin Le Grand 890ddde725dSArmin Le Grand if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper)) 891ddde725dSArmin Le Grand { 892ddde725dSArmin Le Grand const SvgRadialGradientPrimitive2D& rCompare = static_cast< const SvgRadialGradientPrimitive2D& >(rPrimitive); 893ddde725dSArmin Le Grand 894ddde725dSArmin Le Grand if(getRadius() == rCompare.getRadius()) 895ddde725dSArmin Le Grand { 896ddde725dSArmin Le Grand if(isFocalSet() == rCompare.isFocalSet()) 897ddde725dSArmin Le Grand { 898ddde725dSArmin Le Grand if(isFocalSet()) 899ddde725dSArmin Le Grand { 900ddde725dSArmin Le Grand return getFocal() == rCompare.getFocal(); 901ddde725dSArmin Le Grand } 902ddde725dSArmin Le Grand else 903ddde725dSArmin Le Grand { 904ddde725dSArmin Le Grand return true; 905ddde725dSArmin Le Grand } 906ddde725dSArmin Le Grand } 907ddde725dSArmin Le Grand } 908ddde725dSArmin Le Grand } 909ddde725dSArmin Le Grand 910ddde725dSArmin Le Grand return false; 911ddde725dSArmin Le Grand } 912ddde725dSArmin Le Grand getB2DRange(const geometry::ViewInformation2D &) const913ddde725dSArmin Le Grand basegfx::B2DRange SvgRadialGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const 914ddde725dSArmin Le Grand { 915ddde725dSArmin Le Grand // return ObjectRange 916ddde725dSArmin Le Grand return getPolyPolygon().getB2DRange(); 917ddde725dSArmin Le Grand } 918ddde725dSArmin Le Grand 919ddde725dSArmin Le Grand // provide unique ID 920ddde725dSArmin Le Grand ImplPrimitrive2DIDBlock(SvgRadialGradientPrimitive2D, PRIMITIVE2D_ID_SVGRADIALGRADIENTPRIMITIVE2D) 921ddde725dSArmin Le Grand 922ddde725dSArmin Le Grand } // end of namespace primitive2d 923ddde725dSArmin Le Grand } // end of namespace drawinglayer 924ddde725dSArmin Le Grand 925ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 926ddde725dSArmin Le Grand // SvgLinearAtomPrimitive2D class 927ddde725dSArmin Le Grand 928ddde725dSArmin Le Grand namespace drawinglayer 929ddde725dSArmin Le Grand { 930ddde725dSArmin Le Grand namespace primitive2d 931ddde725dSArmin Le Grand { create2DDecomposition(const geometry::ViewInformation2D &) const932e2bf1e9dSArmin Le Grand Primitive2DSequence SvgLinearAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 933ddde725dSArmin Le Grand { 934ddde725dSArmin Le Grand Primitive2DSequence xRetval; 935ddde725dSArmin Le Grand const double fDelta(getOffsetB() - getOffsetA()); 936ddde725dSArmin Le Grand 937ddde725dSArmin Le Grand if(!basegfx::fTools::equalZero(fDelta)) 938ddde725dSArmin Le Grand { 93939551d71SArmin Le Grand // use one discrete unit for overlap (one pixel) 94039551d71SArmin Le Grand const double fDiscreteUnit(getDiscreteUnit()); 94139551d71SArmin Le Grand 94239551d71SArmin Le Grand // use color distance and discrete lengths to calculate step count 94339551d71SArmin Le Grand const sal_uInt32 nSteps(calculateStepsForSvgGradient(getColorA(), getColorB(), fDelta, fDiscreteUnit)); 94439551d71SArmin Le Grand 945025b0597SArmin Le Grand // prepare polygon in needed width at start position (with discrete overlap) 946ddde725dSArmin Le Grand const basegfx::B2DPolygon aPolygon( 947ddde725dSArmin Le Grand basegfx::tools::createPolygonFromRect( 948ddde725dSArmin Le Grand basegfx::B2DRange( 94939551d71SArmin Le Grand getOffsetA() - fDiscreteUnit, 950ddde725dSArmin Le Grand 0.0, 951025b0597SArmin Le Grand getOffsetA() + (fDelta / nSteps) + fDiscreteUnit, 952ddde725dSArmin Le Grand 1.0))); 953ddde725dSArmin Le Grand 954025b0597SArmin Le Grand // prepare loop (inside to outside, [0.0 .. 1.0[) 955025b0597SArmin Le Grand double fUnitScale(0.0); 956025b0597SArmin Le Grand const double fUnitStep(1.0 / nSteps); 957025b0597SArmin Le Grand 958025b0597SArmin Le Grand // prepare result set (known size) 959ddde725dSArmin Le Grand xRetval.realloc(nSteps); 960ddde725dSArmin Le Grand 961025b0597SArmin Le Grand for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep) 962ddde725dSArmin Le Grand { 96339551d71SArmin Le Grand basegfx::B2DPolygon aNew(aPolygon); 964ddde725dSArmin Le Grand 965025b0597SArmin Le Grand aNew.transform(basegfx::tools::createTranslateB2DHomMatrix(fDelta * fUnitScale, 0.0)); 966ddde725dSArmin Le Grand xRetval[a] = new PolyPolygonColorPrimitive2D( 96739551d71SArmin Le Grand basegfx::B2DPolyPolygon(aNew), 968025b0597SArmin Le Grand basegfx::interpolate(getColorA(), getColorB(), fUnitScale)); 969ddde725dSArmin Le Grand } 970ddde725dSArmin Le Grand } 971ddde725dSArmin Le Grand 972ddde725dSArmin Le Grand return xRetval; 973ddde725dSArmin Le Grand } 974ddde725dSArmin Le Grand SvgLinearAtomPrimitive2D(const basegfx::BColor & aColorA,double fOffsetA,const basegfx::BColor & aColorB,double fOffsetB)97539551d71SArmin Le Grand SvgLinearAtomPrimitive2D::SvgLinearAtomPrimitive2D( 97639551d71SArmin Le Grand const basegfx::BColor& aColorA, double fOffsetA, 97739551d71SArmin Le Grand const basegfx::BColor& aColorB, double fOffsetB) 97839551d71SArmin Le Grand : DiscreteMetricDependentPrimitive2D(), 97939551d71SArmin Le Grand maColorA(aColorA), 98039551d71SArmin Le Grand maColorB(aColorB), 98139551d71SArmin Le Grand mfOffsetA(fOffsetA), 98239551d71SArmin Le Grand mfOffsetB(fOffsetB) 98339551d71SArmin Le Grand { 98439551d71SArmin Le Grand if(mfOffsetA > mfOffsetB) 98539551d71SArmin Le Grand { 98639551d71SArmin Le Grand OSL_ENSURE(false, "Wrong offset order (!)"); 98739551d71SArmin Le Grand ::std::swap(mfOffsetA, mfOffsetB); 98839551d71SArmin Le Grand } 98939551d71SArmin Le Grand } 99039551d71SArmin Le Grand operator ==(const BasePrimitive2D & rPrimitive) const991ddde725dSArmin Le Grand bool SvgLinearAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 992ddde725dSArmin Le Grand { 993ddde725dSArmin Le Grand if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) 994ddde725dSArmin Le Grand { 995ddde725dSArmin Le Grand const SvgLinearAtomPrimitive2D& rCompare = static_cast< const SvgLinearAtomPrimitive2D& >(rPrimitive); 996ddde725dSArmin Le Grand 997ddde725dSArmin Le Grand return (getColorA() == rCompare.getColorA() 998ddde725dSArmin Le Grand && getColorB() == rCompare.getColorB() 999ddde725dSArmin Le Grand && getOffsetA() == rCompare.getOffsetA() 100039551d71SArmin Le Grand && getOffsetB() == rCompare.getOffsetB()); 1001ddde725dSArmin Le Grand } 1002ddde725dSArmin Le Grand 1003ddde725dSArmin Le Grand return false; 1004ddde725dSArmin Le Grand } 1005ddde725dSArmin Le Grand 1006ddde725dSArmin Le Grand // provide unique ID 1007ddde725dSArmin Le Grand ImplPrimitrive2DIDBlock(SvgLinearAtomPrimitive2D, PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D) 1008ddde725dSArmin Le Grand 1009ddde725dSArmin Le Grand } // end of namespace primitive2d 1010ddde725dSArmin Le Grand } // end of namespace drawinglayer 1011ddde725dSArmin Le Grand 1012ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 1013ddde725dSArmin Le Grand // SvgRadialAtomPrimitive2D class 1014ddde725dSArmin Le Grand 1015ddde725dSArmin Le Grand namespace drawinglayer 1016ddde725dSArmin Le Grand { 1017ddde725dSArmin Le Grand namespace primitive2d 1018ddde725dSArmin Le Grand { create2DDecomposition(const geometry::ViewInformation2D &) const1019ddde725dSArmin Le Grand Primitive2DSequence SvgRadialAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 1020ddde725dSArmin Le Grand { 1021ddde725dSArmin Le Grand Primitive2DSequence xRetval; 1022ddde725dSArmin Le Grand const double fDeltaScale(getScaleB() - getScaleA()); 1023ddde725dSArmin Le Grand 1024ddde725dSArmin Le Grand if(!basegfx::fTools::equalZero(fDeltaScale)) 1025ddde725dSArmin Le Grand { 102639551d71SArmin Le Grand // use one discrete unit for overlap (one pixel) 102739551d71SArmin Le Grand const double fDiscreteUnit(getDiscreteUnit()); 1028ddde725dSArmin Le Grand 102939551d71SArmin Le Grand // use color distance and discrete lengths to calculate step count 103039551d71SArmin Le Grand const sal_uInt32 nSteps(calculateStepsForSvgGradient(getColorA(), getColorB(), fDeltaScale, fDiscreteUnit)); 1031ddde725dSArmin Le Grand 1032025b0597SArmin Le Grand // prepare loop ([0.0 .. 1.0[, full polygons, no polypolygons with holes) 1033025b0597SArmin Le Grand double fUnitScale(0.0); 1034025b0597SArmin Le Grand const double fUnitStep(1.0 / nSteps); 1035ddde725dSArmin Le Grand 1036025b0597SArmin Le Grand // prepare result set (known size) 1037ddde725dSArmin Le Grand xRetval.realloc(nSteps); 1038ddde725dSArmin Le Grand 1039025b0597SArmin Le Grand for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep) 1040ddde725dSArmin Le Grand { 104139551d71SArmin Le Grand basegfx::B2DHomMatrix aTransform; 1042025b0597SArmin Le Grand const double fEndScale(getScaleB() - (fDeltaScale * fUnitScale)); 1043ddde725dSArmin Le Grand 104439551d71SArmin Le Grand if(isTranslateSet()) 1045ddde725dSArmin Le Grand { 104639551d71SArmin Le Grand const basegfx::B2DVector aTranslate( 104739551d71SArmin Le Grand basegfx::interpolate( 104839551d71SArmin Le Grand getTranslateB(), 1049025b0597SArmin Le Grand getTranslateA(), 105039551d71SArmin Le Grand fUnitScale)); 1051ddde725dSArmin Le Grand 105239551d71SArmin Le Grand aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix( 105339551d71SArmin Le Grand fEndScale, 105439551d71SArmin Le Grand fEndScale, 105539551d71SArmin Le Grand aTranslate.getX(), 105639551d71SArmin Le Grand aTranslate.getY()); 1057ddde725dSArmin Le Grand } 1058ddde725dSArmin Le Grand else 1059ddde725dSArmin Le Grand { 106039551d71SArmin Le Grand aTransform = basegfx::tools::createScaleB2DHomMatrix( 106139551d71SArmin Le Grand fEndScale, 106239551d71SArmin Le Grand fEndScale); 1063ddde725dSArmin Le Grand } 1064ddde725dSArmin Le Grand 106539551d71SArmin Le Grand basegfx::B2DPolygon aNew(basegfx::tools::createPolygonFromUnitCircle()); 1066ddde725dSArmin Le Grand 106739551d71SArmin Le Grand aNew.transform(aTransform); 106839551d71SArmin Le Grand xRetval[a] = new PolyPolygonColorPrimitive2D( 106939551d71SArmin Le Grand basegfx::B2DPolyPolygon(aNew), 1070025b0597SArmin Le Grand basegfx::interpolate(getColorB(), getColorA(), fUnitScale)); 1071ddde725dSArmin Le Grand } 1072ddde725dSArmin Le Grand } 1073ddde725dSArmin Le Grand 1074ddde725dSArmin Le Grand return xRetval; 1075ddde725dSArmin Le Grand } 1076ddde725dSArmin Le Grand SvgRadialAtomPrimitive2D(const basegfx::BColor & aColorA,double fScaleA,const basegfx::B2DVector & rTranslateA,const basegfx::BColor & aColorB,double fScaleB,const basegfx::B2DVector & rTranslateB)107739551d71SArmin Le Grand SvgRadialAtomPrimitive2D::SvgRadialAtomPrimitive2D( 107839551d71SArmin Le Grand const basegfx::BColor& aColorA, double fScaleA, const basegfx::B2DVector& rTranslateA, 107939551d71SArmin Le Grand const basegfx::BColor& aColorB, double fScaleB, const basegfx::B2DVector& rTranslateB) 108039551d71SArmin Le Grand : DiscreteMetricDependentPrimitive2D(), 108139551d71SArmin Le Grand maColorA(aColorA), 108239551d71SArmin Le Grand maColorB(aColorB), 108339551d71SArmin Le Grand mfScaleA(fScaleA), 108439551d71SArmin Le Grand mfScaleB(fScaleB), 108539551d71SArmin Le Grand mpTranslate(0) 108639551d71SArmin Le Grand { 108739551d71SArmin Le Grand // check and evtl. set translations 108839551d71SArmin Le Grand if(!rTranslateA.equal(rTranslateB)) 108939551d71SArmin Le Grand { 109039551d71SArmin Le Grand mpTranslate = new VectorPair(rTranslateA, rTranslateB); 109139551d71SArmin Le Grand } 109239551d71SArmin Le Grand 109339551d71SArmin Le Grand // scale A and B have to be positive 109439551d71SArmin Le Grand mfScaleA = ::std::max(mfScaleA, 0.0); 109539551d71SArmin Le Grand mfScaleB = ::std::max(mfScaleB, 0.0); 109639551d71SArmin Le Grand 109739551d71SArmin Le Grand // scale B has to be bigger than scale A; swap if different 109839551d71SArmin Le Grand if(mfScaleA > mfScaleB) 109939551d71SArmin Le Grand { 110039551d71SArmin Le Grand OSL_ENSURE(false, "Wrong offset order (!)"); 110139551d71SArmin Le Grand ::std::swap(mfScaleA, mfScaleB); 110239551d71SArmin Le Grand 110339551d71SArmin Le Grand if(mpTranslate) 110439551d71SArmin Le Grand { 110539551d71SArmin Le Grand ::std::swap(mpTranslate->maTranslateA, mpTranslate->maTranslateB); 110639551d71SArmin Le Grand } 110739551d71SArmin Le Grand } 110839551d71SArmin Le Grand } 110939551d71SArmin Le Grand SvgRadialAtomPrimitive2D(const basegfx::BColor & aColorA,double fScaleA,const basegfx::BColor & aColorB,double fScaleB)111039551d71SArmin Le Grand SvgRadialAtomPrimitive2D::SvgRadialAtomPrimitive2D( 111139551d71SArmin Le Grand const basegfx::BColor& aColorA, double fScaleA, 111239551d71SArmin Le Grand const basegfx::BColor& aColorB, double fScaleB) 111339551d71SArmin Le Grand : DiscreteMetricDependentPrimitive2D(), 111439551d71SArmin Le Grand maColorA(aColorA), 111539551d71SArmin Le Grand maColorB(aColorB), 111639551d71SArmin Le Grand mfScaleA(fScaleA), 111739551d71SArmin Le Grand mfScaleB(fScaleB), 111839551d71SArmin Le Grand mpTranslate(0) 111939551d71SArmin Le Grand { 112039551d71SArmin Le Grand // scale A and B have to be positive 112139551d71SArmin Le Grand mfScaleA = ::std::max(mfScaleA, 0.0); 112239551d71SArmin Le Grand mfScaleB = ::std::max(mfScaleB, 0.0); 112339551d71SArmin Le Grand 112439551d71SArmin Le Grand // scale B has to be bigger than scale A; swap if different 112539551d71SArmin Le Grand if(mfScaleA > mfScaleB) 112639551d71SArmin Le Grand { 112739551d71SArmin Le Grand OSL_ENSURE(false, "Wrong offset order (!)"); 112839551d71SArmin Le Grand ::std::swap(mfScaleA, mfScaleB); 112939551d71SArmin Le Grand } 113039551d71SArmin Le Grand } 113139551d71SArmin Le Grand ~SvgRadialAtomPrimitive2D()113239551d71SArmin Le Grand SvgRadialAtomPrimitive2D::~SvgRadialAtomPrimitive2D() 113339551d71SArmin Le Grand { 113439551d71SArmin Le Grand if(mpTranslate) 113539551d71SArmin Le Grand { 113639551d71SArmin Le Grand delete mpTranslate; 113739551d71SArmin Le Grand mpTranslate = 0; 113839551d71SArmin Le Grand } 113939551d71SArmin Le Grand } 114039551d71SArmin Le Grand operator ==(const BasePrimitive2D & rPrimitive) const1141ddde725dSArmin Le Grand bool SvgRadialAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 1142ddde725dSArmin Le Grand { 1143ddde725dSArmin Le Grand if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) 1144ddde725dSArmin Le Grand { 1145ddde725dSArmin Le Grand const SvgRadialAtomPrimitive2D& rCompare = static_cast< const SvgRadialAtomPrimitive2D& >(rPrimitive); 1146ddde725dSArmin Le Grand 114739551d71SArmin Le Grand if(getColorA() == rCompare.getColorA() 1148ddde725dSArmin Le Grand && getColorB() == rCompare.getColorB() 1149ddde725dSArmin Le Grand && getScaleA() == rCompare.getScaleA() 115039551d71SArmin Le Grand && getScaleB() == rCompare.getScaleB()) 115139551d71SArmin Le Grand { 115239551d71SArmin Le Grand if(isTranslateSet() && rCompare.isTranslateSet()) 115339551d71SArmin Le Grand { 115439551d71SArmin Le Grand return (getTranslateA() == rCompare.getTranslateA() 115539551d71SArmin Le Grand && getTranslateB() == rCompare.getTranslateB()); 115639551d71SArmin Le Grand } 115739551d71SArmin Le Grand else if(!isTranslateSet() && !rCompare.isTranslateSet()) 115839551d71SArmin Le Grand { 115939551d71SArmin Le Grand return true; 116039551d71SArmin Le Grand } 116139551d71SArmin Le Grand } 1162ddde725dSArmin Le Grand } 1163ddde725dSArmin Le Grand 1164ddde725dSArmin Le Grand return false; 1165ddde725dSArmin Le Grand } 1166ddde725dSArmin Le Grand 1167ddde725dSArmin Le Grand // provide unique ID 1168ddde725dSArmin Le Grand ImplPrimitrive2DIDBlock(SvgRadialAtomPrimitive2D, PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D) 1169ddde725dSArmin Le Grand 1170ddde725dSArmin Le Grand } // end of namespace primitive2d 1171ddde725dSArmin Le Grand } // end of namespace drawinglayer 1172ddde725dSArmin Le Grand 1173ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 1174ddde725dSArmin Le Grand // eof 1175