LCOV - code coverage report
Current view: top level - layout/svg - nsSVGGradientFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 266 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : // Main header first:
       7             : #include "nsSVGGradientFrame.h"
       8             : #include <algorithm>
       9             : 
      10             : // Keep others in (case-insensitive) order:
      11             : #include "AutoReferenceChainGuard.h"
      12             : #include "gfxPattern.h"
      13             : #include "mozilla/dom/SVGGradientElement.h"
      14             : #include "mozilla/dom/SVGStopElement.h"
      15             : #include "nsContentUtils.h"
      16             : #include "nsSVGEffects.h"
      17             : #include "nsSVGAnimatedTransformList.h"
      18             : 
      19             : // XXX Tight coupling with content classes ahead!
      20             : 
      21             : using namespace mozilla;
      22             : using namespace mozilla::dom;
      23             : using namespace mozilla::gfx;
      24             : 
      25             : //----------------------------------------------------------------------
      26             : // Implementation
      27             : 
      28           0 : nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext,
      29           0 :                                        ClassID aID)
      30             :   : nsSVGPaintServerFrame(aContext, aID)
      31             :   , mSource(nullptr)
      32             :   , mLoopFlag(false)
      33           0 :   , mNoHRefURI(false)
      34             : {
      35           0 : }
      36             : 
      37             : //----------------------------------------------------------------------
      38             : // nsIFrame methods:
      39             : 
      40             : nsresult
      41           0 : nsSVGGradientFrame::AttributeChanged(int32_t         aNameSpaceID,
      42             :                                      nsIAtom*        aAttribute,
      43             :                                      int32_t         aModType)
      44             : {
      45           0 :   if (aNameSpaceID == kNameSpaceID_None &&
      46           0 :       (aAttribute == nsGkAtoms::gradientUnits ||
      47           0 :        aAttribute == nsGkAtoms::gradientTransform ||
      48           0 :        aAttribute == nsGkAtoms::spreadMethod)) {
      49           0 :     nsSVGEffects::InvalidateDirectRenderingObservers(this);
      50           0 :   } else if ((aNameSpaceID == kNameSpaceID_XLink ||
      51           0 :               aNameSpaceID == kNameSpaceID_None) &&
      52           0 :              aAttribute == nsGkAtoms::href) {
      53             :     // Blow away our reference, if any
      54           0 :     DeleteProperty(nsSVGEffects::HrefAsPaintingProperty());
      55           0 :     mNoHRefURI = false;
      56             :     // And update whoever references us
      57           0 :     nsSVGEffects::InvalidateDirectRenderingObservers(this);
      58             :   }
      59             : 
      60           0 :   return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID,
      61           0 :                                                  aAttribute, aModType);
      62             : }
      63             : 
      64             : //----------------------------------------------------------------------
      65             : 
      66             : uint16_t
      67           0 : nsSVGGradientFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
      68             : {
      69             :   const nsSVGEnum& thisEnum =
      70           0 :     static_cast<dom::SVGGradientElement*>(mContent)->mEnumAttributes[aIndex];
      71             : 
      72           0 :   if (thisEnum.IsExplicitlySet())
      73           0 :     return thisEnum.GetAnimValue();
      74             : 
      75             :   // Before we recurse, make sure we'll break reference loops and over long
      76             :   // reference chains:
      77             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
      78             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
      79           0 :                                         &sRefChainLengthCounter);
      80           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
      81             :     // Break reference chain
      82             :     return static_cast<dom::SVGGradientElement*>(aDefault)->
      83           0 :              mEnumAttributes[aIndex].GetAnimValue();
      84             :   }
      85             : 
      86           0 :   nsSVGGradientFrame *next = GetReferencedGradient();
      87             : 
      88           0 :   return next ? next->GetEnumValue(aIndex, aDefault)
      89             :               : static_cast<dom::SVGGradientElement*>(aDefault)->
      90           0 :                   mEnumAttributes[aIndex].GetAnimValue();
      91             : }
      92             : 
      93             : uint16_t
      94           0 : nsSVGGradientFrame::GetGradientUnits()
      95             : {
      96             :   // This getter is called every time the others are called - maybe cache it?
      97           0 :   return GetEnumValue(dom::SVGGradientElement::GRADIENTUNITS);
      98             : }
      99             : 
     100             : uint16_t
     101           0 : nsSVGGradientFrame::GetSpreadMethod()
     102             : {
     103           0 :   return GetEnumValue(dom::SVGGradientElement::SPREADMETHOD);
     104             : }
     105             : 
     106             : const nsSVGAnimatedTransformList*
     107           0 : nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault)
     108             : {
     109             :   nsSVGAnimatedTransformList *thisTransformList =
     110           0 :     static_cast<dom::SVGGradientElement*>(mContent)->GetAnimatedTransformList();
     111             : 
     112           0 :   if (thisTransformList && thisTransformList->IsExplicitlySet())
     113           0 :     return thisTransformList;
     114             : 
     115             :   // Before we recurse, make sure we'll break reference loops and over long
     116             :   // reference chains:
     117             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     118             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     119           0 :                                         &sRefChainLengthCounter);
     120           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     121             :     // Break reference chain
     122             :     return static_cast<const dom::SVGGradientElement*>(aDefault)->
     123           0 :              mGradientTransform.get();
     124             :   }
     125             : 
     126           0 :   nsSVGGradientFrame *next = GetReferencedGradient();
     127             : 
     128           0 :   return next ? next->GetGradientTransformList(aDefault)
     129             :               : static_cast<const dom::SVGGradientElement*>(aDefault)->
     130           0 :                   mGradientTransform.get();
     131             : }
     132             : 
     133             : gfxMatrix
     134           0 : nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
     135             :                                          const gfxRect *aOverrideBounds)
     136             : {
     137           0 :   gfxMatrix bboxMatrix;
     138             : 
     139           0 :   uint16_t gradientUnits = GetGradientUnits();
     140           0 :   if (gradientUnits != SVG_UNIT_TYPE_USERSPACEONUSE) {
     141           0 :     NS_ASSERTION(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
     142             :                  "Unknown gradientUnits type");
     143             :     // objectBoundingBox is the default anyway
     144             : 
     145             :     gfxRect bbox =
     146             :       aOverrideBounds
     147             :         ? *aOverrideBounds
     148             :         : nsSVGUtils::GetBBox(aSource, nsSVGUtils::eUseFrameBoundsForOuterSVG |
     149           0 :                                        nsSVGUtils::eBBoxIncludeFillGeometry);
     150           0 :     bboxMatrix =
     151           0 :       gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
     152             :   }
     153             : 
     154             :   const nsSVGAnimatedTransformList* animTransformList =
     155           0 :     GetGradientTransformList(mContent);
     156           0 :   if (!animTransformList)
     157           0 :     return bboxMatrix;
     158             : 
     159             :   gfxMatrix gradientTransform =
     160           0 :     animTransformList->GetAnimValue().GetConsolidationMatrix();
     161           0 :   return bboxMatrix.PreMultiply(gradientTransform);
     162             : }
     163             : 
     164             : dom::SVGLinearGradientElement*
     165           0 : nsSVGGradientFrame::GetLinearGradientWithLength(uint32_t aIndex,
     166             :   dom::SVGLinearGradientElement* aDefault)
     167             : {
     168             :   // If this was a linear gradient with the required length, we would have
     169             :   // already found it in nsSVGLinearGradientFrame::GetLinearGradientWithLength.
     170             :   // Since we didn't find the length, continue looking down the chain.
     171             : 
     172             :   // Before we recurse, make sure we'll break reference loops and over long
     173             :   // reference chains:
     174             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     175             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     176           0 :                                         &sRefChainLengthCounter);
     177           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     178             :     // Break reference chain
     179           0 :     return aDefault;
     180             :   }
     181             : 
     182           0 :   nsSVGGradientFrame *next = GetReferencedGradient();
     183           0 :   return next ? next->GetLinearGradientWithLength(aIndex, aDefault) : aDefault;
     184             : }
     185             : 
     186             : dom::SVGRadialGradientElement*
     187           0 : nsSVGGradientFrame::GetRadialGradientWithLength(uint32_t aIndex,
     188             :   dom::SVGRadialGradientElement* aDefault)
     189             : {
     190             :   // If this was a radial gradient with the required length, we would have
     191             :   // already found it in nsSVGRadialGradientFrame::GetRadialGradientWithLength.
     192             :   // Since we didn't find the length, continue looking down the chain.
     193             : 
     194             :   // Before we recurse, make sure we'll break reference loops and over long
     195             :   // reference chains:
     196             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     197             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     198           0 :                                         &sRefChainLengthCounter);
     199           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     200             :     // Break reference chain
     201           0 :     return aDefault;
     202             :   }
     203             : 
     204           0 :   nsSVGGradientFrame *next = GetReferencedGradient();
     205           0 :   return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault;
     206             : }
     207             : 
     208             : //----------------------------------------------------------------------
     209             : // nsSVGPaintServerFrame methods:
     210             : 
     211             : //helper
     212           0 : static void GetStopInformation(nsIFrame* aStopFrame,
     213             :                                float *aOffset,
     214             :                                nscolor *aStopColor,
     215             :                                float *aStopOpacity)
     216             : {
     217           0 :   nsIContent* stopContent = aStopFrame->GetContent();
     218           0 :   MOZ_ASSERT(stopContent && stopContent->IsSVGElement(nsGkAtoms::stop));
     219             : 
     220             :   static_cast<SVGStopElement*>(stopContent)->
     221           0 :     GetAnimatedNumberValues(aOffset, nullptr);
     222             : 
     223           0 :   *aOffset = mozilla::clamped(*aOffset, 0.0f, 1.0f);
     224           0 :   *aStopColor = aStopFrame->StyleSVGReset()->mStopColor;
     225           0 :   *aStopOpacity = aStopFrame->StyleSVGReset()->mStopOpacity;
     226           0 : }
     227             : 
     228             : already_AddRefed<gfxPattern>
     229           0 : nsSVGGradientFrame::GetPaintServerPattern(nsIFrame* aSource,
     230             :                                           const DrawTarget* aDrawTarget,
     231             :                                           const gfxMatrix& aContextMatrix,
     232             :                                           nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
     233             :                                           float aGraphicOpacity,
     234             :                                           imgDrawingParams& aImgParams,
     235             :                                           const gfxRect* aOverrideBounds)
     236             : {
     237           0 :   uint16_t gradientUnits = GetGradientUnits();
     238           0 :   MOZ_ASSERT(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX ||
     239             :              gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE);
     240           0 :   if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
     241             :     // Set mSource for this consumer.
     242             :     // If this gradient is applied to text, our caller will be the glyph, which
     243             :     // is not an element, so we need to get the parent
     244           0 :     mSource = aSource->GetContent()->IsNodeOfType(nsINode::eTEXT) ?
     245             :                 aSource->GetParent() : aSource;
     246             :   }
     247             : 
     248           0 :   AutoTArray<nsIFrame*,8> stopFrames;
     249           0 :   GetStopFrames(&stopFrames);
     250             : 
     251           0 :   uint32_t nStops = stopFrames.Length();
     252             : 
     253             :   // SVG specification says that no stops should be treated like
     254             :   // the corresponding fill or stroke had "none" specified.
     255           0 :   if (nStops == 0) {
     256           0 :     RefPtr<gfxPattern> pattern = new gfxPattern(Color());
     257           0 :     return do_AddRef(new gfxPattern(Color()));
     258             :   }
     259             : 
     260           0 :   if (nStops == 1 || GradientVectorLengthIsZero()) {
     261             :     // The gradient paints a single colour, using the stop-color of the last
     262             :     // gradient step if there are more than one.
     263           0 :     float stopOpacity = stopFrames[nStops-1]->StyleSVGReset()->mStopOpacity;
     264           0 :     nscolor stopColor = stopFrames[nStops-1]->StyleSVGReset()->mStopColor;
     265             : 
     266           0 :     Color stopColor2 = Color::FromABGR(stopColor);
     267           0 :     stopColor2.a *= stopOpacity * aGraphicOpacity;
     268           0 :     return do_AddRef(new gfxPattern(stopColor2));
     269             :   }
     270             : 
     271             :   // Get the transform list (if there is one). We do this after the returns
     272             :   // above since this call can be expensive when "gradientUnits" is set to
     273             :   // "objectBoundingBox" (since that requiring a GetBBox() call).
     274           0 :   gfxMatrix patternMatrix = GetGradientTransform(aSource, aOverrideBounds);
     275             : 
     276           0 :   if (patternMatrix.IsSingular()) {
     277           0 :     return nullptr;
     278             :   }
     279             : 
     280             :   // revert any vector effect transform so that the gradient appears unchanged
     281           0 :   if (aFillOrStroke == &nsStyleSVG::mStroke) {
     282           0 :     gfxMatrix userToOuterSVG;
     283           0 :     if (nsSVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
     284           0 :       patternMatrix *= userToOuterSVG;
     285             :     }
     286             :   }
     287             : 
     288           0 :   if (!patternMatrix.Invert()) {
     289           0 :     return nullptr;
     290             :   }
     291             : 
     292           0 :   RefPtr<gfxPattern> gradient = CreateGradient();
     293           0 :   if (!gradient) {
     294           0 :     return nullptr;
     295             :   }
     296             : 
     297           0 :   uint16_t aSpread = GetSpreadMethod();
     298           0 :   if (aSpread == SVG_SPREADMETHOD_PAD)
     299           0 :     gradient->SetExtend(ExtendMode::CLAMP);
     300           0 :   else if (aSpread == SVG_SPREADMETHOD_REFLECT)
     301           0 :     gradient->SetExtend(ExtendMode::REFLECT);
     302           0 :   else if (aSpread == SVG_SPREADMETHOD_REPEAT)
     303           0 :     gradient->SetExtend(ExtendMode::REPEAT);
     304             : 
     305           0 :   gradient->SetMatrix(patternMatrix);
     306             : 
     307             :   // setup stops
     308           0 :   float lastOffset = 0.0f;
     309             : 
     310           0 :   for (uint32_t i = 0; i < nStops; i++) {
     311             :     float offset, stopOpacity;
     312             :     nscolor stopColor;
     313             : 
     314           0 :     GetStopInformation(stopFrames[i], &offset, &stopColor, &stopOpacity);
     315             : 
     316           0 :     if (offset < lastOffset)
     317           0 :       offset = lastOffset;
     318             :     else
     319           0 :       lastOffset = offset;
     320             : 
     321           0 :     Color stopColor2 = Color::FromABGR(stopColor);
     322           0 :     stopColor2.a *= stopOpacity * aGraphicOpacity;
     323           0 :     gradient->AddColorStop(offset, stopColor2);
     324             :   }
     325             : 
     326           0 :   return gradient.forget();
     327             : }
     328             : 
     329             : // Private (helper) methods
     330             : 
     331             : nsSVGGradientFrame *
     332           0 : nsSVGGradientFrame::GetReferencedGradient()
     333             : {
     334           0 :   if (mNoHRefURI)
     335           0 :     return nullptr;
     336             : 
     337             :   nsSVGPaintingProperty *property =
     338           0 :     GetProperty(nsSVGEffects::HrefAsPaintingProperty());
     339             : 
     340           0 :   if (!property) {
     341             :     // Fetch our gradient element's href or xlink:href attribute
     342             :     dom::SVGGradientElement* grad =
     343           0 :       static_cast<dom::SVGGradientElement*>(mContent);
     344           0 :     nsAutoString href;
     345           0 :     if (grad->mStringAttributes[dom::SVGGradientElement::HREF]
     346           0 :           .IsExplicitlySet()) {
     347             :       grad->mStringAttributes[dom::SVGGradientElement::HREF]
     348           0 :         .GetAnimValue(href, grad);
     349             :     } else {
     350             :       grad->mStringAttributes[dom::SVGGradientElement::XLINK_HREF]
     351           0 :         .GetAnimValue(href, grad);
     352             :     }
     353             : 
     354           0 :     if (href.IsEmpty()) {
     355           0 :       mNoHRefURI = true;
     356           0 :       return nullptr; // no URL
     357             :     }
     358             : 
     359             :     // Convert href to an nsIURI
     360           0 :     nsCOMPtr<nsIURI> targetURI;
     361           0 :     nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
     362           0 :     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
     363           0 :                                               mContent->GetUncomposedDoc(), base);
     364             : 
     365             :     property =
     366           0 :       nsSVGEffects::GetPaintingProperty(targetURI, this,
     367           0 :                                         nsSVGEffects::HrefAsPaintingProperty());
     368           0 :     if (!property)
     369           0 :       return nullptr;
     370             :   }
     371             : 
     372           0 :   nsIFrame *result = property->GetReferencedFrame();
     373           0 :   if (!result)
     374           0 :     return nullptr;
     375             : 
     376           0 :   LayoutFrameType frameType = result->Type();
     377           0 :   if (frameType != LayoutFrameType::SVGLinearGradient &&
     378             :       frameType != LayoutFrameType::SVGRadialGradient)
     379           0 :     return nullptr;
     380             : 
     381           0 :   return static_cast<nsSVGGradientFrame*>(result);
     382             : }
     383             : 
     384             : void
     385           0 : nsSVGGradientFrame::GetStopFrames(nsTArray<nsIFrame*>* aStopFrames)
     386             : {
     387           0 :   nsIFrame *stopFrame = nullptr;
     388           0 :   for (stopFrame = mFrames.FirstChild(); stopFrame;
     389           0 :        stopFrame = stopFrame->GetNextSibling()) {
     390           0 :     if (stopFrame->IsSVGStopFrame()) {
     391           0 :       aStopFrames->AppendElement(stopFrame);
     392             :     }
     393             :   }
     394           0 :   if (aStopFrames->Length() > 0) {
     395           0 :     return;
     396             :   }
     397             : 
     398             :   // Our gradient element doesn't have stops - try to "inherit" them
     399             : 
     400             :   // Before we recurse, make sure we'll break reference loops and over long
     401             :   // reference chains:
     402             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     403             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     404           0 :                                         &sRefChainLengthCounter);
     405           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     406             :     // Break reference chain
     407           0 :     return;
     408             :   }
     409             : 
     410           0 :   nsSVGGradientFrame* next = GetReferencedGradient();
     411           0 :   if (next) {
     412           0 :     next->GetStopFrames(aStopFrames);
     413             :   }
     414             : }
     415             : 
     416             : // -------------------------------------------------------------------------
     417             : // Linear Gradients
     418             : // -------------------------------------------------------------------------
     419             : 
     420             : #ifdef DEBUG
     421             : void
     422           0 : nsSVGLinearGradientFrame::Init(nsIContent*       aContent,
     423             :                                nsContainerFrame* aParent,
     424             :                                nsIFrame*         aPrevInFlow)
     425             : {
     426           0 :   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::linearGradient),
     427             :                "Content is not an SVG linearGradient");
     428             : 
     429           0 :   nsSVGGradientFrame::Init(aContent, aParent, aPrevInFlow);
     430           0 : }
     431             : #endif /* DEBUG */
     432             : 
     433             : nsresult
     434           0 : nsSVGLinearGradientFrame::AttributeChanged(int32_t         aNameSpaceID,
     435             :                                            nsIAtom*        aAttribute,
     436             :                                            int32_t         aModType)
     437             : {
     438           0 :   if (aNameSpaceID == kNameSpaceID_None &&
     439           0 :       (aAttribute == nsGkAtoms::x1 ||
     440           0 :        aAttribute == nsGkAtoms::y1 ||
     441           0 :        aAttribute == nsGkAtoms::x2 ||
     442           0 :        aAttribute == nsGkAtoms::y2)) {
     443           0 :     nsSVGEffects::InvalidateDirectRenderingObservers(this);
     444             :   }
     445             : 
     446           0 :   return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
     447           0 :                                               aAttribute, aModType);
     448             : }
     449             : 
     450             : //----------------------------------------------------------------------
     451             : 
     452             : float
     453           0 : nsSVGLinearGradientFrame::GetLengthValue(uint32_t aIndex)
     454             : {
     455             :   dom::SVGLinearGradientElement* lengthElement =
     456             :     GetLinearGradientWithLength(aIndex,
     457           0 :       static_cast<dom::SVGLinearGradientElement*>(mContent));
     458             :   // We passed in mContent as a fallback, so, assuming mContent is non-null, the
     459             :   // return value should also be non-null.
     460           0 :   MOZ_ASSERT(lengthElement,
     461             :     "Got unexpected null element from GetLinearGradientWithLength");
     462           0 :   const nsSVGLength2 &length = lengthElement->mLengthAttributes[aIndex];
     463             : 
     464             :   // Object bounding box units are handled by setting the appropriate
     465             :   // transform in GetGradientTransform, but we need to handle user
     466             :   // space units as part of the individual Get* routines.  Fixes 323669.
     467             : 
     468           0 :   uint16_t gradientUnits = GetGradientUnits();
     469           0 :   if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
     470           0 :     return nsSVGUtils::UserSpace(mSource, &length);
     471             :   }
     472             : 
     473           0 :   NS_ASSERTION(
     474             :     gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
     475             :     "Unknown gradientUnits type");
     476             : 
     477           0 :   return length.GetAnimValue(static_cast<SVGSVGElement*>(nullptr));
     478             : }
     479             : 
     480             : dom::SVGLinearGradientElement*
     481           0 : nsSVGLinearGradientFrame::GetLinearGradientWithLength(uint32_t aIndex,
     482             :   dom::SVGLinearGradientElement* aDefault)
     483             : {
     484             :   dom::SVGLinearGradientElement* thisElement =
     485           0 :     static_cast<dom::SVGLinearGradientElement*>(mContent);
     486           0 :   const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
     487             : 
     488           0 :   if (length.IsExplicitlySet()) {
     489           0 :     return thisElement;
     490             :   }
     491             : 
     492           0 :   return nsSVGGradientFrame::GetLinearGradientWithLength(aIndex, aDefault);
     493             : }
     494             : 
     495             : bool
     496           0 : nsSVGLinearGradientFrame::GradientVectorLengthIsZero()
     497             : {
     498           0 :   return GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1) ==
     499           0 :          GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2) &&
     500           0 :          GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1) ==
     501           0 :          GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2);
     502             : }
     503             : 
     504             : already_AddRefed<gfxPattern>
     505           0 : nsSVGLinearGradientFrame::CreateGradient()
     506             : {
     507             :   float x1, y1, x2, y2;
     508             : 
     509           0 :   x1 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1);
     510           0 :   y1 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1);
     511           0 :   x2 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2);
     512           0 :   y2 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2);
     513             : 
     514           0 :   RefPtr<gfxPattern> pattern = new gfxPattern(x1, y1, x2, y2);
     515           0 :   return pattern.forget();
     516             : }
     517             : 
     518             : // -------------------------------------------------------------------------
     519             : // Radial Gradients
     520             : // -------------------------------------------------------------------------
     521             : 
     522             : #ifdef DEBUG
     523             : void
     524           0 : nsSVGRadialGradientFrame::Init(nsIContent*       aContent,
     525             :                                nsContainerFrame* aParent,
     526             :                                nsIFrame*         aPrevInFlow)
     527             : {
     528           0 :   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::radialGradient),
     529             :                "Content is not an SVG radialGradient");
     530             : 
     531           0 :   nsSVGGradientFrame::Init(aContent, aParent, aPrevInFlow);
     532           0 : }
     533             : #endif /* DEBUG */
     534             : 
     535             : nsresult
     536           0 : nsSVGRadialGradientFrame::AttributeChanged(int32_t         aNameSpaceID,
     537             :                                            nsIAtom*        aAttribute,
     538             :                                            int32_t         aModType)
     539             : {
     540           0 :   if (aNameSpaceID == kNameSpaceID_None &&
     541           0 :       (aAttribute == nsGkAtoms::r ||
     542           0 :        aAttribute == nsGkAtoms::cx ||
     543           0 :        aAttribute == nsGkAtoms::cy ||
     544           0 :        aAttribute == nsGkAtoms::fx ||
     545           0 :        aAttribute == nsGkAtoms::fy)) {
     546           0 :     nsSVGEffects::InvalidateDirectRenderingObservers(this);
     547             :   }
     548             : 
     549           0 :   return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
     550           0 :                                               aAttribute, aModType);
     551             : }
     552             : 
     553             : //----------------------------------------------------------------------
     554             : 
     555             : float
     556           0 : nsSVGRadialGradientFrame::GetLengthValue(uint32_t aIndex)
     557             : {
     558             :   dom::SVGRadialGradientElement* lengthElement =
     559             :     GetRadialGradientWithLength(aIndex,
     560           0 :       static_cast<dom::SVGRadialGradientElement*>(mContent));
     561             :   // We passed in mContent as a fallback, so, assuming mContent is non-null,
     562             :   // the return value should also be non-null.
     563           0 :   MOZ_ASSERT(lengthElement,
     564             :     "Got unexpected null element from GetRadialGradientWithLength");
     565           0 :   return GetLengthValueFromElement(aIndex, *lengthElement);
     566             : }
     567             : 
     568             : float
     569           0 : nsSVGRadialGradientFrame::GetLengthValue(uint32_t aIndex, float aDefaultValue)
     570             : {
     571             :   dom::SVGRadialGradientElement* lengthElement =
     572           0 :     GetRadialGradientWithLength(aIndex, nullptr);
     573             : 
     574           0 :   return lengthElement ? GetLengthValueFromElement(aIndex, *lengthElement)
     575           0 :                        : aDefaultValue;
     576             : }
     577             : 
     578             : float
     579           0 : nsSVGRadialGradientFrame::GetLengthValueFromElement(uint32_t aIndex,
     580             :   dom::SVGRadialGradientElement& aElement)
     581             : {
     582           0 :   const nsSVGLength2 &length = aElement.mLengthAttributes[aIndex];
     583             : 
     584             :   // Object bounding box units are handled by setting the appropriate
     585             :   // transform in GetGradientTransform, but we need to handle user
     586             :   // space units as part of the individual Get* routines.  Fixes 323669.
     587             : 
     588           0 :   uint16_t gradientUnits = GetGradientUnits();
     589           0 :   if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
     590           0 :     return nsSVGUtils::UserSpace(mSource, &length);
     591             :   }
     592             : 
     593           0 :   NS_ASSERTION(
     594             :     gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
     595             :     "Unknown gradientUnits type");
     596             : 
     597           0 :   return length.GetAnimValue(static_cast<SVGSVGElement*>(nullptr));
     598             : }
     599             : 
     600             : dom::SVGRadialGradientElement*
     601           0 : nsSVGRadialGradientFrame::GetRadialGradientWithLength(uint32_t aIndex,
     602             :   dom::SVGRadialGradientElement* aDefault)
     603             : {
     604             :   dom::SVGRadialGradientElement* thisElement =
     605           0 :     static_cast<dom::SVGRadialGradientElement*>(mContent);
     606           0 :   const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
     607             : 
     608           0 :   if (length.IsExplicitlySet()) {
     609           0 :     return thisElement;
     610             :   }
     611             : 
     612           0 :   return nsSVGGradientFrame::GetRadialGradientWithLength(aIndex, aDefault);
     613             : }
     614             : 
     615             : bool
     616           0 : nsSVGRadialGradientFrame::GradientVectorLengthIsZero()
     617             : {
     618           0 :   return GetLengthValue(dom::SVGRadialGradientElement::ATTR_R) == 0;
     619             : }
     620             : 
     621             : already_AddRefed<gfxPattern>
     622           0 : nsSVGRadialGradientFrame::CreateGradient()
     623             : {
     624             :   float cx, cy, r, fx, fy, fr;
     625             : 
     626           0 :   cx = GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX);
     627           0 :   cy = GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY);
     628           0 :   r  = GetLengthValue(dom::SVGRadialGradientElement::ATTR_R);
     629             :   // If fx or fy are not set, use cx/cy instead
     630           0 :   fx = GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX, cx);
     631           0 :   fy = GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY, cy);
     632           0 :   fr = GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR);
     633             : 
     634           0 :   if (fx != cx || fy != cy) {
     635             :     // The focal point (fFx and fFy) must be clamped to be *inside* - not on -
     636             :     // the circumference of the gradient or we'll get rendering anomalies. We
     637             :     // calculate the distance from the focal point to the gradient center and
     638             :     // make sure it is *less* than the gradient radius.
     639             :     // 1/128 is the limit of the fractional part of cairo's 24.8 fixed point
     640             :     // representation divided by 2 to ensure that we get different cairo
     641             :     // fractions
     642           0 :     double dMax = std::max(0.0, r - 1.0/128);
     643           0 :     float dx = fx - cx;
     644           0 :     float dy = fy - cy;
     645           0 :     double d = sqrt((dx * dx) + (dy * dy));
     646           0 :     if (d > dMax) {
     647           0 :       double angle = atan2(dy, dx);
     648           0 :       fx = (float)(dMax * cos(angle)) + cx;
     649           0 :       fy = (float)(dMax * sin(angle)) + cy;
     650             :     }
     651             :   }
     652             : 
     653           0 :   RefPtr<gfxPattern> pattern = new gfxPattern(fx, fy, fr, cx, cy, r);
     654           0 :   return pattern.forget();
     655             : }
     656             : 
     657             : // -------------------------------------------------------------------------
     658             : // Public functions
     659             : // -------------------------------------------------------------------------
     660             : 
     661             : nsIFrame*
     662           0 : NS_NewSVGLinearGradientFrame(nsIPresShell*   aPresShell,
     663             :                              nsStyleContext* aContext)
     664             : {
     665           0 :   return new (aPresShell) nsSVGLinearGradientFrame(aContext);
     666             : }
     667             : 
     668           0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGLinearGradientFrame)
     669             : 
     670             : nsIFrame*
     671           0 : NS_NewSVGRadialGradientFrame(nsIPresShell*   aPresShell,
     672             :                              nsStyleContext* aContext)
     673             : {
     674           0 :   return new (aPresShell) nsSVGRadialGradientFrame(aContext);
     675             : }
     676             : 
     677           0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGRadialGradientFrame)

Generated by: LCOV version 1.13