LCOV - code coverage report
Current view: top level - layout/svg - nsSVGEffects.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 224 490 45.7 %
Date: 2017-07-14 16:53:18 Functions: 35 86 40.7 %
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 "nsSVGEffects.h"
       8             : 
       9             : // Keep others in (case-insensitive) order:
      10             : #include "mozilla/RestyleManager.h"
      11             : #include "mozilla/RestyleManagerInlines.h"
      12             : #include "nsCSSFrameConstructor.h"
      13             : #include "nsISupportsImpl.h"
      14             : #include "nsSVGClipPathFrame.h"
      15             : #include "nsSVGPaintServerFrame.h"
      16             : #include "nsSVGFilterFrame.h"
      17             : #include "nsSVGMaskFrame.h"
      18             : #include "nsIReflowCallback.h"
      19             : #include "nsCycleCollectionParticipant.h"
      20             : #include "SVGGeometryElement.h"
      21             : #include "SVGUseElement.h"
      22             : 
      23             : using namespace mozilla;
      24             : using namespace mozilla::dom;
      25             : 
      26             : void
      27          24 : nsSVGRenderingObserver::StartListening()
      28             : {
      29          24 :   Element* target = GetTarget();
      30          24 :   if (target) {
      31          23 :     target->AddMutationObserver(this);
      32             :   }
      33          24 : }
      34             : 
      35             : void
      36           0 : nsSVGRenderingObserver::StopListening()
      37             : {
      38           0 :   Element* target = GetTarget();
      39             : 
      40           0 :   if (target) {
      41           0 :     target->RemoveMutationObserver(this);
      42           0 :     if (mInObserverList) {
      43           0 :       nsSVGEffects::RemoveRenderingObserver(target, this);
      44           0 :       mInObserverList = false;
      45             :     }
      46             :   }
      47           0 :   NS_ASSERTION(!mInObserverList, "still in an observer list?");
      48           0 : }
      49             : 
      50             : static nsSVGRenderingObserverList *
      51         271 : GetObserverList(Element *aElement)
      52             : {
      53             :   return static_cast<nsSVGRenderingObserverList*>
      54         271 :     (aElement->GetProperty(nsGkAtoms::renderingobserverlist));
      55             : }
      56             : 
      57             : Element*
      58          20 : nsSVGRenderingObserver::GetReferencedElement()
      59             : {
      60          20 :   Element* target = GetTarget();
      61             : #ifdef DEBUG
      62          20 :   if (target) {
      63           6 :     nsSVGRenderingObserverList *observerList = GetObserverList(target);
      64           6 :     bool inObserverList = observerList && observerList->Contains(this);
      65           6 :     NS_ASSERTION(inObserverList == mInObserverList, "failed to track whether we're in our referenced element's observer list!");
      66             :   } else {
      67          14 :     NS_ASSERTION(!mInObserverList, "In whose observer list are we, then?");
      68             :   }
      69             : #endif
      70          20 :   if (target && !mInObserverList) {
      71           2 :     nsSVGEffects::AddRenderingObserver(target, this);
      72           2 :     mInObserverList = true;
      73             :   }
      74          20 :   return target;
      75             : }
      76             : 
      77             : nsIFrame*
      78          20 : nsSVGRenderingObserver::GetReferencedFrame()
      79             : {
      80          20 :   Element* referencedElement = GetReferencedElement();
      81          20 :   return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr;
      82             : }
      83             : 
      84             : nsIFrame*
      85          20 : nsSVGRenderingObserver::GetReferencedFrame(LayoutFrameType aFrameType,
      86             :                                            bool* aOK)
      87             : {
      88          20 :   nsIFrame* frame = GetReferencedFrame();
      89          20 :   if (frame) {
      90           6 :     if (frame->Type() == aFrameType)
      91           6 :       return frame;
      92           0 :     if (aOK) {
      93           0 :       *aOK = false;
      94             :     }
      95             :   }
      96          14 :   return nullptr;
      97             : }
      98             : 
      99             : void
     100          72 : nsSVGRenderingObserver::InvalidateViaReferencedElement()
     101             : {
     102          72 :   mInObserverList = false;
     103          72 :   DoUpdate();
     104          72 : }
     105             : 
     106             : void
     107           0 : nsSVGRenderingObserver::NotifyEvictedFromRenderingObserverList()
     108             : {
     109           0 :   mInObserverList = false; // We've been removed from rendering-obs. list.
     110           0 :   StopListening();            // Remove ourselves from mutation-obs. list.
     111           0 : }
     112             : 
     113             : void
     114           0 : nsSVGRenderingObserver::AttributeChanged(nsIDocument* aDocument,
     115             :                                          dom::Element* aElement,
     116             :                                          int32_t aNameSpaceID,
     117             :                                          nsIAtom* aAttribute,
     118             :                                          int32_t aModType,
     119             :                                          const nsAttrValue* aOldValue)
     120             : {
     121             :   // An attribute belonging to the element that we are observing *or one of its
     122             :   // descendants* has changed.
     123             :   //
     124             :   // In the case of observing a gradient element, say, we want to know if any
     125             :   // of its 'stop' element children change, but we don't actually want to do
     126             :   // anything for changes to SMIL element children, for example. Maybe it's not
     127             :   // worth having logic to optimize for that, but in most cases it could be a
     128             :   // small check?
     129             :   //
     130             :   // XXXjwatt: do we really want to blindly break the link between our
     131             :   // observers and ourselves for all attribute changes? For non-ID changes
     132             :   // surely that is unnecessary.
     133             : 
     134           0 :   DoUpdate();
     135           0 : }
     136             : 
     137             : void
     138           0 : nsSVGRenderingObserver::ContentAppended(nsIDocument* aDocument,
     139             :                                         nsIContent* aContainer,
     140             :                                         nsIContent* aFirstNewContent,
     141             :                                         int32_t /* unused */)
     142             : {
     143           0 :   DoUpdate();
     144           0 : }
     145             : 
     146             : void
     147           0 : nsSVGRenderingObserver::ContentInserted(nsIDocument* aDocument,
     148             :                                         nsIContent* aContainer,
     149             :                                         nsIContent* aChild,
     150             :                                         int32_t /* unused */)
     151             : {
     152           0 :   DoUpdate();
     153           0 : }
     154             : 
     155             : void
     156           0 : nsSVGRenderingObserver::ContentRemoved(nsIDocument* aDocument,
     157             :                                        nsIContent* aContainer,
     158             :                                        nsIContent* aChild,
     159             :                                        int32_t aIndexInContainer,
     160             :                                        nsIContent* aPreviousSibling)
     161             : {
     162           0 :   DoUpdate();
     163           0 : }
     164             : 
     165             : /**
     166             :  * Note that in the current setup there are two separate observer lists.
     167             :  *
     168             :  * In nsSVGIDRenderingObserver's ctor, the new object adds itself to the
     169             :  * mutation observer list maintained by the referenced element. In this way the
     170             :  * nsSVGIDRenderingObserver is notified if there are any attribute or content
     171             :  * tree changes to the element or any of its *descendants*.
     172             :  *
     173             :  * In nsSVGIDRenderingObserver::GetReferencedElement() the
     174             :  * nsSVGIDRenderingObserver object also adds itself to an
     175             :  * nsSVGRenderingObserverList object belonging to the referenced
     176             :  * element.
     177             :  *
     178             :  * XXX: it would be nice to have a clear and concise executive summary of the
     179             :  * benefits/necessity of maintaining a second observer list.
     180             :  */
     181             : 
     182           3 : nsSVGIDRenderingObserver::nsSVGIDRenderingObserver(nsIURI* aURI,
     183             :                                                    nsIContent* aObservingContent,
     184           3 :                                                    bool aReferenceImage)
     185           3 :   : mElement(this)
     186             : {
     187             :   // Start watching the target element
     188           3 :   mElement.Reset(aObservingContent, aURI, true, aReferenceImage);
     189           3 :   StartListening();
     190           3 : }
     191             : 
     192           0 : nsSVGIDRenderingObserver::~nsSVGIDRenderingObserver()
     193             : {
     194           0 :   StopListening();
     195           0 : }
     196             : 
     197             : void
     198           0 : nsSVGIDRenderingObserver::DoUpdate()
     199             : {
     200           0 :   if (mElement.get() && mInObserverList) {
     201           0 :     nsSVGEffects::RemoveRenderingObserver(mElement.get(), this);
     202           0 :     mInObserverList = false;
     203             :   }
     204           0 : }
     205             : 
     206             : void
     207           0 : nsSVGFrameReferenceFromProperty::Detach()
     208             : {
     209           0 :   mFrame = nullptr;
     210           0 :   mFramePresShell = nullptr;
     211           0 : }
     212             : 
     213             : nsIFrame*
     214           0 : nsSVGFrameReferenceFromProperty::Get()
     215             : {
     216           0 :   if (mFramePresShell && mFramePresShell->IsDestroying()) {
     217             :     // mFrame is no longer valid.
     218           0 :     Detach();
     219             :   }
     220           0 :   return mFrame;
     221             : }
     222             : 
     223           3 : NS_IMPL_ISUPPORTS(nsSVGRenderingObserverProperty, nsIMutationObserver)
     224             : 
     225             : void
     226           0 : nsSVGRenderingObserverProperty::DoUpdate()
     227             : {
     228           0 :   nsSVGIDRenderingObserver::DoUpdate();
     229             : 
     230           0 :   nsIFrame* frame = mFrameReference.Get();
     231           0 :   if (frame && frame->IsFrameOfType(nsIFrame::eSVG)) {
     232             :     // Changes should propagate out to things that might be observing
     233             :     // the referencing frame or its ancestors.
     234           0 :     nsLayoutUtils::PostRestyleEvent(
     235           0 :       frame->GetContent()->AsElement(), nsRestyleHint(0),
     236           0 :       nsChangeHint_InvalidateRenderingObservers);
     237             :   }
     238           0 : }
     239             : 
     240           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGFilterReference)
     241           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGFilterReference)
     242             : 
     243             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGFilterReference)
     244             : 
     245           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsSVGFilterReference)
     246           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
     247           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     248             : 
     249           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsSVGFilterReference)
     250           0 :   tmp->StopListening();
     251           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement);
     252           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     253             : 
     254           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGFilterReference)
     255           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsSVGIDRenderingObserver)
     256           0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     257           0 :   NS_INTERFACE_MAP_ENTRY(nsISVGFilterReference)
     258           0 : NS_INTERFACE_MAP_END
     259             : 
     260             : nsSVGFilterFrame *
     261           0 : nsSVGFilterReference::GetFilterFrame()
     262             : {
     263             :   return static_cast<nsSVGFilterFrame*>(
     264           0 :     GetReferencedFrame(LayoutFrameType::SVGFilter, nullptr));
     265             : }
     266             : 
     267             : void
     268           0 : nsSVGFilterReference::DoUpdate()
     269             : {
     270           0 :   nsSVGIDRenderingObserver::DoUpdate();
     271             : 
     272           0 :   if (mFilterChainObserver) {
     273           0 :     mFilterChainObserver->Invalidate();
     274             :   }
     275           0 : }
     276             : 
     277           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGFilterChainObserver)
     278           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGFilterChainObserver)
     279             : 
     280             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGFilterChainObserver)
     281             : 
     282           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsSVGFilterChainObserver)
     283           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReferences)
     284           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     285             : 
     286           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsSVGFilterChainObserver)
     287           0 :   tmp->DetachReferences();
     288           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mReferences);
     289           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     290             : 
     291           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGFilterChainObserver)
     292           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     293           0 : NS_INTERFACE_MAP_END
     294             : 
     295           0 : nsSVGFilterChainObserver::nsSVGFilterChainObserver(const nsTArray<nsStyleFilter>& aFilters,
     296             :                                                    nsIContent* aFilteredElement,
     297           0 :                                                    nsIFrame* aFilteredFrame)
     298             : {
     299           0 :   for (uint32_t i = 0; i < aFilters.Length(); i++) {
     300           0 :     if (aFilters[i].GetType() != NS_STYLE_FILTER_URL)
     301           0 :       continue;
     302             : 
     303             :     // aFilteredFrame can be null if this filter belongs to a
     304             :     // CanvasRenderingContext2D.
     305             :     nsCOMPtr<nsIURI> filterURL = aFilteredFrame
     306           0 :       ? nsSVGEffects::GetFilterURI(aFilteredFrame, i)
     307           0 :       : aFilters[i].GetURL()->ResolveLocalRef(aFilteredElement);
     308             : 
     309             :     RefPtr<nsSVGFilterReference> reference =
     310           0 :       new nsSVGFilterReference(filterURL, aFilteredElement, this);
     311           0 :     mReferences.AppendElement(reference);
     312             :   }
     313           0 : }
     314             : 
     315           0 : nsSVGFilterChainObserver::~nsSVGFilterChainObserver()
     316             : {
     317           0 :   DetachReferences();
     318           0 : }
     319             : 
     320             : bool
     321           0 : nsSVGFilterChainObserver::ReferencesValidResources()
     322             : {
     323           0 :   for (uint32_t i = 0; i < mReferences.Length(); i++) {
     324           0 :     if (!mReferences[i]->ReferencesValidResource())
     325           0 :       return false;
     326             :   }
     327           0 :   return true;
     328             : }
     329             : 
     330             : bool
     331           0 : nsSVGFilterChainObserver::IsInObserverLists() const
     332             : {
     333           0 :   for (uint32_t i = 0; i < mReferences.Length(); i++) {
     334           0 :     if (!mReferences[i]->IsInObserverList())
     335           0 :       return false;
     336             :   }
     337           0 :   return true;
     338             : }
     339             : 
     340             : void
     341           0 : nsSVGFilterProperty::DoUpdate()
     342             : {
     343           0 :   nsIFrame* frame = mFrameReference.Get();
     344           0 :   if (!frame)
     345           0 :     return;
     346             : 
     347             :   // Repaint asynchronously in case the filter frame is being torn down
     348             :   nsChangeHint changeHint =
     349           0 :     nsChangeHint(nsChangeHint_RepaintFrame);
     350             : 
     351           0 :   if (frame && frame->IsFrameOfType(nsIFrame::eSVG)) {
     352             :     // Changes should propagate out to things that might be observing
     353             :     // the referencing frame or its ancestors.
     354           0 :     changeHint |= nsChangeHint_InvalidateRenderingObservers;
     355             :   }
     356             : 
     357             :   // Don't need to request UpdateOverflow if we're being reflowed.
     358           0 :   if (!(frame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
     359           0 :     changeHint |= nsChangeHint_UpdateOverflow;
     360             :   }
     361           0 :   frame->PresContext()->RestyleManager()->PostRestyleEvent(
     362           0 :     frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
     363             : }
     364             : 
     365             : void
     366           0 : nsSVGMarkerProperty::DoUpdate()
     367             : {
     368           0 :   nsSVGRenderingObserverProperty::DoUpdate();
     369             : 
     370           0 :   nsIFrame* frame = mFrameReference.Get();
     371           0 :   if (!frame)
     372           0 :     return;
     373             : 
     374           0 :   NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
     375             : 
     376             :   // Repaint asynchronously in case the marker frame is being torn down
     377             :   nsChangeHint changeHint =
     378           0 :     nsChangeHint(nsChangeHint_RepaintFrame);
     379             : 
     380             :   // Don't need to request ReflowFrame if we're being reflowed.
     381           0 :   if (!(frame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
     382           0 :     changeHint |= nsChangeHint_InvalidateRenderingObservers;
     383             :     // XXXjwatt: We need to unify SVG into standard reflow so we can just use
     384             :     // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
     385             :     // XXXSDL KILL THIS!!!
     386           0 :     nsSVGUtils::ScheduleReflowSVG(frame);
     387             :   }
     388           0 :   frame->PresContext()->RestyleManager()->PostRestyleEvent(
     389           0 :     frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
     390             : }
     391             : 
     392           1 : NS_IMPL_ISUPPORTS(nsSVGMaskProperty, nsISupports)
     393             : 
     394           1 : nsSVGMaskProperty::nsSVGMaskProperty(nsIFrame* aFrame)
     395             : {
     396           1 :   const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
     397             : 
     398           2 :   for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
     399           2 :     nsCOMPtr<nsIURI> maskUri = nsSVGEffects::GetMaskURI(aFrame, i);
     400             :     nsSVGPaintingProperty* prop = new nsSVGPaintingProperty(maskUri, aFrame,
     401           2 :                                                             false);
     402           1 :     mProperties.AppendElement(prop);
     403             :   }
     404           1 : }
     405             : 
     406             : bool
     407           0 : nsSVGTextPathProperty::TargetIsValid()
     408             : {
     409           0 :   Element* target = GetTarget();
     410           0 :   return target && target->IsSVGElement(nsGkAtoms::path);
     411             : }
     412             : 
     413             : void
     414           0 : nsSVGTextPathProperty::DoUpdate()
     415             : {
     416           0 :   nsSVGRenderingObserverProperty::DoUpdate();
     417             : 
     418           0 :   nsIFrame* frame = mFrameReference.Get();
     419           0 :   if (!frame)
     420           0 :     return;
     421             : 
     422           0 :   NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG) ||
     423             :                nsSVGUtils::IsInSVGTextSubtree(frame),
     424             :                "SVG frame expected");
     425             : 
     426             :   // Avoid getting into an infinite loop of reflows if the <textPath> is
     427             :   // pointing to one of its ancestors.  TargetIsValid returns true iff
     428             :   // the target element is a <path> element, and we would not have this
     429             :   // nsSVGTextPathProperty if this <textPath> were a descendant of the
     430             :   // target <path>.
     431             :   //
     432             :   // Note that we still have to post the restyle event when we
     433             :   // change from being valid to invalid, so that mPositions on the
     434             :   // SVGTextFrame gets updated, skipping the <textPath>, ensuring
     435             :   // that nothing gets painted for that element.
     436           0 :   bool nowValid = TargetIsValid();
     437           0 :   if (!mValid && !nowValid) {
     438             :     // Just return if we were previously invalid, and are still invalid.
     439           0 :     return;
     440             :   }
     441           0 :   mValid = nowValid;
     442             : 
     443             :   // Repaint asynchronously in case the path frame is being torn down
     444             :   nsChangeHint changeHint =
     445           0 :     nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateTextPath);
     446           0 :   frame->PresContext()->RestyleManager()->PostRestyleEvent(
     447           0 :     frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
     448             : }
     449             : 
     450             : static void
     451           0 : InvalidateAllContinuations(nsIFrame* aFrame)
     452             : {
     453           0 :   for (nsIFrame* f = aFrame; f;
     454             :        f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
     455           0 :     f->InvalidateFrame();
     456             :   }
     457           0 : }
     458             : 
     459             : void
     460           0 : nsSVGPaintingProperty::DoUpdate()
     461             : {
     462           0 :   nsSVGRenderingObserverProperty::DoUpdate();
     463             : 
     464           0 :   nsIFrame* frame = mFrameReference.Get();
     465           0 :   if (!frame)
     466           0 :     return;
     467             : 
     468           0 :   if (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
     469           0 :     nsLayoutUtils::PostRestyleEvent(
     470           0 :       frame->GetContent()->AsElement(), nsRestyleHint(0),
     471           0 :       nsChangeHint_InvalidateRenderingObservers);
     472           0 :     frame->InvalidateFrameSubtree();
     473             :   } else {
     474           0 :     InvalidateAllContinuations(frame);
     475             :   }
     476             : }
     477             : 
     478             : static nsSVGFilterProperty*
     479         137 : GetOrCreateFilterProperty(nsIFrame* aFrame)
     480             : {
     481         137 :   const nsStyleEffects* effects = aFrame->StyleEffects();
     482         137 :   if (!effects->HasFilters())
     483         137 :     return nullptr;
     484             : 
     485             :   nsSVGFilterProperty *prop =
     486           0 :     aFrame->GetProperty(nsSVGEffects::FilterProperty());
     487           0 :   if (prop)
     488           0 :     return prop;
     489           0 :   prop = new nsSVGFilterProperty(effects->mFilters, aFrame);
     490           0 :   NS_ADDREF(prop);
     491           0 :   aFrame->SetProperty(nsSVGEffects::FilterProperty(), prop);
     492           0 :   return prop;
     493             : }
     494             : 
     495             : static nsSVGMaskProperty*
     496          15 : GetOrCreateMaskProperty(nsIFrame* aFrame)
     497             : {
     498          15 :   nsSVGMaskProperty *prop = aFrame->GetProperty(nsSVGEffects::MaskProperty());
     499          15 :   if (prop)
     500          14 :     return prop;
     501             : 
     502           1 :   prop = new nsSVGMaskProperty(aFrame);
     503           1 :   NS_ADDREF(prop);
     504           1 :   aFrame->SetProperty(nsSVGEffects::MaskProperty(), prop);
     505           1 :   return prop;
     506             : }
     507             : 
     508             : template<class T>
     509             : static T*
     510         392 : GetEffectProperty(nsIURI* aURI, nsIFrame* aFrame,
     511             :   const mozilla::FramePropertyDescriptor<T>* aProperty)
     512             : {
     513         392 :   if (!aURI)
     514         384 :     return nullptr;
     515             : 
     516           8 :   T* prop = aFrame->GetProperty(aProperty);
     517           8 :   if (prop)
     518           6 :     return prop;
     519           2 :   prop = new T(aURI, aFrame, false);
     520           2 :   NS_ADDREF(prop);
     521           2 :   aFrame->SetProperty(aProperty, prop);
     522           2 :   return prop;
     523             : }
     524             : 
     525             : nsSVGMarkerProperty*
     526         384 : nsSVGEffects::GetMarkerProperty(nsIURI* aURI, nsIFrame* aFrame,
     527             :   const mozilla::FramePropertyDescriptor<nsSVGMarkerProperty>* aProperty)
     528             : {
     529         384 :   MOZ_ASSERT(aFrame->IsSVGGeometryFrame() &&
     530             :              static_cast<SVGGeometryElement*>(aFrame->GetContent())->IsMarkable(),
     531             :              "Bad frame");
     532         384 :   return GetEffectProperty(aURI, aFrame, aProperty);
     533             : }
     534             : 
     535             : nsSVGTextPathProperty*
     536           0 : nsSVGEffects::GetTextPathProperty(nsIURI* aURI, nsIFrame* aFrame,
     537             :   const mozilla::FramePropertyDescriptor<nsSVGTextPathProperty>* aProperty)
     538             : {
     539           0 :   return GetEffectProperty(aURI, aFrame, aProperty);
     540             : }
     541             : 
     542             : nsSVGPaintingProperty*
     543           8 : nsSVGEffects::GetPaintingProperty(nsIURI* aURI, nsIFrame* aFrame,
     544             :   const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty)
     545             : {
     546           8 :   return GetEffectProperty(aURI, aFrame, aProperty);
     547             : }
     548             : 
     549             : nsSVGPaintingProperty*
     550           0 : nsSVGEffects::GetPaintingPropertyForURI(nsIURI* aURI, nsIFrame* aFrame,
     551             :   URIObserverHashtablePropertyDescriptor aProperty)
     552             : {
     553           0 :   if (!aURI)
     554           0 :     return nullptr;
     555             : 
     556             :   nsSVGEffects::URIObserverHashtable *hashtable =
     557           0 :     aFrame->GetProperty(aProperty);
     558           0 :   if (!hashtable) {
     559           0 :     hashtable = new nsSVGEffects::URIObserverHashtable();
     560           0 :     aFrame->SetProperty(aProperty, hashtable);
     561             :   }
     562             :   nsSVGPaintingProperty* prop =
     563           0 :     static_cast<nsSVGPaintingProperty*>(hashtable->GetWeak(aURI));
     564           0 :   if (!prop) {
     565           0 :     bool watchImage = aProperty == nsSVGEffects::BackgroundImageProperty();
     566           0 :     prop = new nsSVGPaintingProperty(aURI, aFrame, watchImage);
     567           0 :     hashtable->Put(aURI, prop);
     568             :   }
     569           0 :   return prop;
     570             : }
     571             : 
     572             : nsSVGEffects::EffectProperties
     573          37 : nsSVGEffects::GetEffectProperties(nsIFrame* aFrame)
     574             : {
     575          37 :   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
     576             : 
     577             :   EffectProperties result;
     578          37 :   const nsStyleSVGReset *style = aFrame->StyleSVGReset();
     579             : 
     580          37 :   result.mFilter = GetOrCreateFilterProperty(aFrame);
     581             : 
     582          37 :   if (style->mClipPath.GetType() == StyleShapeSourceType::URL) {
     583          16 :     nsCOMPtr<nsIURI> pathURI = nsSVGEffects::GetClipPathURI(aFrame);
     584           8 :     result.mClipPath =
     585           8 :       GetPaintingProperty(pathURI, aFrame, ClipPathProperty());
     586             :   } else {
     587          29 :     result.mClipPath = nullptr;
     588             :   }
     589             : 
     590          37 :   MOZ_ASSERT(style->mMask.mImageCount > 0);
     591          74 :   result.mMask = style->HasMask()
     592          37 :                  ? GetOrCreateMaskProperty(aFrame) : nullptr;
     593             : 
     594          37 :   return result;
     595             : }
     596             : 
     597             : nsSVGPaintServerFrame *
     598          34 : nsSVGEffects::GetPaintServer(nsIFrame* aTargetFrame,
     599             :                              nsStyleSVGPaint nsStyleSVG::* aPaint,
     600             :                              PaintingPropertyDescriptor aType)
     601             : {
     602          34 :   const nsStyleSVG* svgStyle = aTargetFrame->StyleSVG();
     603          34 :   if ((svgStyle->*aPaint).Type() != eStyleSVGPaintType_Server)
     604          34 :     return nullptr;
     605             : 
     606             :   // If we're looking at a frame within SVG text, then we need to look up
     607             :   // to find the right frame to get the painting property off.  We should at
     608             :   // least look up past a text frame, and if the text frame's parent is the
     609             :   // anonymous block frame, then we look up to its parent (the SVGTextFrame).
     610           0 :   nsIFrame* frame = aTargetFrame;
     611           0 :   if (frame->GetContent()->IsNodeOfType(nsINode::eTEXT)) {
     612           0 :     frame = frame->GetParent();
     613           0 :     nsIFrame* grandparent = frame->GetParent();
     614           0 :     if (grandparent && grandparent->IsSVGTextFrame()) {
     615           0 :       frame = grandparent;
     616             :     }
     617             :   }
     618             : 
     619           0 :   nsCOMPtr<nsIURI> paintServerURL = nsSVGEffects::GetPaintURI(frame, aPaint);
     620             :   nsSVGPaintingProperty *property =
     621           0 :     nsSVGEffects::GetPaintingProperty(paintServerURL, frame, aType);
     622           0 :   if (!property)
     623           0 :     return nullptr;
     624           0 :   nsIFrame* result = property->GetReferencedFrame();
     625           0 :   if (!result)
     626           0 :     return nullptr;
     627             : 
     628           0 :   LayoutFrameType type = result->Type();
     629           0 :   if (type != LayoutFrameType::SVGLinearGradient &&
     630           0 :       type != LayoutFrameType::SVGRadialGradient &&
     631             :       type != LayoutFrameType::SVGPattern)
     632           0 :     return nullptr;
     633             : 
     634           0 :   return static_cast<nsSVGPaintServerFrame*>(result);
     635             : }
     636             : 
     637             : nsSVGClipPathFrame *
     638          22 : nsSVGEffects::EffectProperties::GetClipPathFrame()
     639             : {
     640          22 :   if (!mClipPath)
     641          18 :     return nullptr;
     642             : 
     643             :   nsSVGClipPathFrame* frame = static_cast<nsSVGClipPathFrame*>(
     644           4 :     mClipPath->GetReferencedFrame(LayoutFrameType::SVGClipPath, nullptr));
     645             : 
     646           4 :   return frame;
     647             : }
     648             : 
     649             : nsTArray<nsSVGMaskFrame *>
     650          15 : nsSVGEffects::EffectProperties::GetMaskFrames()
     651             : {
     652          15 :   nsTArray<nsSVGMaskFrame *> result;
     653          15 :   if (!mMask)
     654           6 :     return result;
     655             : 
     656           9 :   bool ok = true;
     657           9 :   const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
     658          18 :   for (size_t i = 0; i < props.Length(); i++) {
     659             :     nsSVGMaskFrame* maskFrame = static_cast<nsSVGMaskFrame*>(
     660           9 :       props[i]->GetReferencedFrame(LayoutFrameType::SVGMask, &ok));
     661           9 :     MOZ_ASSERT(!maskFrame || ok);
     662           9 :     result.AppendElement(maskFrame);
     663             :   }
     664             : 
     665           9 :   return result;
     666             : }
     667             : 
     668             : bool
     669           0 : nsSVGEffects::EffectProperties::HasNoOrValidEffects()
     670             : {
     671           0 :   return HasNoOrValidClipPath() && HasNoOrValidMask() && HasNoOrValidFilter();
     672             : }
     673             : 
     674             : bool
     675           9 : nsSVGEffects::EffectProperties::HasNoOrValidClipPath()
     676             : {
     677           9 :   if (mClipPath) {
     678           2 :     bool ok = true;
     679             :     nsSVGClipPathFrame* frame = static_cast<nsSVGClipPathFrame*>(
     680           2 :       mClipPath->GetReferencedFrame(LayoutFrameType::SVGClipPath, &ok));
     681           2 :     if (!ok || (frame && !frame->IsValid())) {
     682           0 :       return false;
     683             :     }
     684             :   }
     685             : 
     686           9 :   return true;
     687             : }
     688             : 
     689             : bool
     690           7 : nsSVGEffects::EffectProperties::HasNoOrValidMask()
     691             : {
     692           7 :   if (mMask) {
     693           5 :     bool ok = true;
     694           5 :     const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
     695          10 :     for (size_t i = 0; i < props.Length(); i++) {
     696           5 :       props[i]->GetReferencedFrame(LayoutFrameType::SVGMask, &ok);
     697           5 :       if (!ok) {
     698           0 :         return false;
     699             :       }
     700             :     }
     701             :   }
     702             : 
     703           7 :   return true;
     704             : }
     705             : 
     706             : void
     707         100 : nsSVGEffects::UpdateEffects(nsIFrame* aFrame)
     708             : {
     709         100 :   NS_ASSERTION(aFrame->GetContent()->IsElement(),
     710             :                "aFrame's content should be an element");
     711             : 
     712         100 :   aFrame->DeleteProperty(FilterProperty());
     713         100 :   aFrame->DeleteProperty(MaskProperty());
     714         100 :   aFrame->DeleteProperty(ClipPathProperty());
     715         100 :   aFrame->DeleteProperty(MarkerBeginProperty());
     716         100 :   aFrame->DeleteProperty(MarkerMiddleProperty());
     717         100 :   aFrame->DeleteProperty(MarkerEndProperty());
     718         100 :   aFrame->DeleteProperty(FillProperty());
     719         100 :   aFrame->DeleteProperty(StrokeProperty());
     720         100 :   aFrame->DeleteProperty(BackgroundImageProperty());
     721             : 
     722             :   // Ensure that the filter is repainted correctly
     723             :   // We can't do that in DoUpdate as the referenced frame may not be valid
     724         100 :   GetOrCreateFilterProperty(aFrame);
     725             : 
     726         148 :   if (aFrame->IsSVGGeometryFrame() &&
     727          48 :       static_cast<SVGGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
     728             :     // Set marker properties here to avoid reference loops
     729             :     nsCOMPtr<nsIURI> markerURL =
     730          76 :       GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
     731          38 :     GetMarkerProperty(markerURL, aFrame, MarkerBeginProperty());
     732          38 :     markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
     733          38 :     GetMarkerProperty(markerURL, aFrame, MarkerMiddleProperty());
     734          38 :     markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
     735          38 :     GetMarkerProperty(markerURL, aFrame, MarkerEndProperty());
     736             :   }
     737         100 : }
     738             : 
     739             : nsSVGFilterProperty*
     740          11 : nsSVGEffects::GetFilterProperty(nsIFrame* aFrame)
     741             : {
     742          11 :   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
     743             : 
     744          11 :   if (!aFrame->StyleEffects()->HasFilters())
     745          11 :     return nullptr;
     746             : 
     747           0 :   return aFrame->GetProperty(FilterProperty());
     748             : }
     749             : 
     750             : void
     751          18 : nsSVGRenderingObserverList::InvalidateAll()
     752             : {
     753          18 :   if (mObservers.Count() == 0)
     754           0 :     return;
     755             : 
     756          36 :   AutoTArray<nsSVGRenderingObserver*,10> observers;
     757             : 
     758          36 :   for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
     759          18 :     observers.AppendElement(it.Get()->GetKey());
     760             :   }
     761          18 :   mObservers.Clear();
     762             : 
     763          36 :   for (uint32_t i = 0; i < observers.Length(); ++i) {
     764          18 :     observers[i]->InvalidateViaReferencedElement();
     765             :   }
     766             : }
     767             : 
     768             : void
     769          54 : nsSVGRenderingObserverList::InvalidateAllForReflow()
     770             : {
     771          54 :   if (mObservers.Count() == 0)
     772           0 :     return;
     773             : 
     774         108 :   AutoTArray<nsSVGRenderingObserver*,10> observers;
     775             : 
     776         108 :   for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
     777          54 :     nsSVGRenderingObserver* obs = it.Get()->GetKey();
     778          54 :     if (obs->ObservesReflow()) {
     779          54 :       observers.AppendElement(obs);
     780          54 :       it.Remove();
     781             :     }
     782             :   }
     783             : 
     784         108 :   for (uint32_t i = 0; i < observers.Length(); ++i) {
     785          54 :     observers[i]->InvalidateViaReferencedElement();
     786             :   }
     787             : }
     788             : 
     789             : void
     790           0 : nsSVGRenderingObserverList::RemoveAll()
     791             : {
     792           0 :   AutoTArray<nsSVGRenderingObserver*,10> observers;
     793             : 
     794           0 :   for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
     795           0 :     observers.AppendElement(it.Get()->GetKey());
     796             :   }
     797           0 :   mObservers.Clear();
     798             : 
     799             :   // Our list is now cleared.  We need to notify the observers we've removed,
     800             :   // so they can update their state & remove themselves as mutation-observers.
     801           0 :   for (uint32_t i = 0; i < observers.Length(); ++i) {
     802           0 :     observers[i]->NotifyEvictedFromRenderingObserverList();
     803             :   }
     804           0 : }
     805             : 
     806             : void
     807          95 : nsSVGEffects::AddRenderingObserver(Element* aElement,
     808             :                                    nsSVGRenderingObserver* aObserver)
     809             : {
     810          95 :   nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
     811          95 :   if (!observerList) {
     812          23 :     observerList = new nsSVGRenderingObserverList();
     813          23 :     if (!observerList)
     814           0 :       return;
     815          23 :     aElement->SetProperty(nsGkAtoms::renderingobserverlist, observerList,
     816          46 :                           nsINode::DeleteProperty<nsSVGRenderingObserverList>);
     817             :   }
     818          95 :   aElement->SetHasRenderingObservers(true);
     819          95 :   observerList->Add(aObserver);
     820             : }
     821             : 
     822             : void
     823           0 : nsSVGEffects::RemoveRenderingObserver(Element* aElement,
     824             :                                       nsSVGRenderingObserver* aObserver)
     825             : {
     826           0 :   nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
     827           0 :   if (observerList) {
     828           0 :     NS_ASSERTION(observerList->Contains(aObserver),
     829             :                  "removing observer from an element we're not observing?");
     830           0 :     observerList->Remove(aObserver);
     831           0 :     if (observerList->IsEmpty()) {
     832           0 :       aElement->SetHasRenderingObservers(false);
     833             :     }
     834             :   }
     835           0 : }
     836             : 
     837             : void
     838           0 : nsSVGEffects::RemoveAllRenderingObservers(Element* aElement)
     839             : {
     840           0 :   nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
     841           0 :   if (observerList) {
     842           0 :     observerList->RemoveAll();
     843           0 :     aElement->SetHasRenderingObservers(false);
     844             :   }
     845           0 : }
     846             : 
     847             : void
     848          23 : nsSVGEffects::InvalidateRenderingObservers(nsIFrame* aFrame)
     849             : {
     850          23 :   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
     851             : 
     852          23 :   nsIContent* content = aFrame->GetContent();
     853          23 :   if (!content || !content->IsElement())
     854           0 :     return;
     855             : 
     856             :   // If the rendering has changed, the bounds may well have changed too:
     857          23 :   aFrame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty());
     858             : 
     859             :   nsSVGRenderingObserverList *observerList =
     860          23 :     GetObserverList(content->AsElement());
     861          23 :   if (observerList) {
     862           0 :     observerList->InvalidateAll();
     863           0 :     return;
     864             :   }
     865             : 
     866             :   // Check ancestor SVG containers. The root frame cannot be of type
     867             :   // eSVGContainer so we don't have to check f for null here.
     868         196 :   for (nsIFrame *f = aFrame->GetParent();
     869          98 :        f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
     870          75 :     if (f->GetContent()->IsElement()) {
     871          75 :       observerList = GetObserverList(f->GetContent()->AsElement());
     872          75 :       if (observerList) {
     873           0 :         observerList->InvalidateAll();
     874           0 :         return;
     875             :       }
     876             :     }
     877             :   }
     878             : }
     879             : 
     880             : void
     881        3404 : nsSVGEffects::InvalidateDirectRenderingObservers(Element* aElement, uint32_t aFlags /* = 0 */)
     882             : {
     883        3404 :   nsIFrame* frame = aElement->GetPrimaryFrame();
     884        3404 :   if (frame) {
     885             :     // If the rendering has changed, the bounds may well have changed too:
     886        3344 :     frame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty());
     887             :   }
     888             : 
     889        3404 :   if (aElement->HasRenderingObservers()) {
     890          72 :     nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
     891          72 :     if (observerList) {
     892          72 :       if (aFlags & INVALIDATE_REFLOW) {
     893          54 :         observerList->InvalidateAllForReflow();
     894             :       } else {
     895          18 :         observerList->InvalidateAll();
     896             :       }
     897             :     }
     898             :   }
     899        3404 : }
     900             : 
     901             : void
     902        3842 : nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame* aFrame, uint32_t aFlags /* = 0 */)
     903             : {
     904        3842 :   nsIContent* content = aFrame->GetContent();
     905        3842 :   if (content && content->IsElement()) {
     906        3400 :     InvalidateDirectRenderingObservers(content->AsElement(), aFlags);
     907             :   }
     908        3842 : }
     909             : 
     910             : already_AddRefed<nsIURI>
     911          31 : nsSVGEffects::GetBaseURLForLocalRef(nsIContent* content, nsIURI* aDocURI)
     912             : {
     913          31 :   MOZ_ASSERT(content);
     914             : 
     915             :   // For a local-reference URL, resolve that fragment against the current
     916             :   // document that relative URLs are resolved against.
     917          62 :   nsCOMPtr<nsIURI> baseURI = content->OwnerDoc()->GetDocumentURI();
     918             : 
     919          31 :   if (content->IsInAnonymousSubtree()) {
     920           0 :     nsIContent* bindingParent = content->GetBindingParent();
     921           0 :     nsCOMPtr<nsIURI> originalURI;
     922             : 
     923             :     // content is in a shadow tree.  If this URL was specified in the subtree
     924             :     // referenced by the <use>(or -moz-binding) element, and that subtree came
     925             :     // from a separate resource document, then we want the fragment-only URL
     926             :     // to resolve to an element from the resource document.  Otherwise, the
     927             :     // URL was specified somewhere in the document with the <use> element, and
     928             :     // we want the fragment-only URL to resolve to an element in that document.
     929           0 :     if (bindingParent) {
     930           0 :       if (content->IsAnonymousContentInSVGUseSubtree()) {
     931           0 :         SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
     932           0 :         originalURI = useElement->GetSourceDocURI();
     933             :       } else {
     934           0 :         nsXBLBinding* binding = bindingParent->GetXBLBinding();
     935           0 :         if (binding) {
     936           0 :           originalURI = binding->GetSourceDocURI();
     937             :         } else {
     938           0 :           MOZ_ASSERT(content->IsInNativeAnonymousSubtree(),
     939             :                      "an non-native anonymous tree which is not from "
     940             :                      "an XBL binding?");
     941             :         }
     942             :       }
     943             : 
     944           0 :       if (originalURI) {
     945           0 :         bool isEqualsExceptRef = false;
     946           0 :         aDocURI->EqualsExceptRef(originalURI, &isEqualsExceptRef);
     947           0 :         if (isEqualsExceptRef) {
     948           0 :           baseURI = originalURI;
     949             :         }
     950             :       }
     951             :     }
     952             :   }
     953             : 
     954          62 :   return baseURI.forget();
     955             : }
     956             : 
     957             : static already_AddRefed<nsIURI>
     958         393 : ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL)
     959             : {
     960         393 :   MOZ_ASSERT(aFrame);
     961             : 
     962         393 :   if (!aURL) {
     963         385 :     return nullptr;
     964             :   }
     965             : 
     966             :   // Non-local-reference URL.
     967           8 :   if (!aURL->IsLocalRef()) {
     968           0 :     nsCOMPtr<nsIURI> result = aURL->GetURI();
     969           0 :     return result.forget();
     970             :   }
     971             : 
     972             :   nsCOMPtr<nsIURI> baseURI =
     973          16 :     nsSVGEffects::GetBaseURLForLocalRef(aFrame->GetContent(), aURL->GetURI());
     974             : 
     975           8 :   return aURL->ResolveLocalRef(baseURI);
     976             : }
     977             : 
     978             : already_AddRefed<nsIURI>
     979         384 : nsSVGEffects::GetMarkerURI(nsIFrame* aFrame,
     980             :                            RefPtr<css::URLValue> nsStyleSVG::* aMarker)
     981             : {
     982         384 :   return ResolveURLUsingLocalRef(aFrame, aFrame->StyleSVG()->*aMarker);
     983             : }
     984             : 
     985             : already_AddRefed<nsIURI>
     986           8 : nsSVGEffects::GetClipPathURI(nsIFrame* aFrame)
     987             : {
     988           8 :   const nsStyleSVGReset* svgResetStyle = aFrame->StyleSVGReset();
     989           8 :   MOZ_ASSERT(svgResetStyle->mClipPath.GetType() == StyleShapeSourceType::URL);
     990             : 
     991           8 :   css::URLValue* url = svgResetStyle->mClipPath.GetURL();
     992           8 :   return ResolveURLUsingLocalRef(aFrame, url);
     993             : }
     994             : 
     995             : already_AddRefed<nsIURI>
     996           0 : nsSVGEffects::GetFilterURI(nsIFrame* aFrame, uint32_t aIndex)
     997             : {
     998           0 :   const nsStyleEffects* effects = aFrame->StyleEffects();
     999           0 :   MOZ_ASSERT(effects->mFilters.Length() > aIndex);
    1000           0 :   MOZ_ASSERT(effects->mFilters[aIndex].GetType() == NS_STYLE_FILTER_URL);
    1001             : 
    1002           0 :   return ResolveURLUsingLocalRef(aFrame, effects->mFilters[aIndex].GetURL());
    1003             : }
    1004             : 
    1005             : already_AddRefed<nsIURI>
    1006           0 : nsSVGEffects::GetFilterURI(nsIFrame* aFrame, const nsStyleFilter& aFilter)
    1007             : {
    1008           0 :   MOZ_ASSERT(aFrame->StyleEffects()->mFilters.Length());
    1009           0 :   MOZ_ASSERT(aFilter.GetType() == NS_STYLE_FILTER_URL);
    1010             : 
    1011           0 :   return ResolveURLUsingLocalRef(aFrame, aFilter.GetURL());
    1012             : }
    1013             : 
    1014             : already_AddRefed<nsIURI>
    1015           0 : nsSVGEffects::GetPaintURI(nsIFrame* aFrame,
    1016             :                           nsStyleSVGPaint nsStyleSVG::* aPaint)
    1017             : {
    1018           0 :   const nsStyleSVG* svgStyle = aFrame->StyleSVG();
    1019           0 :   MOZ_ASSERT((svgStyle->*aPaint).Type() ==
    1020             :              nsStyleSVGPaintType::eStyleSVGPaintType_Server);
    1021             : 
    1022             :   return ResolveURLUsingLocalRef(aFrame,
    1023           0 :                                  (svgStyle->*aPaint).GetPaintServer());
    1024             : }
    1025             : 
    1026             : already_AddRefed<nsIURI>
    1027           1 : nsSVGEffects::GetMaskURI(nsIFrame* aFrame, uint32_t aIndex)
    1028             : {
    1029           1 :   const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
    1030           1 :   MOZ_ASSERT(svgReset->mMask.mLayers.Length() > aIndex);
    1031             : 
    1032             :   mozilla::css::URLValueData* data =
    1033           1 :     svgReset->mMask.mLayers[aIndex].mImage.GetURLValue();
    1034           1 :   return ResolveURLUsingLocalRef(aFrame, data);
    1035             : }

Generated by: LCOV version 1.13