tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SVGObserverUtils.cpp (68814B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // Main header first:
      8 #include "SVGObserverUtils.h"
      9 
     10 // Keep others in (case-insensitive) order:
     11 #include "SVGFilterFrame.h"
     12 #include "SVGMarkerFrame.h"
     13 #include "SVGPaintServerFrame.h"
     14 #include "mozilla/PresShell.h"
     15 #include "mozilla/RestyleManager.h"
     16 #include "mozilla/SVGClipPathFrame.h"
     17 #include "mozilla/SVGGeometryFrame.h"
     18 #include "mozilla/SVGMaskFrame.h"
     19 #include "mozilla/SVGTextFrame.h"
     20 #include "mozilla/SVGUtils.h"
     21 #include "mozilla/css/ImageLoader.h"
     22 #include "mozilla/dom/CanvasRenderingContext2D.h"
     23 #include "mozilla/dom/ReferrerInfo.h"
     24 #include "mozilla/dom/SVGFEImageElement.h"
     25 #include "mozilla/dom/SVGGeometryElement.h"
     26 #include "mozilla/dom/SVGGraphicsElement.h"
     27 #include "mozilla/dom/SVGMPathElement.h"
     28 #include "mozilla/dom/SVGTextPathElement.h"
     29 #include "mozilla/dom/SVGUseElement.h"
     30 #include "nsCSSFrameConstructor.h"
     31 #include "nsCycleCollectionParticipant.h"
     32 #include "nsHashKeys.h"
     33 #include "nsIContent.h"
     34 #include "nsIContentInlines.h"
     35 #include "nsIReflowCallback.h"
     36 #include "nsISupportsImpl.h"
     37 #include "nsInterfaceHashtable.h"
     38 #include "nsLayoutUtils.h"
     39 #include "nsNetUtil.h"
     40 #include "nsTHashtable.h"
     41 #include "nsURIHashKey.h"
     42 
     43 using namespace mozilla::dom;
     44 
     45 namespace mozilla {
     46 
     47 /*
     48 * This class contains URL and referrer information (referrer and referrer
     49 * policy).
     50 * We use it to pass to svg system instead of nsIURI. The object brings referrer
     51 * and referrer policy so we can send correct Referer headers.
     52 */
     53 class SVGReference {
     54 public:
     55  SVGReference(const nsAString& aLocalRef, nsIURI* aBase,
     56               nsIReferrerInfo* aReferrerInfo)
     57      : mLocalRef(aLocalRef), mURI(aBase), mReferrerInfo(aReferrerInfo) {
     58    MOZ_ASSERT(nsContentUtils::IsLocalRefURL(mLocalRef));
     59  }
     60 
     61  SVGReference(const nsACString& aLocalRef, const URLExtraData& aExtraData)
     62      : mURI(aExtraData.BaseURI()), mReferrerInfo(aExtraData.ReferrerInfo()) {
     63    CopyUTF8toUTF16(aLocalRef, mLocalRef);
     64    MOZ_ASSERT(nsContentUtils::IsLocalRefURL(mLocalRef));
     65  }
     66 
     67  SVGReference(nsIURI* aURI, nsIReferrerInfo* aReferrerInfo)
     68      : mURI(aURI), mReferrerInfo(aReferrerInfo) {
     69    MOZ_ASSERT(aURI);
     70  }
     71 
     72  SVGReference(nsIURI* aURI, const URLExtraData& aExtraData)
     73      : mURI(aURI), mReferrerInfo(aExtraData.ReferrerInfo()) {
     74    MOZ_ASSERT(aURI);
     75  }
     76 
     77  NS_INLINE_DECL_REFCOUNTING(SVGReference)
     78 
     79  bool IsLocalRef() const { return !mLocalRef.IsEmpty(); }
     80  const nsAString& GetLocalRef() const { return mLocalRef; }
     81 
     82  nsIURI* GetURI() const { return mURI; }
     83  nsIReferrerInfo* GetReferrerInfo() const { return mReferrerInfo; }
     84 
     85  bool operator==(const SVGReference& aRHS) const;
     86 
     87 private:
     88  ~SVGReference() = default;
     89 
     90  nsString mLocalRef;
     91  // For local refs, this is the base URI that specified the URL. For non-local
     92  // refs, this is the whole URI. This is needed so that we can distinguish URIs
     93  // from an inner shadow tree and inherited ones.
     94  const nsCOMPtr<nsIURI> mURI;
     95  const nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
     96 };
     97 
     98 bool SVGReference::operator==(const SVGReference& aRHS) const {
     99  if (mLocalRef != aRHS.mLocalRef) {
    100    return false;
    101  }
    102  bool uriEqual = false, referrerEqual = false;
    103  mURI->Equals(aRHS.mURI, &uriEqual);
    104  mReferrerInfo->Equals(aRHS.mReferrerInfo, &referrerEqual);
    105  return uriEqual && referrerEqual;
    106 }
    107 
    108 class SVGReferenceHashKey : public PLDHashEntryHdr {
    109 public:
    110  using KeyType = const SVGReference*;
    111  using KeyTypePointer = const SVGReference*;
    112 
    113  explicit SVGReferenceHashKey(const SVGReference* aKey) noexcept : mKey(aKey) {
    114    MOZ_COUNT_CTOR(SVGReferenceHashKey);
    115  }
    116  SVGReferenceHashKey(SVGReferenceHashKey&& aToMove) noexcept
    117      : PLDHashEntryHdr(std::move(aToMove)), mKey(std::move(aToMove.mKey)) {
    118    MOZ_COUNT_CTOR(SVGReferenceHashKey);
    119  }
    120  MOZ_COUNTED_DTOR(SVGReferenceHashKey)
    121 
    122  const SVGReference* GetKey() const { return mKey; }
    123 
    124  bool KeyEquals(const SVGReference* aKey) const {
    125    if (!mKey) {
    126      return !aKey;
    127    }
    128    return *mKey == *aKey;
    129  }
    130 
    131  static const SVGReference* KeyToPointer(const SVGReference* aKey) {
    132    return aKey;
    133  }
    134 
    135  static PLDHashNumber HashKey(const SVGReference* aKey) {
    136    MOZ_ASSERT(aKey);
    137 
    138    nsAutoCString urlSpec, referrerSpec;
    139    // nsURIHashKey ignores GetSpec() failures, so we do too:
    140    (void)aKey->GetURI()->GetSpec(urlSpec);
    141    return AddToHash(
    142        HashString(aKey->GetLocalRef()), HashString(urlSpec),
    143        static_cast<ReferrerInfo*>(aKey->GetReferrerInfo())->Hash());
    144  }
    145 
    146  enum { ALLOW_MEMMOVE = true };
    147 
    148 protected:
    149  RefPtr<const SVGReference> mKey;
    150 };
    151 
    152 static already_AddRefed<SVGReference> ResolveURLUsingLocalRef(
    153    const StyleComputedUrl& aURL) {
    154  if (aURL.IsLocalRef()) {
    155    return MakeAndAddRef<SVGReference>(aURL.SpecifiedSerialization(),
    156                                       aURL.ExtraData());
    157  }
    158 
    159  nsCOMPtr<nsIURI> uri = aURL.GetURI();
    160  if (!uri) {
    161    return nullptr;
    162  }
    163 
    164  return do_AddRef(new SVGReference(uri, aURL.ExtraData()));
    165 }
    166 
    167 static already_AddRefed<SVGReference> ResolveURLUsingLocalRef(
    168    nsIContent* aContent, const nsAString& aURL) {
    169  // We want to resolve the URL against any <use> element shadow tree's source
    170  // document. We are assuming that the URL was specified directly on mFrame's
    171  // content (because this ResolveURLUsingLocalRef overload is used for href=""
    172  // attributes and not CSS URL values), so there is no need to check whether
    173  // the URL was specified / inherited from outside the shadow tree.
    174  nsIURI* base = nullptr;
    175  const Encoding* encoding = nullptr;
    176  if (SVGUseElement* use = aContent->GetContainingSVGUseShadowHost()) {
    177    base = use->GetSourceDocURI();
    178    encoding = use->GetSourceDocCharacterSet();
    179  }
    180 
    181  // There's no clear refererer policy spec about non-CSS SVG resource
    182  // references Bug 1415044 to investigate which referrer we should use
    183  nsIReferrerInfo* referrerInfo =
    184      aContent->OwnerDoc()->ReferrerInfoForInternalCSSAndSVGResources();
    185 
    186  if (nsContentUtils::IsLocalRefURL(aURL)) {
    187    return MakeAndAddRef<SVGReference>(aURL, base, referrerInfo);
    188  }
    189 
    190  if (!base) {
    191    base = aContent->OwnerDoc()->GetDocumentURI();
    192    encoding = aContent->OwnerDoc()->GetDocumentCharacterSet();
    193  }
    194 
    195  nsCOMPtr<nsIURI> uri;
    196  (void)NS_NewURI(getter_AddRefs(uri), aURL, WrapNotNull(encoding), base);
    197  if (!uri) {
    198    return nullptr;
    199  }
    200  return do_AddRef(new SVGReference(uri, referrerInfo));
    201 }
    202 
    203 class SVGFilterObserverList;
    204 
    205 /**
    206 * A class used as a member of the "observer" classes below to help them
    207 * avoid dereferencing their frame during presshell teardown when their frame
    208 * may have been destroyed (leaving their pointer to their frame dangling).
    209 *
    210 * When a presshell is torn down, the properties for each frame may not be
    211 * deleted until after the frames are destroyed.  "Observer" objects (attached
    212 * as frame properties) must therefore check whether the presshell is being
    213 * torn down before using their pointer to their frame.
    214 *
    215 * mFramePresShell may be null, but when mFrame is non-null, mFramePresShell
    216 * is guaranteed to be non-null, too.
    217 */
    218 struct SVGFrameReferenceFromProperty {
    219  explicit SVGFrameReferenceFromProperty(nsIFrame* aFrame)
    220      : mFrame(aFrame), mFramePresShell(aFrame->PresShell()) {}
    221 
    222  // Clear our reference to the frame.
    223  void Detach() {
    224    mFrame = nullptr;
    225    mFramePresShell = nullptr;
    226  }
    227 
    228  // null if the frame has become invalid
    229  nsIFrame* Get() {
    230    if (mFramePresShell && mFramePresShell->IsDestroying()) {
    231      Detach();  // mFrame is no longer valid.
    232    }
    233    return mFrame;
    234  }
    235 
    236 private:
    237  // The frame that our property is attached to (may be null).
    238  nsIFrame* mFrame;
    239  PresShell* mFramePresShell;
    240 };
    241 
    242 void SVGRenderingObserver::StartObserving() {
    243  Element* target = GetReferencedElementWithoutObserving();
    244  if (target) {
    245    target->AddMutationObserver(this);
    246  }
    247 }
    248 
    249 void SVGRenderingObserver::StopObserving() {
    250  Element* target = GetReferencedElementWithoutObserving();
    251 
    252  if (target) {
    253    target->RemoveMutationObserver(this);
    254    if (mInObserverSet) {
    255      SVGObserverUtils::RemoveRenderingObserver(target, this);
    256      mInObserverSet = false;
    257    }
    258  }
    259  NS_ASSERTION(!mInObserverSet, "still in an observer set?");
    260 }
    261 
    262 Element* SVGRenderingObserver::GetAndObserveReferencedElement() {
    263 #ifdef DEBUG
    264  DebugObserverSet();
    265 #endif
    266  Element* referencedElement = GetReferencedElementWithoutObserving();
    267  if (referencedElement && !mInObserverSet) {
    268    SVGObserverUtils::AddRenderingObserver(referencedElement, this);
    269    mInObserverSet = true;
    270  }
    271  return referencedElement;
    272 }
    273 
    274 nsIFrame* SVGRenderingObserver::GetAndObserveReferencedFrame() {
    275  Element* referencedElement = GetAndObserveReferencedElement();
    276  return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr;
    277 }
    278 
    279 nsIFrame* SVGRenderingObserver::GetAndObserveReferencedFrame(
    280    LayoutFrameType aFrameType, bool* aOK) {
    281  nsIFrame* frame = GetAndObserveReferencedFrame();
    282  if (frame) {
    283    if (frame->Type() == aFrameType) {
    284      return frame;
    285    }
    286    if (aOK) {
    287      *aOK = false;
    288    }
    289  }
    290  return nullptr;
    291 }
    292 
    293 void SVGRenderingObserver::OnNonDOMMutationRenderingChange() {
    294  OnRenderingChange();
    295 }
    296 
    297 void SVGRenderingObserver::NotifyEvictedFromRenderingObserverSet() {
    298  mInObserverSet = false;  // We've been removed from rendering-obs. set.
    299  StopObserving();         // Stop observing mutations too.
    300 }
    301 
    302 void SVGRenderingObserver::AttributeChanged(dom::Element* aElement,
    303                                            int32_t aNameSpaceID,
    304                                            nsAtom* aAttribute, AttrModType,
    305                                            const nsAttrValue* aOldValue) {
    306  if (aElement->IsInNativeAnonymousSubtree()) {
    307    // Don't observe attribute changes in native-anonymous subtrees like
    308    // scrollbars.
    309    return;
    310  }
    311 
    312  // An attribute belonging to the element that we are observing *or one of its
    313  // descendants* has changed.
    314  //
    315  // In the case of observing a gradient element, say, we want to know if any
    316  // of its 'stop' element children change, but we don't actually want to do
    317  // anything for changes to SMIL element children, for example. Maybe it's not
    318  // worth having logic to optimize for that, but in most cases it could be a
    319  // small check?
    320  //
    321  // XXXjwatt: do we really want to blindly break the link between our
    322  // observers and ourselves for all attribute changes? For non-ID changes
    323  // surely that is unnecessary.
    324 
    325  OnRenderingChange();
    326 }
    327 
    328 void SVGRenderingObserver::ContentAppended(nsIContent* aFirstNewContent,
    329                                           const ContentAppendInfo&) {
    330  OnRenderingChange();
    331 }
    332 
    333 void SVGRenderingObserver::ContentInserted(nsIContent* aChild,
    334                                           const ContentInsertInfo&) {
    335  OnRenderingChange();
    336 }
    337 
    338 void SVGRenderingObserver::ContentWillBeRemoved(
    339    nsIContent* aChild, const ContentRemoveInfo& aInfo) {
    340  if (aInfo.mBatchRemovalState && !aInfo.mBatchRemovalState->mIsFirst) {
    341    return;
    342  }
    343  OnRenderingChange();
    344 }
    345 
    346 /**
    347 * SVG elements reference supporting resources by element ID. We need to
    348 * track when those resources change and when the document changes in ways
    349 * that affect which element is referenced by a given ID (e.g., when
    350 * element IDs change). The code here is responsible for that.
    351 *
    352 * When a frame references a supporting resource, we create a property
    353 * object derived from SVGIDRenderingObserver to manage the relationship. The
    354 * property object is attached to the referencing frame.
    355 */
    356 class SVGIDRenderingObserver : public SVGRenderingObserver {
    357 public:
    358  // Callback for checking if the element being observed is valid for this
    359  // observer. Note that this may be called during construction, before the
    360  // deriving class is fully constructed.
    361  using TargetIsValidCallback = bool (*)(const Element&);
    362  SVGIDRenderingObserver(
    363      SVGReference* aReference, Element* aObservingElement,
    364      bool aReferenceImage,
    365      uint32_t aCallbacks = kAttributeChanged | kContentAppended |
    366                            kContentInserted | kContentWillBeRemoved,
    367      TargetIsValidCallback aTargetIsValidCallback = nullptr);
    368 
    369  void Traverse(nsCycleCollectionTraversalCallback* aCB);
    370 
    371 protected:
    372  virtual ~SVGIDRenderingObserver() {
    373    // This needs to call our GetReferencedElementWithoutObserving override,
    374    // so must be called here rather than in our base class's dtor.
    375    StopObserving();
    376  }
    377 
    378  void TargetChanged() {
    379    mTargetIsValid = ([this] {
    380      Element* observed = mObservedElementTracker.get();
    381      if (!observed) {
    382        return false;
    383      }
    384      // If the content is observing an ancestor, then return the target is not
    385      // valid.
    386      //
    387      // TODO(emilio): Should we allow content observing its own descendants?
    388      // That seems potentially-bad as well.
    389      if (observed->OwnerDoc() == mObservingElement->OwnerDoc() &&
    390          nsContentUtils::ContentIsHostIncludingDescendantOf(mObservingElement,
    391                                                             observed)) {
    392        return false;
    393      }
    394      if (mTargetIsValidCallback) {
    395        return mTargetIsValidCallback(*observed);
    396      }
    397      return true;
    398    }());
    399  }
    400 
    401  Element* GetReferencedElementWithoutObserving() final {
    402    return mTargetIsValid ? mObservedElementTracker.get() : nullptr;
    403  }
    404 
    405  void OnRenderingChange() override;
    406 
    407  /**
    408   * Helper that provides a reference to the element with the ID that our
    409   * observer wants to observe, and that will invalidate our observer if the
    410   * element that that ID identifies changes to a different element (or none).
    411   */
    412  class ElementTracker final : public IDTracker {
    413   public:
    414    explicit ElementTracker(SVGIDRenderingObserver* aOwningObserver)
    415        : mOwningObserver(aOwningObserver) {}
    416 
    417   protected:
    418    void ElementChanged(Element* aFrom, Element* aTo) override {
    419      // Call OnRenderingChange() before the target changes, so that
    420      // mIsTargetValid reflects the right state.
    421      mOwningObserver->OnRenderingChange();
    422      mOwningObserver->StopObserving();
    423      IDTracker::ElementChanged(aFrom, aTo);
    424      mOwningObserver->TargetChanged();
    425      mOwningObserver->StartObserving();
    426      // And same after the target changes, for the same reason.
    427      mOwningObserver->OnRenderingChange();
    428    }
    429    /**
    430     * Override IsPersistent because we want to keep tracking the element
    431     * for the ID even when it changes.
    432     */
    433    bool IsPersistent() override { return true; }
    434 
    435   private:
    436    SVGIDRenderingObserver* mOwningObserver;
    437  };
    438 
    439  ElementTracker mObservedElementTracker;
    440  RefPtr<Element> mObservingElement;
    441  bool mTargetIsValid = false;
    442  TargetIsValidCallback mTargetIsValidCallback;
    443 };
    444 
    445 /**
    446 * Note that in the current setup there are two separate observer lists.
    447 *
    448 * In SVGIDRenderingObserver's ctor, the new object adds itself to the
    449 * mutation observer list maintained by the referenced element. In this way the
    450 * SVGIDRenderingObserver is notified if there are any attribute or content
    451 * tree changes to the element or any of its *descendants*.
    452 *
    453 * In SVGIDRenderingObserver::GetAndObserveReferencedElement() the
    454 * SVGIDRenderingObserver object also adds itself to an
    455 * SVGRenderingObserverSet object belonging to the referenced
    456 * element.
    457 *
    458 * XXX: it would be nice to have a clear and concise executive summary of the
    459 * benefits/necessity of maintaining a second observer list.
    460 */
    461 SVGIDRenderingObserver::SVGIDRenderingObserver(
    462    SVGReference* aReference, Element* aObservingElement, bool aReferenceImage,
    463    uint32_t aCallbacks, TargetIsValidCallback aTargetIsValidCallback)
    464    : SVGRenderingObserver(aCallbacks),
    465      mObservedElementTracker(this),
    466      mObservingElement(aObservingElement),
    467      mTargetIsValidCallback(aTargetIsValidCallback) {
    468  // Start watching the target element
    469  if (aReference) {
    470    if (aReference->IsLocalRef()) {
    471      mObservedElementTracker.ResetToLocalFragmentID(
    472          *aObservingElement, aReference->GetLocalRef(), aReference->GetURI(),
    473          aReference->GetReferrerInfo(), aReferenceImage);
    474    } else {
    475      mObservedElementTracker.ResetToURIWithFragmentID(
    476          *aObservingElement, aReference->GetURI(),
    477          aReference->GetReferrerInfo(), aReferenceImage);
    478    }
    479  } else {
    480    mObservedElementTracker.Unlink();
    481  }
    482 
    483  TargetChanged();
    484  StartObserving();
    485 }
    486 
    487 void SVGIDRenderingObserver::Traverse(nsCycleCollectionTraversalCallback* aCB) {
    488  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mObservingElement");
    489  aCB->NoteXPCOMChild(mObservingElement);
    490  mObservedElementTracker.Traverse(aCB);
    491 }
    492 
    493 void SVGIDRenderingObserver::OnRenderingChange() {
    494  if (mObservedElementTracker.get() && mInObserverSet) {
    495    SVGObserverUtils::RemoveRenderingObserver(mObservedElementTracker.get(),
    496                                              this);
    497    mInObserverSet = false;
    498  }
    499 }
    500 
    501 // Convenience function to return aFrame->GetContent() as an Element* if the
    502 // content pointer is non-null (or just return nullptr otherwise).
    503 // (AsElement itself isn't callable on null pointers.)
    504 static Element* GetFrameContentAsElement(nsIFrame* aFrame) {
    505  MOZ_ASSERT(aFrame, "Expecting a non-null frame");
    506  auto* content = aFrame->GetContent();
    507  if (content) {
    508    return content->AsElement();
    509  }
    510  return nullptr;
    511 }
    512 
    513 class SVGRenderingObserverProperty : public SVGIDRenderingObserver {
    514 public:
    515  NS_DECL_ISUPPORTS
    516 
    517  SVGRenderingObserverProperty(
    518      SVGReference* aReference, nsIFrame* aFrame, bool aReferenceImage,
    519      uint32_t aCallbacks = kAttributeChanged | kContentAppended |
    520                            kContentInserted | kContentWillBeRemoved,
    521      TargetIsValidCallback aTargetIsValidCallback = nullptr)
    522      : SVGIDRenderingObserver(aReference, GetFrameContentAsElement(aFrame),
    523                               aReferenceImage, aCallbacks,
    524                               aTargetIsValidCallback),
    525        mFrameReference(aFrame) {}
    526 
    527 protected:
    528  virtual ~SVGRenderingObserverProperty() = default;  // non-public
    529 
    530  void OnRenderingChange() override;
    531 
    532  SVGFrameReferenceFromProperty mFrameReference;
    533 };
    534 
    535 NS_IMPL_ISUPPORTS(SVGRenderingObserverProperty, nsIMutationObserver)
    536 
    537 void SVGRenderingObserverProperty::OnRenderingChange() {
    538  SVGIDRenderingObserver::OnRenderingChange();
    539 
    540  if (!mTargetIsValid) {
    541    return;
    542  }
    543 
    544  nsIFrame* frame = mFrameReference.Get();
    545 
    546  if (frame && frame->HasAllStateBits(NS_FRAME_SVG_LAYOUT)) {
    547    // We need to notify anything that is observing the referencing frame or
    548    // any of its ancestors that the referencing frame has been invalidated.
    549    // Since walking the parent chain checking for observers is expensive we
    550    // do that using a change hint (multiple change hints of the same type are
    551    // coalesced).
    552    nsLayoutUtils::PostRestyleEvent(frame->GetContent()->AsElement(),
    553                                    RestyleHint{0},
    554                                    nsChangeHint_InvalidateRenderingObservers);
    555  }
    556 }
    557 
    558 static bool IsSVGGeometryElement(const Element& aObserved) {
    559  return aObserved.IsSVGGeometryElement();
    560 }
    561 
    562 class SVGTextPathObserver final : public SVGRenderingObserverProperty {
    563 public:
    564  SVGTextPathObserver(SVGReference* aReference, nsIFrame* aFrame,
    565                      bool aReferenceImage)
    566      : SVGRenderingObserverProperty(aReference, aFrame, aReferenceImage,
    567                                     kAttributeChanged, IsSVGGeometryElement) {}
    568 
    569 protected:
    570  void OnRenderingChange() override;
    571 };
    572 
    573 void SVGTextPathObserver::OnRenderingChange() {
    574  SVGRenderingObserverProperty::OnRenderingChange();
    575 
    576  if (!mTargetIsValid) {
    577    return;
    578  }
    579 
    580  nsIFrame* frame = mFrameReference.Get();
    581  if (!frame) {
    582    return;
    583  }
    584 
    585  MOZ_ASSERT(frame->IsSVGFrame() || frame->IsInSVGTextSubtree(),
    586             "SVG frame expected");
    587 
    588  MOZ_ASSERT(frame->GetContent()->IsSVGElement(nsGkAtoms::textPath),
    589             "expected frame for a <textPath> element");
    590 
    591  auto* text = static_cast<SVGTextFrame*>(
    592      nsLayoutUtils::GetClosestFrameOfType(frame, LayoutFrameType::SVGText));
    593  MOZ_ASSERT(text, "expected to find an ancestor SVGTextFrame");
    594  if (text) {
    595    text->AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
    596 
    597    if (SVGUtils::AnyOuterSVGIsCallingReflowSVG(text)) {
    598      text->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
    599      if (text->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
    600        text->ReflowSVGNonDisplayText();
    601      } else {
    602        text->ReflowSVG();
    603      }
    604    } else {
    605      text->ScheduleReflowSVG();
    606    }
    607  }
    608 }
    609 
    610 static bool IsSVGGraphicsElement(const Element& aObserved) {
    611  return aObserved.IsSVGGraphicsElement();
    612 }
    613 
    614 class SVGFEImageObserver final : public SVGIDRenderingObserver {
    615 public:
    616  NS_DECL_ISUPPORTS
    617 
    618  SVGFEImageObserver(SVGReference* aReference, SVGFEImageElement* aElement)
    619      : SVGIDRenderingObserver(aReference, aElement,
    620                               /* aReferenceImage = */ false,
    621                               kAttributeChanged | kContentAppended |
    622                                   kContentInserted | kContentWillBeRemoved,
    623                               IsSVGGraphicsElement) {}
    624 
    625 protected:
    626  virtual ~SVGFEImageObserver() = default;  // non-public
    627 
    628  void OnRenderingChange() override;
    629 };
    630 
    631 NS_IMPL_ISUPPORTS(SVGFEImageObserver, nsIMutationObserver)
    632 
    633 void SVGFEImageObserver::OnRenderingChange() {
    634  SVGIDRenderingObserver::OnRenderingChange();
    635 
    636  if (!mTargetIsValid) {
    637    return;
    638  }
    639  auto* element = static_cast<SVGFEImageElement*>(mObservingElement.get());
    640  element->NotifyImageContentChanged();
    641 }
    642 
    643 class SVGMPathObserver final : public SVGIDRenderingObserver {
    644 public:
    645  NS_DECL_ISUPPORTS
    646 
    647  SVGMPathObserver(SVGReference* aReference, SVGMPathElement* aElement)
    648      : SVGIDRenderingObserver(aReference, aElement,
    649                               /* aReferenceImage = */ false, kAttributeChanged,
    650                               IsSVGGeometryElement) {}
    651 
    652 protected:
    653  virtual ~SVGMPathObserver() = default;  // non-public
    654 
    655  void OnRenderingChange() override;
    656 };
    657 
    658 NS_IMPL_ISUPPORTS(SVGMPathObserver, nsIMutationObserver)
    659 
    660 void SVGMPathObserver::OnRenderingChange() {
    661  SVGIDRenderingObserver::OnRenderingChange();
    662 
    663  if (!mTargetIsValid) {
    664    return;
    665  }
    666 
    667  auto* element = static_cast<SVGMPathElement*>(mObservingElement.get());
    668  element->NotifyParentOfMpathChange();
    669 }
    670 
    671 class SVGMarkerObserver final : public SVGRenderingObserverProperty {
    672 public:
    673  SVGMarkerObserver(SVGReference* aReference, nsIFrame* aFrame,
    674                    bool aReferenceImage)
    675      : SVGRenderingObserverProperty(aReference, aFrame, aReferenceImage,
    676                                     kAttributeChanged | kContentAppended |
    677                                         kContentInserted |
    678                                         kContentWillBeRemoved) {}
    679 
    680 protected:
    681  void OnRenderingChange() override;
    682 };
    683 
    684 void SVGMarkerObserver::OnRenderingChange() {
    685  SVGRenderingObserverProperty::OnRenderingChange();
    686 
    687  nsIFrame* frame = mFrameReference.Get();
    688  if (!frame) {
    689    return;
    690  }
    691 
    692  MOZ_ASSERT(frame->IsSVGFrame(), "SVG frame expected");
    693 
    694  // Don't need to request ReflowFrame if we're being reflowed.
    695  // Because mRect for SVG frames includes the bounds of any markers
    696  // (see the comment for nsIFrame::GetRect), the referencing frame must be
    697  // reflowed for any marker changes.
    698  if (!SVGUtils::OuterSVGIsCallingReflowSVG(frame)) {
    699    // XXXjwatt: We need to unify SVG into standard reflow so we can just use
    700    // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
    701    // XXXSDL KILL THIS!!!
    702    SVGUtils::ScheduleReflowSVG(frame);
    703  }
    704  frame->PresContext()->RestyleManager()->PostRestyleEvent(
    705      frame->GetContent()->AsElement(), RestyleHint{0},
    706      nsChangeHint_RepaintFrame);
    707 }
    708 
    709 class SVGPaintingProperty : public SVGRenderingObserverProperty {
    710 public:
    711  SVGPaintingProperty(SVGReference* aReference, nsIFrame* aFrame,
    712                      bool aReferenceImage)
    713      : SVGRenderingObserverProperty(aReference, aFrame, aReferenceImage) {}
    714 
    715 protected:
    716  void OnRenderingChange() override;
    717 };
    718 
    719 void SVGPaintingProperty::OnRenderingChange() {
    720  SVGRenderingObserverProperty::OnRenderingChange();
    721 
    722  nsIFrame* frame = mFrameReference.Get();
    723  if (!frame) {
    724    return;
    725  }
    726 
    727  if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
    728    frame->InvalidateFrameSubtree();
    729  } else {
    730    for (nsIFrame* f = frame; f;
    731         f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
    732      f->InvalidateFrame();
    733    }
    734  }
    735 }
    736 
    737 // Observer for -moz-element(#element). Note that the observed element does not
    738 // have to be an SVG element.
    739 class SVGMozElementObserver final : public SVGPaintingProperty {
    740 public:
    741  SVGMozElementObserver(SVGReference* aReference, nsIFrame* aFrame)
    742      : SVGPaintingProperty(aReference, aFrame, /* aReferenceImage = */ true) {}
    743 
    744  // We only return true here because GetAndObserveBackgroundImage uses us
    745  // to implement observing of arbitrary elements (including HTML elements)
    746  // that may require us to repaint if the referenced element is reflowed.
    747  // Bug 1496065 has been filed to remove that support though.
    748  bool ObservesReflow() override { return true; }
    749 };
    750 
    751 /**
    752 * For content with `background-clip: text`.
    753 *
    754 * This observer is unusual in that the observing frame and observed frame are
    755 * the same frame.  This is because the observing frame is observing for reflow
    756 * of its descendant text nodes, since such reflows may not result in the
    757 * frame's nsDisplayBackground changing.  In other words, Display List Based
    758 * Invalidation may not invalidate the frame's background, so we need this
    759 * observer to make sure that happens.
    760 *
    761 * XXX: It's questionable whether we should even be [ab]using the SVG observer
    762 * mechanism for `background-clip:text`.  Since we know that the observed frame
    763 * is the frame we need to invalidate, we could just check the computed style
    764 * in the (one) place where we pass INVALIDATE_REFLOW and invalidate there...
    765 */
    766 class BackgroundClipRenderingObserver : public SVGRenderingObserver {
    767 public:
    768  explicit BackgroundClipRenderingObserver(nsIFrame* aFrame) : mFrame(aFrame) {}
    769 
    770  NS_DECL_ISUPPORTS
    771 
    772 private:
    773  // We do not call StopObserving() since the observing and observed element
    774  // are the same element (and because we could crash - see bug 1556441).
    775  virtual ~BackgroundClipRenderingObserver() = default;
    776 
    777  Element* GetReferencedElementWithoutObserving() final {
    778    return mFrame->GetContent()->AsElement();
    779  }
    780 
    781  void OnRenderingChange() final;
    782 
    783  /**
    784   * Observing for mutations is not enough.  A new font loading and applying
    785   * to the text content could cause it to reflow, and we need to invalidate
    786   * for that.
    787   */
    788  bool ObservesReflow() final { return true; }
    789 
    790  // The observer and observee!
    791  nsIFrame* mFrame;
    792 };
    793 
    794 NS_IMPL_ISUPPORTS(BackgroundClipRenderingObserver, nsIMutationObserver)
    795 
    796 void BackgroundClipRenderingObserver::OnRenderingChange() {
    797  for (nsIFrame* f = mFrame; f;
    798       f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
    799    f->InvalidateFrame();
    800  }
    801 }
    802 
    803 static bool IsSVGFilterElement(const Element& aObserved) {
    804  return aObserved.IsSVGElement(nsGkAtoms::filter);
    805 }
    806 
    807 /**
    808 * In a filter chain, there can be multiple SVG reference filters.
    809 * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
    810 *
    811 * This class keeps track of one SVG reference filter in a filter chain.
    812 * e.g. url(#svg-filter-1)
    813 *
    814 * It fires invalidations when the SVG filter element's id changes or when
    815 * the SVG filter element's content changes.
    816 *
    817 * The SVGFilterObserverList class manages a list of SVGFilterObservers.
    818 */
    819 class SVGFilterObserver final : public SVGIDRenderingObserver {
    820 public:
    821  SVGFilterObserver(SVGReference* aReference, Element* aObservingElement,
    822                    SVGFilterObserverList* aFilterChainObserver)
    823      : SVGIDRenderingObserver(aReference, aObservingElement, false,
    824                               kAttributeChanged | kContentAppended |
    825                                   kContentInserted | kContentWillBeRemoved,
    826                               IsSVGFilterElement),
    827        mFilterObserverList(aFilterChainObserver) {}
    828 
    829  void DetachFromChainObserver() { mFilterObserverList = nullptr; }
    830 
    831  /**
    832   * @return the filter frame, or null if there is no filter frame
    833   */
    834  SVGFilterFrame* GetAndObserveFilterFrame();
    835 
    836  // nsISupports
    837  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    838  NS_DECL_CYCLE_COLLECTION_CLASS(SVGFilterObserver)
    839 
    840  // SVGIDRenderingObserver
    841  void OnRenderingChange() override;
    842 
    843 protected:
    844  virtual ~SVGFilterObserver() = default;  // non-public
    845 
    846  SVGFilterObserverList* mFilterObserverList;
    847 };
    848 
    849 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGFilterObserver)
    850 NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGFilterObserver)
    851 
    852 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGFilterObserver)
    853  NS_INTERFACE_MAP_ENTRY(nsISupports)
    854  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
    855 NS_INTERFACE_MAP_END
    856 
    857 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGFilterObserver)
    858 
    859 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SVGFilterObserver)
    860  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservedElementTracker)
    861  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservingElement)
    862 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    863 
    864 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SVGFilterObserver)
    865  tmp->StopObserving();
    866  NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservedElementTracker);
    867  NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservingElement)
    868 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    869 
    870 SVGFilterFrame* SVGFilterObserver::GetAndObserveFilterFrame() {
    871  return static_cast<SVGFilterFrame*>(
    872      GetAndObserveReferencedFrame(LayoutFrameType::SVGFilter, nullptr));
    873 }
    874 
    875 NS_IMPL_CYCLE_COLLECTION(ISVGFilterObserverList)
    876 
    877 NS_IMPL_CYCLE_COLLECTING_ADDREF(ISVGFilterObserverList)
    878 NS_IMPL_CYCLE_COLLECTING_RELEASE(ISVGFilterObserverList)
    879 
    880 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ISVGFilterObserverList)
    881  NS_INTERFACE_MAP_ENTRY(nsISupports)
    882 NS_INTERFACE_MAP_END
    883 
    884 /**
    885 * This class manages a list of SVGFilterObservers, which correspond to
    886 * reference to SVG filters in a list of filters in a given 'filter' property.
    887 * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
    888 *
    889 * In the above example, the SVGFilterObserverList will manage two
    890 * SVGFilterObservers, one for each of the references to SVG filters.  CSS
    891 * filters like "blur(10px)" don't reference filter elements, so they don't
    892 * need an SVGFilterObserver.  The style system invalidates changes to CSS
    893 * filters.
    894 *
    895 * FIXME(emilio): Why do we need this as opposed to the individual observers we
    896 * create in the constructor?
    897 */
    898 class SVGFilterObserverList : public ISVGFilterObserverList {
    899 public:
    900  SVGFilterObserverList(Span<const StyleFilter> aFilters,
    901                        Element* aFilteredElement,
    902                        nsIFrame* aFilteredFrame = nullptr);
    903 
    904  const nsTArray<RefPtr<SVGFilterObserver>>& GetObservers() const override {
    905    return mObservers;
    906  }
    907 
    908  // nsISupports
    909  NS_DECL_ISUPPORTS_INHERITED
    910  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGFilterObserverList,
    911                                           ISVGFilterObserverList)
    912 
    913  virtual void OnRenderingChange(Element* aObservingElement) = 0;
    914 
    915 protected:
    916  virtual ~SVGFilterObserverList();
    917 
    918  void DetachObservers() {
    919    for (auto& observer : mObservers) {
    920      observer->DetachFromChainObserver();
    921    }
    922  }
    923 
    924  nsTArray<RefPtr<SVGFilterObserver>> mObservers;
    925 };
    926 
    927 void SVGFilterObserver::OnRenderingChange() {
    928  SVGIDRenderingObserver::OnRenderingChange();
    929 
    930  if (!mTargetIsValid) {
    931    return;
    932  }
    933 
    934  if (mFilterObserverList) {
    935    mFilterObserverList->OnRenderingChange(mObservingElement);
    936  }
    937 }
    938 
    939 NS_IMPL_ADDREF_INHERITED(SVGFilterObserverList, ISVGFilterObserverList)
    940 NS_IMPL_RELEASE_INHERITED(SVGFilterObserverList, ISVGFilterObserverList)
    941 
    942 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGFilterObserverList)
    943 
    944 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGFilterObserverList,
    945                                                  ISVGFilterObserverList)
    946  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
    947 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    948 
    949 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGFilterObserverList,
    950                                                ISVGFilterObserverList)
    951  tmp->DetachObservers();
    952  NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers)
    953 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    954 
    955 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGFilterObserverList)
    956  NS_INTERFACE_MAP_ENTRY(ISVGFilterObserverList)
    957  NS_INTERFACE_MAP_ENTRY(nsISupports)
    958 NS_INTERFACE_MAP_END
    959 
    960 SVGFilterObserverList::SVGFilterObserverList(Span<const StyleFilter> aFilters,
    961                                             Element* aFilteredElement,
    962                                             nsIFrame* aFilteredFrame) {
    963  for (const auto& filter : aFilters) {
    964    if (!filter.IsUrl()) {
    965      continue;
    966    }
    967 
    968    const auto& url = filter.AsUrl();
    969 
    970    // aFilteredFrame can be null if this filter belongs to a
    971    // CanvasRenderingContext2D.
    972    RefPtr<SVGReference> filterURL = ResolveURLUsingLocalRef(url);
    973    auto observer =
    974        MakeRefPtr<SVGFilterObserver>(filterURL, aFilteredElement, this);
    975    mObservers.AppendElement(std::move(observer));
    976  }
    977 }
    978 
    979 SVGFilterObserverList::~SVGFilterObserverList() { DetachObservers(); }
    980 
    981 class SVGFilterObserverListForCSSProp final : public SVGFilterObserverList {
    982 public:
    983  SVGFilterObserverListForCSSProp(Span<const StyleFilter> aFilters,
    984                                  nsIFrame* aFilteredFrame)
    985      : SVGFilterObserverList(aFilters,
    986                              GetFrameContentAsElement(aFilteredFrame),
    987                              aFilteredFrame) {}
    988 
    989 protected:
    990  void OnRenderingChange(Element* aObservingElement) override;
    991 };
    992 
    993 void SVGFilterObserverListForCSSProp::OnRenderingChange(
    994    Element* aObservingElement) {
    995  nsIFrame* frame = aObservingElement->GetPrimaryFrame();
    996  if (!frame) {
    997    return;
    998  }
    999  // Repaint asynchronously in case the filter frame is being torn down
   1000  auto changeHint = nsChangeHint_RepaintFrame;
   1001 
   1002  // Since we don't call SVGRenderingObserverProperty::
   1003  // OnRenderingChange, we have to add this bit ourselves.
   1004  if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
   1005    // Changes should propagate out to things that might be observing
   1006    // the referencing frame or its ancestors.
   1007    changeHint |= nsChangeHint_InvalidateRenderingObservers;
   1008  }
   1009 
   1010  // Don't need to request UpdateOverflow if we're being reflowed.
   1011  if (!frame->HasAnyStateBits(NS_FRAME_IN_REFLOW)) {
   1012    changeHint |= nsChangeHint_UpdateOverflow;
   1013  }
   1014  frame->PresContext()->RestyleManager()->PostRestyleEvent(
   1015      aObservingElement, RestyleHint{0}, changeHint);
   1016 }
   1017 
   1018 class SVGFilterObserverListForCanvasContext final
   1019    : public SVGFilterObserverList {
   1020 public:
   1021  SVGFilterObserverListForCanvasContext(CanvasRenderingContext2D* aContext,
   1022                                        Element* aCanvasElement,
   1023                                        Span<const StyleFilter> aFilters)
   1024      : SVGFilterObserverList(aFilters, aCanvasElement), mContext(aContext) {}
   1025 
   1026  void OnRenderingChange(Element* aObservingElement) override;
   1027  void Detach() override { mContext = nullptr; }
   1028 
   1029 private:
   1030  CanvasRenderingContext2D* mContext;
   1031 };
   1032 
   1033 void SVGFilterObserverListForCanvasContext::OnRenderingChange(
   1034    Element* aObservingElement) {
   1035  if (!mContext) {
   1036    NS_WARNING(
   1037        "GFX: This should never be called without a context, except during "
   1038        "cycle collection (when Detach has been called)");
   1039    return;
   1040  }
   1041  // Refresh the cached FilterDescription in mContext->CurrentState().filter.
   1042  // If this filter is not at the top of the state stack, we'll refresh the
   1043  // wrong filter, but that's ok, because we'll refresh the right filter
   1044  // when we pop the state stack in CanvasRenderingContext2D::Restore().
   1045  //
   1046  // We don't need to flush, we're called by layout.
   1047  RefPtr<CanvasRenderingContext2D> kungFuDeathGrip(mContext);
   1048  kungFuDeathGrip->UpdateFilter(/* aFlushIfNeeded = */ false);
   1049 }
   1050 
   1051 class SVGMaskObserverList final : public nsISupports {
   1052 public:
   1053  explicit SVGMaskObserverList(nsIFrame* aFrame);
   1054 
   1055  // nsISupports
   1056  NS_DECL_ISUPPORTS
   1057 
   1058  const nsTArray<RefPtr<SVGPaintingProperty>>& GetObservers() const {
   1059    return mProperties;
   1060  }
   1061 
   1062  void ResolveImage(uint32_t aIndex);
   1063 
   1064 private:
   1065  virtual ~SVGMaskObserverList() = default;  // non-public
   1066  nsTArray<RefPtr<SVGPaintingProperty>> mProperties;
   1067  nsIFrame* mFrame;
   1068 };
   1069 
   1070 NS_IMPL_ISUPPORTS(SVGMaskObserverList, nsISupports)
   1071 
   1072 SVGMaskObserverList::SVGMaskObserverList(nsIFrame* aFrame) : mFrame(aFrame) {
   1073  const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
   1074 
   1075  for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
   1076    const StyleComputedUrl* data =
   1077        svgReset->mMask.mLayers[i].mImage.GetImageRequestURLValue();
   1078    RefPtr<SVGReference> maskUri;
   1079    if (data) {
   1080      maskUri = ResolveURLUsingLocalRef(*data);
   1081    }
   1082 
   1083    bool hasRef = false;
   1084    if (maskUri) {
   1085      if (maskUri->IsLocalRef()) {
   1086        hasRef = true;
   1087      } else {
   1088        maskUri->GetURI()->GetHasRef(&hasRef);
   1089      }
   1090    }
   1091 
   1092    // According to maskUri, SVGPaintingProperty's ctor may trigger an external
   1093    // SVG resource download, so we should pass maskUri in only if maskUri has a
   1094    // chance pointing to an SVG mask resource.
   1095    //
   1096    // And, an URL may refer to an SVG mask resource if it consists of a
   1097    // fragment.
   1098    auto prop = MakeRefPtr<SVGPaintingProperty>(
   1099        hasRef ? maskUri.get() : nullptr, aFrame, false);
   1100    mProperties.AppendElement(std::move(prop));
   1101  }
   1102 }
   1103 
   1104 void SVGMaskObserverList::ResolveImage(uint32_t aIndex) {
   1105  const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset();
   1106  MOZ_ASSERT(aIndex < svgReset->mMask.mImageCount);
   1107 
   1108  const auto& image = svgReset->mMask.mLayers[aIndex].mImage;
   1109  if (image.IsResolved()) {
   1110    return;
   1111  }
   1112  MOZ_ASSERT(image.IsImageRequestType());
   1113  Document* doc = mFrame->PresContext()->Document();
   1114  const_cast<StyleImage&>(image).ResolveImage(*doc, nullptr);
   1115  if (imgRequestProxy* req = image.GetImageRequest()) {
   1116    // FIXME(emilio): What disassociates this request?
   1117    doc->EnsureStyleImageLoader().AssociateRequestToFrame(req, mFrame);
   1118  }
   1119 }
   1120 
   1121 /**
   1122 * Used for gradient-to-gradient, pattern-to-pattern and filter-to-filter
   1123 * references to "template" elements (specified via the 'href' attributes).
   1124 */
   1125 class SVGTemplateElementObserver : public SVGIDRenderingObserver {
   1126 public:
   1127  NS_DECL_ISUPPORTS
   1128 
   1129  SVGTemplateElementObserver(SVGReference* aReference, nsIFrame* aFrame,
   1130                             bool aReferenceImage)
   1131      : SVGIDRenderingObserver(aReference, GetFrameContentAsElement(aFrame),
   1132                               aReferenceImage,
   1133                               kAttributeChanged | kContentAppended |
   1134                                   kContentInserted | kContentWillBeRemoved),
   1135        mFrameReference(aFrame) {}
   1136 
   1137 protected:
   1138  virtual ~SVGTemplateElementObserver() = default;  // non-public
   1139 
   1140  void OnRenderingChange() override;
   1141 
   1142  SVGFrameReferenceFromProperty mFrameReference;
   1143 };
   1144 
   1145 NS_IMPL_ISUPPORTS(SVGTemplateElementObserver, nsIMutationObserver)
   1146 
   1147 void SVGTemplateElementObserver::OnRenderingChange() {
   1148  SVGIDRenderingObserver::OnRenderingChange();
   1149 
   1150  if (nsIFrame* frame = mFrameReference.Get()) {
   1151    SVGObserverUtils::InvalidateRenderingObservers(frame);
   1152  }
   1153 }
   1154 
   1155 /**
   1156 * An instance of this class is stored on an observed frame (as a frame
   1157 * property) whenever the frame has active rendering observers.  It is used to
   1158 * store pointers to the SVGRenderingObserver instances belonging to any
   1159 * observing frames, allowing invalidations from the observed frame to be sent
   1160 * to all observing frames.
   1161 *
   1162 * SVGRenderingObserver instances that are added are not strongly referenced,
   1163 * so they must remove themselves before they die.
   1164 *
   1165 * This class is "single-shot", which is to say that when something about the
   1166 * observed element changes, InvalidateAll() clears our hashtable of
   1167 * SVGRenderingObservers.  SVGRenderingObserver objects will be added back
   1168 * again if/when the observing frame looks up our observed frame to use it.
   1169 *
   1170 * XXXjwatt: is this the best thing to do nowadays?  Back when that mechanism
   1171 * landed in bug 330498 we had two pass, recursive invalidation up the frame
   1172 * tree, and I think reference loops were a problem.  Nowadays maybe a flag
   1173 * on the SVGRenderingObserver objects to coalesce invalidations may work
   1174 * better?
   1175 *
   1176 * InvalidateAll must be called before this object is destroyed, i.e.
   1177 * before the referenced frame is destroyed. This should normally happen
   1178 * via SVGContainerFrame::RemoveFrame, since only frames in the frame
   1179 * tree should be referenced.
   1180 */
   1181 class SVGRenderingObserverSet {
   1182 public:
   1183  SVGRenderingObserverSet() : mObservers(4) {
   1184    MOZ_COUNT_CTOR(SVGRenderingObserverSet);
   1185  }
   1186 
   1187  ~SVGRenderingObserverSet() { MOZ_COUNT_DTOR(SVGRenderingObserverSet); }
   1188 
   1189  void Add(SVGRenderingObserver* aObserver) { mObservers.Insert(aObserver); }
   1190  void Remove(SVGRenderingObserver* aObserver) { mObservers.Remove(aObserver); }
   1191 #ifdef DEBUG
   1192  bool Contains(SVGRenderingObserver* aObserver) {
   1193    return mObservers.Contains(aObserver);
   1194  }
   1195 #endif
   1196  bool IsEmpty() { return mObservers.IsEmpty(); }
   1197 
   1198  /**
   1199   * Drop all our observers, and notify them that we have changed and dropped
   1200   * our reference to them.
   1201   */
   1202  void InvalidateAll();
   1203 
   1204  /**
   1205   * Drop all observers that observe reflow, and notify them that we have
   1206   * changed and dropped our reference to them.
   1207   */
   1208  void InvalidateAllForReflow();
   1209 
   1210  /**
   1211   * Drop all our observers, and notify them that we have dropped our reference
   1212   * to them.
   1213   */
   1214  void RemoveAll();
   1215 
   1216 private:
   1217  nsTHashSet<SVGRenderingObserver*> mObservers;
   1218 };
   1219 
   1220 void SVGRenderingObserverSet::InvalidateAll() {
   1221  if (mObservers.IsEmpty()) {
   1222    return;
   1223  }
   1224 
   1225  const auto observers = std::move(mObservers);
   1226 
   1227  // We've moved all the observers from mObservers, effectively
   1228  // evicting them so we need to notify all observers of eviction
   1229  // before we process any rendering changes. In short, don't
   1230  // try to merge these loops.
   1231  for (const auto& observer : observers) {
   1232    observer->NotifyEvictedFromRenderingObserverSet();
   1233  }
   1234  for (const auto& observer : observers) {
   1235    observer->OnNonDOMMutationRenderingChange();
   1236  }
   1237 }
   1238 
   1239 void SVGRenderingObserverSet::InvalidateAllForReflow() {
   1240  if (mObservers.IsEmpty()) {
   1241    return;
   1242  }
   1243 
   1244  AutoTArray<SVGRenderingObserver*, 10> observers;
   1245 
   1246  for (auto it = mObservers.cbegin(), end = mObservers.cend(); it != end;
   1247       ++it) {
   1248    SVGRenderingObserver* obs = *it;
   1249    if (obs->ObservesReflow()) {
   1250      observers.AppendElement(obs);
   1251      mObservers.Remove(it);
   1252      obs->NotifyEvictedFromRenderingObserverSet();
   1253    }
   1254  }
   1255 
   1256  for (const auto& observer : observers) {
   1257    observer->OnNonDOMMutationRenderingChange();
   1258  }
   1259 }
   1260 
   1261 void SVGRenderingObserverSet::RemoveAll() {
   1262  const auto observers = std::move(mObservers);
   1263 
   1264  // Our list is now cleared.  We need to notify the observers we've removed,
   1265  // so they can update their state & remove themselves as mutation-observers.
   1266  for (const auto& observer : observers) {
   1267    observer->NotifyEvictedFromRenderingObserverSet();
   1268  }
   1269 }
   1270 
   1271 static SVGRenderingObserverSet* GetObserverSet(Element* aElement) {
   1272  return static_cast<SVGRenderingObserverSet*>(
   1273      aElement->GetProperty(nsGkAtoms::renderingobserverset));
   1274 }
   1275 
   1276 #ifdef DEBUG
   1277 // Defined down here because we need SVGRenderingObserverSet's definition.
   1278 void SVGRenderingObserver::DebugObserverSet() {
   1279  Element* referencedElement = GetReferencedElementWithoutObserving();
   1280  if (referencedElement) {
   1281    SVGRenderingObserverSet* observers = GetObserverSet(referencedElement);
   1282    bool inObserverSet = observers && observers->Contains(this);
   1283    MOZ_ASSERT(inObserverSet == mInObserverSet,
   1284               "failed to track whether we're in our referenced element's "
   1285               "observer set!");
   1286  } else {
   1287    MOZ_ASSERT(!mInObserverSet, "In whose observer set are we, then?");
   1288  }
   1289 }
   1290 #endif
   1291 
   1292 using URIObserverHashtable =
   1293    nsInterfaceHashtable<SVGReferenceHashKey, nsIMutationObserver>;
   1294 
   1295 using PaintingPropertyDescriptor =
   1296    const FramePropertyDescriptor<SVGPaintingProperty>*;
   1297 
   1298 static void DestroyFilterProperty(SVGFilterObserverListForCSSProp* aProp) {
   1299  aProp->Release();
   1300 }
   1301 
   1302 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefToTemplateProperty,
   1303                                     SVGTemplateElementObserver)
   1304 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(BackdropFilterProperty,
   1305                                    SVGFilterObserverListForCSSProp,
   1306                                    DestroyFilterProperty)
   1307 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(FilterProperty,
   1308                                    SVGFilterObserverListForCSSProp,
   1309                                    DestroyFilterProperty)
   1310 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MaskProperty, SVGMaskObserverList)
   1311 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(ClipPathProperty, SVGPaintingProperty)
   1312 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerStartProperty, SVGMarkerObserver)
   1313 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerMidProperty, SVGMarkerObserver)
   1314 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerEndProperty, SVGMarkerObserver)
   1315 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(FillProperty, SVGPaintingProperty)
   1316 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(StrokeProperty, SVGPaintingProperty)
   1317 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefAsTextPathProperty,
   1318                                     SVGTextPathObserver)
   1319 NS_DECLARE_FRAME_PROPERTY_DELETABLE(BackgroundImageProperty,
   1320                                    URIObserverHashtable)
   1321 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(BackgroundClipObserverProperty,
   1322                                     BackgroundClipRenderingObserver)
   1323 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(OffsetPathProperty,
   1324                                     SVGRenderingObserverProperty)
   1325 
   1326 template <class T>
   1327 static T* GetEffectProperty(SVGReference* aReference, nsIFrame* aFrame,
   1328                            const FramePropertyDescriptor<T>* aProperty) {
   1329  if (!aReference) {
   1330    return nullptr;
   1331  }
   1332 
   1333  bool found;
   1334  T* prop = aFrame->GetProperty(aProperty, &found);
   1335  if (found) {
   1336    MOZ_ASSERT(prop, "this property should only store non-null values");
   1337    return prop;
   1338  }
   1339  prop = new T(aReference, aFrame, false);
   1340  NS_ADDREF(prop);
   1341  aFrame->AddProperty(aProperty, prop);
   1342  return prop;
   1343 }
   1344 
   1345 static SVGPaintingProperty* GetPaintingProperty(
   1346    SVGReference* aReference, nsIFrame* aFrame,
   1347    const FramePropertyDescriptor<SVGPaintingProperty>* aProperty) {
   1348  return GetEffectProperty(aReference, aFrame, aProperty);
   1349 }
   1350 
   1351 static already_AddRefed<SVGReference> GetMarkerURI(
   1352    nsIFrame* aFrame, const StyleUrlOrNone nsStyleSVG::* aMarker) {
   1353  const StyleUrlOrNone& url = aFrame->StyleSVG()->*aMarker;
   1354  if (url.IsNone()) {
   1355    return nullptr;
   1356  }
   1357  return ResolveURLUsingLocalRef(url.AsUrl());
   1358 }
   1359 
   1360 bool SVGObserverUtils::GetAndObserveMarkers(nsIFrame* aMarkedFrame,
   1361                                            SVGMarkerFrame* (*aFrames)[3]) {
   1362  MOZ_ASSERT(!aMarkedFrame->GetPrevContinuation() &&
   1363                 aMarkedFrame->IsSVGGeometryFrame() &&
   1364                 static_cast<SVGGeometryElement*>(aMarkedFrame->GetContent())
   1365                     ->IsMarkable(),
   1366             "Bad frame");
   1367 
   1368  bool foundMarker = false;
   1369  RefPtr<SVGReference> markerURL;
   1370  SVGMarkerObserver* observer;
   1371  nsIFrame* marker;
   1372 
   1373 #define GET_MARKER(type)                                                    \
   1374  markerURL = GetMarkerURI(aMarkedFrame, &nsStyleSVG::mMarker##type);       \
   1375  observer =                                                                \
   1376      GetEffectProperty(markerURL, aMarkedFrame, Marker##type##Property()); \
   1377  marker = observer ? observer->GetAndObserveReferencedFrame(               \
   1378                          LayoutFrameType::SVGMarker, nullptr)              \
   1379                    : nullptr;                                              \
   1380  foundMarker = foundMarker || bool(marker);                                \
   1381  (*aFrames)[SVGMark::e##type] = static_cast<SVGMarkerFrame*>(marker);
   1382 
   1383  GET_MARKER(Start)
   1384  GET_MARKER(Mid)
   1385  GET_MARKER(End)
   1386 
   1387 #undef GET_MARKER
   1388 
   1389  return foundMarker;
   1390 }
   1391 
   1392 // Note that the returned list will be empty in the case of a 'filter' property
   1393 // that only specifies CSS filter functions (no url()'s to SVG filters).
   1394 template <typename P>
   1395 static SVGFilterObserverListForCSSProp* GetOrCreateFilterObserverListForCSS(
   1396    nsIFrame* aFrame, bool aHasFilters,
   1397    FrameProperties::Descriptor<P> aProperty,
   1398    Span<const StyleFilter> aFilters) {
   1399  if (!aHasFilters) {
   1400    return nullptr;
   1401  }
   1402 
   1403  bool found;
   1404  SVGFilterObserverListForCSSProp* observers =
   1405      aFrame->GetProperty(aProperty, &found);
   1406  if (found) {
   1407    MOZ_ASSERT(observers, "this property should only store non-null values");
   1408    return observers;
   1409  }
   1410  observers = new SVGFilterObserverListForCSSProp(aFilters, aFrame);
   1411  NS_ADDREF(observers);
   1412  aFrame->AddProperty(aProperty, observers);
   1413  return observers;
   1414 }
   1415 
   1416 static SVGFilterObserverListForCSSProp* GetOrCreateFilterObserverListForCSS(
   1417    nsIFrame* aFrame, StyleFilterType aStyleFilterType) {
   1418  MOZ_ASSERT(!aFrame->GetPrevContinuation(), "Require first continuation");
   1419 
   1420  const nsStyleEffects* effects = aFrame->StyleEffects();
   1421 
   1422  return aStyleFilterType == StyleFilterType::BackdropFilter
   1423             ? GetOrCreateFilterObserverListForCSS(
   1424                   aFrame, effects->HasBackdropFilters(),
   1425                   BackdropFilterProperty(), effects->mBackdropFilters.AsSpan())
   1426             : GetOrCreateFilterObserverListForCSS(
   1427                   aFrame, effects->HasFilters(), FilterProperty(),
   1428                   effects->mFilters.AsSpan());
   1429 }
   1430 
   1431 static SVGObserverUtils::ReferenceState GetAndObserveFilters(
   1432    ISVGFilterObserverList* aObserverList,
   1433    nsTArray<SVGFilterFrame*>* aFilterFrames) {
   1434  if (!aObserverList) {
   1435    return SVGObserverUtils::eHasNoRefs;
   1436  }
   1437 
   1438  const nsTArray<RefPtr<SVGFilterObserver>>& observers =
   1439      aObserverList->GetObservers();
   1440  if (observers.IsEmpty()) {
   1441    return SVGObserverUtils::eHasNoRefs;
   1442  }
   1443 
   1444  for (const auto& observer : observers) {
   1445    SVGFilterFrame* filter = observer->GetAndObserveFilterFrame();
   1446    if (!filter) {
   1447      if (aFilterFrames) {
   1448        aFilterFrames->Clear();
   1449      }
   1450      return SVGObserverUtils::eHasRefsSomeInvalid;
   1451    }
   1452    if (aFilterFrames) {
   1453      aFilterFrames->AppendElement(filter);
   1454    }
   1455  }
   1456 
   1457  return SVGObserverUtils::eHasRefsAllValid;
   1458 }
   1459 
   1460 SVGObserverUtils::ReferenceState SVGObserverUtils::GetAndObserveFilters(
   1461    nsIFrame* aFilteredFrame, nsTArray<SVGFilterFrame*>* aFilterFrames,
   1462    StyleFilterType aStyleFilterType) {
   1463  SVGFilterObserverListForCSSProp* observerList =
   1464      GetOrCreateFilterObserverListForCSS(aFilteredFrame, aStyleFilterType);
   1465  return mozilla::GetAndObserveFilters(observerList, aFilterFrames);
   1466 }
   1467 
   1468 SVGObserverUtils::ReferenceState SVGObserverUtils::GetAndObserveFilters(
   1469    ISVGFilterObserverList* aObserverList,
   1470    nsTArray<SVGFilterFrame*>* aFilterFrames) {
   1471  return mozilla::GetAndObserveFilters(aObserverList, aFilterFrames);
   1472 }
   1473 
   1474 SVGObserverUtils::ReferenceState SVGObserverUtils::GetFiltersIfObserving(
   1475    nsIFrame* aFilteredFrame, nsTArray<SVGFilterFrame*>* aFilterFrames) {
   1476  SVGFilterObserverListForCSSProp* observerList =
   1477      aFilteredFrame->GetProperty(FilterProperty());
   1478  return mozilla::GetAndObserveFilters(observerList, aFilterFrames);
   1479 }
   1480 
   1481 already_AddRefed<ISVGFilterObserverList>
   1482 SVGObserverUtils::ObserveFiltersForCanvasContext(
   1483    CanvasRenderingContext2D* aContext, Element* aCanvasElement,
   1484    const Span<const StyleFilter> aFilters) {
   1485  return do_AddRef(new SVGFilterObserverListForCanvasContext(
   1486      aContext, aCanvasElement, aFilters));
   1487 }
   1488 
   1489 static SVGPaintingProperty* GetOrCreateClipPathObserver(
   1490    nsIFrame* aClippedFrame) {
   1491  MOZ_ASSERT(!aClippedFrame->GetPrevContinuation(),
   1492             "Require first continuation");
   1493 
   1494  const nsStyleSVGReset* svgStyleReset = aClippedFrame->StyleSVGReset();
   1495  if (!svgStyleReset->mClipPath.IsUrl()) {
   1496    return nullptr;
   1497  }
   1498  const auto& url = svgStyleReset->mClipPath.AsUrl();
   1499  RefPtr<SVGReference> pathURI = ResolveURLUsingLocalRef(url);
   1500  return GetPaintingProperty(pathURI, aClippedFrame, ClipPathProperty());
   1501 }
   1502 
   1503 SVGObserverUtils::ReferenceState SVGObserverUtils::GetAndObserveClipPath(
   1504    nsIFrame* aClippedFrame, SVGClipPathFrame** aClipPathFrame) {
   1505  if (aClipPathFrame) {
   1506    *aClipPathFrame = nullptr;
   1507  }
   1508  SVGPaintingProperty* observers = GetOrCreateClipPathObserver(aClippedFrame);
   1509  if (!observers) {
   1510    return eHasNoRefs;
   1511  }
   1512  bool frameTypeOK = true;
   1513  SVGClipPathFrame* frame =
   1514      static_cast<SVGClipPathFrame*>(observers->GetAndObserveReferencedFrame(
   1515          LayoutFrameType::SVGClipPath, &frameTypeOK));
   1516  // Note that, unlike for filters, a reference to an ID that doesn't exist
   1517  // is not invalid for clip-path or mask.
   1518  if (!frameTypeOK) {
   1519    return eHasRefsSomeInvalid;
   1520  }
   1521  if (aClipPathFrame) {
   1522    *aClipPathFrame = frame;
   1523  }
   1524  return frame ? eHasRefsAllValid : eHasNoRefs;
   1525 }
   1526 
   1527 static SVGRenderingObserverProperty* GetOrCreateGeometryObserver(
   1528    nsIFrame* aFrame) {
   1529  // Now only offset-path property uses this. See MotionPathUtils.cpp.
   1530  const nsStyleDisplay* disp = aFrame->StyleDisplay();
   1531  if (!disp->mOffsetPath.IsUrl()) {
   1532    return nullptr;
   1533  }
   1534  const auto& url = disp->mOffsetPath.AsUrl();
   1535  RefPtr<SVGReference> pathURI = ResolveURLUsingLocalRef(url);
   1536  return GetEffectProperty(pathURI, aFrame, OffsetPathProperty());
   1537 }
   1538 
   1539 SVGGeometryElement* SVGObserverUtils::GetAndObserveGeometry(nsIFrame* aFrame) {
   1540  SVGRenderingObserverProperty* observers = GetOrCreateGeometryObserver(aFrame);
   1541  if (!observers) {
   1542    return nullptr;
   1543  }
   1544 
   1545  bool frameTypeOK = true;
   1546  SVGGeometryFrame* frame =
   1547      do_QueryFrame(observers->GetAndObserveReferencedFrame(
   1548          LayoutFrameType::SVGGeometry, &frameTypeOK));
   1549  if (!frameTypeOK || !frame) {
   1550    return nullptr;
   1551  }
   1552 
   1553  return static_cast<dom::SVGGeometryElement*>(frame->GetContent());
   1554 }
   1555 
   1556 static SVGMaskObserverList* GetOrCreateMaskObserverList(
   1557    nsIFrame* aMaskedFrame) {
   1558  MOZ_ASSERT(!aMaskedFrame->GetPrevContinuation(),
   1559             "Require first continuation");
   1560 
   1561  const nsStyleSVGReset* style = aMaskedFrame->StyleSVGReset();
   1562  if (!style->HasMask()) {
   1563    return nullptr;
   1564  }
   1565 
   1566  MOZ_ASSERT(style->mMask.mImageCount > 0);
   1567 
   1568  bool found;
   1569  SVGMaskObserverList* prop = aMaskedFrame->GetProperty(MaskProperty(), &found);
   1570  if (found) {
   1571    MOZ_ASSERT(prop, "this property should only store non-null values");
   1572    return prop;
   1573  }
   1574  prop = new SVGMaskObserverList(aMaskedFrame);
   1575  NS_ADDREF(prop);
   1576  aMaskedFrame->AddProperty(MaskProperty(), prop);
   1577  return prop;
   1578 }
   1579 
   1580 SVGObserverUtils::ReferenceState SVGObserverUtils::GetAndObserveMasks(
   1581    nsIFrame* aMaskedFrame, nsTArray<SVGMaskFrame*>* aMaskFrames) {
   1582  SVGMaskObserverList* observerList = GetOrCreateMaskObserverList(aMaskedFrame);
   1583  if (!observerList) {
   1584    return eHasNoRefs;
   1585  }
   1586 
   1587  const nsTArray<RefPtr<SVGPaintingProperty>>& observers =
   1588      observerList->GetObservers();
   1589  if (observers.IsEmpty()) {
   1590    return eHasNoRefs;
   1591  }
   1592 
   1593  ReferenceState state = eHasRefsAllValid;
   1594 
   1595  for (size_t i = 0; i < observers.Length(); i++) {
   1596    bool frameTypeOK = true;
   1597    SVGMaskFrame* maskFrame =
   1598        static_cast<SVGMaskFrame*>(observers[i]->GetAndObserveReferencedFrame(
   1599            LayoutFrameType::SVGMask, &frameTypeOK));
   1600    MOZ_ASSERT(!maskFrame || frameTypeOK);
   1601    // XXXjwatt: this looks fishy
   1602    if (!frameTypeOK) {
   1603      // We can not find the specific SVG mask resource in the downloaded SVG
   1604      // document. There are two possibilities:
   1605      // 1. The given resource id is invalid.
   1606      // 2. The given resource id refers to a viewbox.
   1607      //
   1608      // Hand it over to the style image.
   1609      observerList->ResolveImage(i);
   1610      state = eHasRefsSomeInvalid;
   1611    }
   1612    if (aMaskFrames) {
   1613      aMaskFrames->AppendElement(maskFrame);
   1614    }
   1615  }
   1616 
   1617  return state;
   1618 }
   1619 
   1620 SVGGeometryElement* SVGObserverUtils::GetAndObserveTextPathsPath(
   1621    nsIFrame* aTextPathFrame) {
   1622  // Continuations can come and go during reflow, and we don't need to observe
   1623  // the referenced element more than once for a given node.
   1624  aTextPathFrame = aTextPathFrame->FirstContinuation();
   1625 
   1626  SVGTextPathObserver* property =
   1627      aTextPathFrame->GetProperty(HrefAsTextPathProperty());
   1628 
   1629  if (!property) {
   1630    nsIContent* content = aTextPathFrame->GetContent();
   1631    nsAutoString href;
   1632    static_cast<SVGTextPathElement*>(content)->HrefAsString(href);
   1633    if (href.IsEmpty()) {
   1634      return nullptr;  // no URL
   1635    }
   1636 
   1637    RefPtr<SVGReference> target = ResolveURLUsingLocalRef(content, href);
   1638 
   1639    property =
   1640        GetEffectProperty(target, aTextPathFrame, HrefAsTextPathProperty());
   1641    if (!property) {
   1642      return nullptr;
   1643    }
   1644  }
   1645 
   1646  return SVGGeometryElement::FromNodeOrNull(
   1647      property->GetAndObserveReferencedElement());
   1648 }
   1649 
   1650 SVGGraphicsElement* SVGObserverUtils::GetAndObserveFEImageContent(
   1651    SVGFEImageElement* aSVGFEImageElement) {
   1652  if (!aSVGFEImageElement->mImageContentObserver) {
   1653    nsAutoString href;
   1654    aSVGFEImageElement->HrefAsString(href);
   1655    if (href.IsEmpty()) {
   1656      return nullptr;  // no URL
   1657    }
   1658 
   1659    RefPtr<SVGReference> target =
   1660        ResolveURLUsingLocalRef(aSVGFEImageElement, href);
   1661 
   1662    aSVGFEImageElement->mImageContentObserver =
   1663        new SVGFEImageObserver(target, aSVGFEImageElement);
   1664  }
   1665 
   1666  return SVGGraphicsElement::FromNodeOrNull(
   1667      static_cast<SVGFEImageObserver*>(
   1668          aSVGFEImageElement->mImageContentObserver.get())
   1669          ->GetAndObserveReferencedElement());
   1670 }
   1671 
   1672 void SVGObserverUtils::TraverseFEImageObserver(
   1673    SVGFEImageElement* aSVGFEImageElement,
   1674    nsCycleCollectionTraversalCallback* aCB) {
   1675  if (aSVGFEImageElement->mImageContentObserver) {
   1676    static_cast<SVGFEImageObserver*>(
   1677        aSVGFEImageElement->mImageContentObserver.get())
   1678        ->Traverse(aCB);
   1679  }
   1680 }
   1681 
   1682 SVGGeometryElement* SVGObserverUtils::GetAndObserveMPathsPath(
   1683    SVGMPathElement* aSVGMPathElement) {
   1684  if (!aSVGMPathElement->mMPathObserver) {
   1685    nsAutoString href;
   1686    aSVGMPathElement->HrefAsString(href);
   1687    if (href.IsEmpty()) {
   1688      return nullptr;  // no URL
   1689    }
   1690 
   1691    RefPtr<SVGReference> target =
   1692        ResolveURLUsingLocalRef(aSVGMPathElement, href);
   1693 
   1694    aSVGMPathElement->mMPathObserver =
   1695        new SVGMPathObserver(target, aSVGMPathElement);
   1696  }
   1697 
   1698  return SVGGeometryElement::FromNodeOrNull(
   1699      static_cast<SVGMPathObserver*>(aSVGMPathElement->mMPathObserver.get())
   1700          ->GetAndObserveReferencedElement());
   1701 }
   1702 
   1703 void SVGObserverUtils::TraverseMPathObserver(
   1704    SVGMPathElement* aSVGMPathElement,
   1705    nsCycleCollectionTraversalCallback* aCB) {
   1706  if (aSVGMPathElement->mMPathObserver) {
   1707    static_cast<SVGMPathObserver*>(aSVGMPathElement->mMPathObserver.get())
   1708        ->Traverse(aCB);
   1709  }
   1710 }
   1711 
   1712 void SVGObserverUtils::InitiateResourceDocLoads(nsIFrame* aFrame) {
   1713  // We create observer objects and attach them to aFrame, but we do not
   1714  // make aFrame start observing the referenced frames.
   1715  (void)GetOrCreateFilterObserverListForCSS(aFrame,
   1716                                            StyleFilterType::BackdropFilter);
   1717  (void)GetOrCreateFilterObserverListForCSS(aFrame, StyleFilterType::Filter);
   1718  (void)GetOrCreateClipPathObserver(aFrame);
   1719  (void)GetOrCreateGeometryObserver(aFrame);
   1720  (void)GetOrCreateMaskObserverList(aFrame);
   1721 }
   1722 
   1723 void SVGObserverUtils::RemoveTextPathObserver(nsIFrame* aTextPathFrame) {
   1724  aTextPathFrame->RemoveProperty(HrefAsTextPathProperty());
   1725 }
   1726 
   1727 nsIFrame* SVGObserverUtils::GetAndObserveTemplate(
   1728    nsIFrame* aFrame, HrefToTemplateCallback aGetHref) {
   1729  SVGTemplateElementObserver* observer =
   1730      aFrame->GetProperty(HrefToTemplateProperty());
   1731 
   1732  if (!observer) {
   1733    nsAutoString href;
   1734    aGetHref(href);
   1735    if (href.IsEmpty()) {
   1736      return nullptr;  // no URL
   1737    }
   1738 
   1739    RefPtr<SVGReference> info =
   1740        ResolveURLUsingLocalRef(aFrame->GetContent(), href);
   1741 
   1742    observer = GetEffectProperty(info, aFrame, HrefToTemplateProperty());
   1743  }
   1744 
   1745  return observer ? observer->GetAndObserveReferencedFrame() : nullptr;
   1746 }
   1747 
   1748 void SVGObserverUtils::RemoveTemplateObserver(nsIFrame* aFrame) {
   1749  aFrame->RemoveProperty(HrefToTemplateProperty());
   1750 }
   1751 
   1752 Element* SVGObserverUtils::GetAndObserveBackgroundImage(nsIFrame* aFrame,
   1753                                                        const nsAtom* aHref) {
   1754  bool found;
   1755  URIObserverHashtable* hashtable =
   1756      aFrame->GetProperty(BackgroundImageProperty(), &found);
   1757  if (!found) {
   1758    hashtable = new URIObserverHashtable();
   1759    aFrame->AddProperty(BackgroundImageProperty(), hashtable);
   1760  } else {
   1761    MOZ_ASSERT(hashtable, "this property should only store non-null values");
   1762  }
   1763  nsAutoString localRef = u"#"_ns + nsDependentAtomString(aHref);
   1764  auto* doc = aFrame->GetContent()->OwnerDoc();
   1765  nsIURI* baseURI = aFrame->GetContent()->GetBaseURI();
   1766  nsIReferrerInfo* referrerInfo =
   1767      doc->ReferrerInfoForInternalCSSAndSVGResources();
   1768  auto url = MakeRefPtr<SVGReference>(localRef, baseURI, referrerInfo);
   1769 
   1770  return static_cast<SVGMozElementObserver*>(
   1771             hashtable
   1772                 ->LookupOrInsertWith(
   1773                     url,
   1774                     [&] {
   1775                       return MakeRefPtr<SVGMozElementObserver>(url, aFrame);
   1776                     })
   1777                 .get())
   1778      ->GetAndObserveReferencedElement();
   1779 }
   1780 
   1781 Element* SVGObserverUtils::GetAndObserveBackgroundClip(nsIFrame* aFrame) {
   1782  bool found;
   1783  BackgroundClipRenderingObserver* obs =
   1784      aFrame->GetProperty(BackgroundClipObserverProperty(), &found);
   1785  if (!found) {
   1786    obs = new BackgroundClipRenderingObserver(aFrame);
   1787    NS_ADDREF(obs);
   1788    aFrame->AddProperty(BackgroundClipObserverProperty(), obs);
   1789  }
   1790 
   1791  return obs->GetAndObserveReferencedElement();
   1792 }
   1793 
   1794 SVGPaintServerFrame* SVGObserverUtils::GetAndObservePaintServer(
   1795    nsIFrame* aPaintedFrame, StyleSVGPaint nsStyleSVG::* aPaint) {
   1796  // If we're looking at a frame within SVG text, then we need to look up
   1797  // to find the right frame to get the painting property off.  We should at
   1798  // least look up past a text frame, and if the text frame's parent is the
   1799  // anonymous block frame, then we look up to its parent (the SVGTextFrame).
   1800  nsIFrame* paintedFrame = aPaintedFrame;
   1801  if (paintedFrame->IsInSVGTextSubtree()) {
   1802    paintedFrame = paintedFrame->GetParent();
   1803    nsIFrame* grandparent = paintedFrame->GetParent();
   1804    if (grandparent && grandparent->IsSVGTextFrame()) {
   1805      paintedFrame = grandparent;
   1806    }
   1807  }
   1808 
   1809  const nsStyleSVG* svgStyle = paintedFrame->StyleSVG();
   1810  if (!(svgStyle->*aPaint).kind.IsPaintServer()) {
   1811    return nullptr;
   1812  }
   1813 
   1814  RefPtr<SVGReference> paintServerURL =
   1815      ResolveURLUsingLocalRef((svgStyle->*aPaint).kind.AsPaintServer());
   1816 
   1817  MOZ_ASSERT(aPaint == &nsStyleSVG::mFill || aPaint == &nsStyleSVG::mStroke);
   1818  PaintingPropertyDescriptor propDesc =
   1819      (aPaint == &nsStyleSVG::mFill) ? FillProperty() : StrokeProperty();
   1820  if (auto* property =
   1821          GetPaintingProperty(paintServerURL, paintedFrame, propDesc)) {
   1822    return do_QueryFrame(property->GetAndObserveReferencedFrame());
   1823  }
   1824  return nullptr;
   1825 }
   1826 
   1827 void SVGObserverUtils::UpdateEffects(nsIFrame* aFrame) {
   1828  NS_ASSERTION(!aFrame->GetContent() || aFrame->GetContent()->IsElement(),
   1829               "aFrame's content (if non-null) should be an element");
   1830 
   1831  aFrame->RemoveProperty(BackdropFilterProperty());
   1832  aFrame->RemoveProperty(FilterProperty());
   1833  aFrame->RemoveProperty(MaskProperty());
   1834  aFrame->RemoveProperty(ClipPathProperty());
   1835  aFrame->RemoveProperty(MarkerStartProperty());
   1836  aFrame->RemoveProperty(MarkerMidProperty());
   1837  aFrame->RemoveProperty(MarkerEndProperty());
   1838  aFrame->RemoveProperty(FillProperty());
   1839  aFrame->RemoveProperty(StrokeProperty());
   1840  aFrame->RemoveProperty(BackgroundImageProperty());
   1841 
   1842  // Ensure that the filter is repainted correctly
   1843  // We can't do that in OnRenderingChange as the referenced frame may
   1844  // not be valid
   1845  GetOrCreateFilterObserverListForCSS(aFrame, StyleFilterType::BackdropFilter);
   1846  GetOrCreateFilterObserverListForCSS(aFrame, StyleFilterType::Filter);
   1847 
   1848  if (aFrame->IsSVGGeometryFrame() &&
   1849      static_cast<SVGGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
   1850    // Set marker properties here to avoid reference loops
   1851    RefPtr<SVGReference> markerURL =
   1852        GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
   1853    GetEffectProperty(markerURL, aFrame, MarkerStartProperty());
   1854    markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
   1855    GetEffectProperty(markerURL, aFrame, MarkerMidProperty());
   1856    markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
   1857    GetEffectProperty(markerURL, aFrame, MarkerEndProperty());
   1858  }
   1859 }
   1860 
   1861 bool SVGObserverUtils::SelfOrAncestorHasRenderingObservers(
   1862    const nsIFrame* aFrame) {
   1863  nsIContent* content = aFrame->GetContent();
   1864  while (content) {
   1865    if (content->HasDirectRenderingObservers()) {
   1866      return true;
   1867    }
   1868    const auto* frame = content->GetPrimaryFrame();
   1869    if (frame && frame->IsSVGRenderingObserverContainer()) {
   1870      break;
   1871    }
   1872    content = content->GetFlattenedTreeParent();
   1873  }
   1874  return false;
   1875 }
   1876 
   1877 void SVGObserverUtils::AddRenderingObserver(Element* aElement,
   1878                                            SVGRenderingObserver* aObserver) {
   1879  SVGRenderingObserverSet* observers = GetObserverSet(aElement);
   1880  if (!observers) {
   1881    observers = new SVGRenderingObserverSet();
   1882    // When we call cloneAndAdopt we keep the property. If the referenced
   1883    // element doesn't exist in the new document then the observer set and
   1884    // observers will be removed by ElementTracker::ElementChanged when we
   1885    // get the ChangeNotification.
   1886    aElement->SetProperty(nsGkAtoms::renderingobserverset, observers,
   1887                          nsINode::DeleteProperty<SVGRenderingObserverSet>,
   1888                          /* aTransfer = */ true);
   1889  }
   1890  aElement->SetHasDirectRenderingObservers(true);
   1891  observers->Add(aObserver);
   1892 }
   1893 
   1894 void SVGObserverUtils::RemoveRenderingObserver(
   1895    Element* aElement, SVGRenderingObserver* aObserver) {
   1896  SVGRenderingObserverSet* observers = GetObserverSet(aElement);
   1897  if (observers) {
   1898    NS_ASSERTION(observers->Contains(aObserver),
   1899                 "removing observer from an element we're not observing?");
   1900    observers->Remove(aObserver);
   1901    if (observers->IsEmpty()) {
   1902      aElement->RemoveProperty(nsGkAtoms::renderingobserverset);
   1903      aElement->SetHasDirectRenderingObservers(false);
   1904    }
   1905  }
   1906 }
   1907 
   1908 void SVGObserverUtils::RemoveAllRenderingObservers(Element* aElement) {
   1909  SVGRenderingObserverSet* observers = GetObserverSet(aElement);
   1910  if (observers) {
   1911    observers->RemoveAll();
   1912    aElement->RemoveProperty(nsGkAtoms::renderingobserverset);
   1913    aElement->SetHasDirectRenderingObservers(false);
   1914  }
   1915 }
   1916 
   1917 void SVGObserverUtils::InvalidateRenderingObservers(nsIFrame* aFrame) {
   1918  NS_ASSERTION(!aFrame->GetPrevContinuation(),
   1919               "aFrame must be first continuation");
   1920 
   1921  auto* element = Element::FromNodeOrNull(aFrame->GetContent());
   1922  if (!element) {
   1923    return;
   1924  }
   1925 
   1926  // If the rendering has changed, the bounds may well have changed too:
   1927  aFrame->RemoveProperty(SVGUtils::ObjectBoundingBoxProperty());
   1928 
   1929  if (auto* observers = GetObserverSet(element)) {
   1930    observers->InvalidateAll();
   1931    return;
   1932  }
   1933 
   1934  if (aFrame->IsSVGRenderingObserverContainer()) {
   1935    return;
   1936  }
   1937 
   1938  // Check ancestor SVG containers. The root frame cannot be of type
   1939  // eSVGContainer so we don't have to check f for null here.
   1940  for (nsIFrame* f = aFrame->GetParent(); f->IsSVGContainerFrame();
   1941       f = f->GetParent()) {
   1942    if (auto* element = Element::FromNode(f->GetContent())) {
   1943      if (auto* observers = GetObserverSet(element)) {
   1944        observers->InvalidateAll();
   1945        return;
   1946      }
   1947    }
   1948    if (f->IsSVGRenderingObserverContainer()) {
   1949      return;
   1950    }
   1951  }
   1952 }
   1953 
   1954 void SVGObserverUtils::InvalidateDirectRenderingObservers(
   1955    Element* aElement, uint32_t aFlags /* = 0 */) {
   1956  if (!(aFlags & INVALIDATE_DESTROY)) {
   1957    if (nsIFrame* frame = aElement->GetPrimaryFrame()) {
   1958      // If the rendering has changed, the bounds may well have changed too:
   1959      frame->RemoveProperty(SVGUtils::ObjectBoundingBoxProperty());
   1960    }
   1961  }
   1962 
   1963  if (aElement->HasDirectRenderingObservers()) {
   1964    SVGRenderingObserverSet* observers = GetObserverSet(aElement);
   1965    if (observers) {
   1966      if (aFlags & INVALIDATE_REFLOW) {
   1967        observers->InvalidateAllForReflow();
   1968      } else {
   1969        observers->InvalidateAll();
   1970      }
   1971    }
   1972  }
   1973 }
   1974 
   1975 void SVGObserverUtils::InvalidateDirectRenderingObservers(
   1976    nsIFrame* aFrame, uint32_t aFlags /* = 0 */) {
   1977  if (auto* element = Element::FromNodeOrNull(aFrame->GetContent())) {
   1978    InvalidateDirectRenderingObservers(element, aFlags);
   1979  }
   1980 }
   1981 
   1982 }  // namespace mozilla