Bug 1859059 - increase chunk number for windows debug mochitest-browser-chrome jobs...
[gecko.git] / layout / svg / SVGObserverUtils.cpp
blob6682fb9af3528af3909f83119fa4177eb428a070
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/. */
7 // Main header first:
8 #include "SVGObserverUtils.h"
10 // Keep others in (case-insensitive) order:
11 #include "mozilla/css/ImageLoader.h"
12 #include "mozilla/dom/CanvasRenderingContext2D.h"
13 #include "mozilla/dom/ReferrerInfo.h"
14 #include "mozilla/dom/SVGGeometryElement.h"
15 #include "mozilla/dom/SVGMPathElement.h"
16 #include "mozilla/dom/SVGTextPathElement.h"
17 #include "mozilla/dom/SVGUseElement.h"
18 #include "mozilla/PresShell.h"
19 #include "mozilla/RestyleManager.h"
20 #include "mozilla/SVGClipPathFrame.h"
21 #include "mozilla/SVGGeometryFrame.h"
22 #include "mozilla/SVGMaskFrame.h"
23 #include "mozilla/SVGTextFrame.h"
24 #include "mozilla/SVGUtils.h"
25 #include "nsCSSFrameConstructor.h"
26 #include "nsCycleCollectionParticipant.h"
27 #include "nsHashKeys.h"
28 #include "nsIContent.h"
29 #include "nsIContentInlines.h"
30 #include "nsInterfaceHashtable.h"
31 #include "nsIReflowCallback.h"
32 #include "nsISupportsImpl.h"
33 #include "nsLayoutUtils.h"
34 #include "nsNetUtil.h"
35 #include "nsTHashtable.h"
36 #include "nsURIHashKey.h"
37 #include "SVGFilterFrame.h"
38 #include "SVGMarkerFrame.h"
39 #include "SVGPaintServerFrame.h"
41 using namespace mozilla::dom;
43 namespace mozilla {
45 bool URLAndReferrerInfo::operator==(const URLAndReferrerInfo& aRHS) const {
46 bool uriEqual = false, referrerEqual = false;
47 this->mURI->Equals(aRHS.mURI, &uriEqual);
48 this->mReferrerInfo->Equals(aRHS.mReferrerInfo, &referrerEqual);
50 return uriEqual && referrerEqual;
53 class URLAndReferrerInfoHashKey : public PLDHashEntryHdr {
54 public:
55 using KeyType = const URLAndReferrerInfo*;
56 using KeyTypePointer = const URLAndReferrerInfo*;
58 explicit URLAndReferrerInfoHashKey(const URLAndReferrerInfo* aKey) noexcept
59 : mKey(aKey) {
60 MOZ_COUNT_CTOR(URLAndReferrerInfoHashKey);
62 URLAndReferrerInfoHashKey(URLAndReferrerInfoHashKey&& aToMove) noexcept
63 : PLDHashEntryHdr(std::move(aToMove)), mKey(std::move(aToMove.mKey)) {
64 MOZ_COUNT_CTOR(URLAndReferrerInfoHashKey);
66 MOZ_COUNTED_DTOR(URLAndReferrerInfoHashKey)
68 const URLAndReferrerInfo* GetKey() const { return mKey; }
70 bool KeyEquals(const URLAndReferrerInfo* aKey) const {
71 if (!mKey) {
72 return !aKey;
74 return *mKey == *aKey;
77 static const URLAndReferrerInfo* KeyToPointer(
78 const URLAndReferrerInfo* aKey) {
79 return aKey;
82 static PLDHashNumber HashKey(const URLAndReferrerInfo* aKey) {
83 if (!aKey) {
84 // If the key is null, return hash for empty string.
85 return HashString(""_ns);
87 nsAutoCString urlSpec, referrerSpec;
88 // nsURIHashKey ignores GetSpec() failures, so we do too:
89 Unused << aKey->GetURI()->GetSpec(urlSpec);
90 return AddToHash(
91 HashString(urlSpec),
92 static_cast<ReferrerInfo*>(aKey->GetReferrerInfo())->Hash());
95 enum { ALLOW_MEMMOVE = true };
97 protected:
98 RefPtr<const URLAndReferrerInfo> mKey;
101 static already_AddRefed<URLAndReferrerInfo> ResolveURLUsingLocalRef(
102 nsIFrame* aFrame, const StyleComputedImageUrl& aURL) {
103 MOZ_ASSERT(aFrame);
105 nsCOMPtr<nsIURI> uri = aURL.GetURI();
107 if (aURL.IsLocalRef()) {
108 uri = SVGObserverUtils::GetBaseURLForLocalRef(aFrame->GetContent(), uri);
109 uri = aURL.ResolveLocalRef(uri);
112 if (!uri) {
113 return nullptr;
116 RefPtr<URLAndReferrerInfo> info =
117 new URLAndReferrerInfo(uri, aURL.ExtraData());
118 return info.forget();
121 static already_AddRefed<URLAndReferrerInfo> ResolveURLUsingLocalRef(
122 nsIContent* aContent, const nsAString& aURL,
123 nsIReferrerInfo* aReferrerInfo) {
124 // Like SVGObserverUtils::GetBaseURLForLocalRef, we want to resolve the
125 // URL against any <use> element shadow tree's source document.
127 // Unlike GetBaseURLForLocalRef, we are assuming that the URL was specified
128 // directly on mFrame's content (because this ResolveURLUsingLocalRef
129 // overload is used for href="" attributes and not CSS URL values), so there
130 // is no need to check whether the URL was specified / inherited from
131 // outside the shadow tree.
132 nsIURI* base = nullptr;
133 const Encoding* encoding = nullptr;
134 if (SVGUseElement* use = aContent->GetContainingSVGUseShadowHost()) {
135 base = use->GetSourceDocURI();
136 encoding = use->GetSourceDocCharacterSet();
139 if (!base) {
140 base = aContent->OwnerDoc()->GetDocumentURI();
141 encoding = aContent->OwnerDoc()->GetDocumentCharacterSet();
144 nsCOMPtr<nsIURI> uri;
145 Unused << NS_NewURI(getter_AddRefs(uri), aURL, WrapNotNull(encoding), base);
147 if (!uri) {
148 return nullptr;
151 RefPtr<URLAndReferrerInfo> info = new URLAndReferrerInfo(uri, aReferrerInfo);
152 return info.forget();
155 static already_AddRefed<URLAndReferrerInfo> ResolveURLUsingLocalRef(
156 nsIFrame* aFrame, const nsAString& aURL, nsIReferrerInfo* aReferrerInfo) {
157 MOZ_ASSERT(aFrame);
159 return ResolveURLUsingLocalRef(aFrame->GetContent(), aURL, aReferrerInfo);
162 class SVGFilterObserverList;
165 * A class used as a member of the "observer" classes below to help them
166 * avoid dereferencing their frame during presshell teardown when their frame
167 * may have been destroyed (leaving their pointer to their frame dangling).
169 * When a presshell is torn down, the properties for each frame may not be
170 * deleted until after the frames are destroyed. "Observer" objects (attached
171 * as frame properties) must therefore check whether the presshell is being
172 * torn down before using their pointer to their frame.
174 * mFramePresShell may be null, but when mFrame is non-null, mFramePresShell
175 * is guaranteed to be non-null, too.
177 struct SVGFrameReferenceFromProperty {
178 explicit SVGFrameReferenceFromProperty(nsIFrame* aFrame)
179 : mFrame(aFrame), mFramePresShell(aFrame->PresShell()) {}
181 // Clear our reference to the frame.
182 void Detach() {
183 mFrame = nullptr;
184 mFramePresShell = nullptr;
187 // null if the frame has become invalid
188 nsIFrame* Get() {
189 if (mFramePresShell && mFramePresShell->IsDestroying()) {
190 Detach(); // mFrame is no longer valid.
192 return mFrame;
195 private:
196 // The frame that our property is attached to (may be null).
197 nsIFrame* mFrame;
198 PresShell* mFramePresShell;
201 void SVGRenderingObserver::StartObserving() {
202 Element* target = GetReferencedElementWithoutObserving();
203 if (target) {
204 target->AddMutationObserver(this);
208 void SVGRenderingObserver::StopObserving() {
209 Element* target = GetReferencedElementWithoutObserving();
211 if (target) {
212 target->RemoveMutationObserver(this);
213 if (mInObserverSet) {
214 SVGObserverUtils::RemoveRenderingObserver(target, this);
215 mInObserverSet = false;
218 NS_ASSERTION(!mInObserverSet, "still in an observer set?");
221 Element* SVGRenderingObserver::GetAndObserveReferencedElement() {
222 #ifdef DEBUG
223 DebugObserverSet();
224 #endif
225 Element* referencedElement = GetReferencedElementWithoutObserving();
226 if (referencedElement && !mInObserverSet) {
227 SVGObserverUtils::AddRenderingObserver(referencedElement, this);
228 mInObserverSet = true;
230 return referencedElement;
233 nsIFrame* SVGRenderingObserver::GetAndObserveReferencedFrame() {
234 Element* referencedElement = GetAndObserveReferencedElement();
235 return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr;
238 nsIFrame* SVGRenderingObserver::GetAndObserveReferencedFrame(
239 LayoutFrameType aFrameType, bool* aOK) {
240 nsIFrame* frame = GetAndObserveReferencedFrame();
241 if (frame) {
242 if (frame->Type() == aFrameType) {
243 return frame;
245 if (aOK) {
246 *aOK = false;
249 return nullptr;
252 void SVGRenderingObserver::OnNonDOMMutationRenderingChange() {
253 mInObserverSet = false;
254 OnRenderingChange();
257 void SVGRenderingObserver::NotifyEvictedFromRenderingObserverSet() {
258 mInObserverSet = false; // We've been removed from rendering-obs. set.
259 StopObserving(); // Stop observing mutations too.
262 void SVGRenderingObserver::AttributeChanged(dom::Element* aElement,
263 int32_t aNameSpaceID,
264 nsAtom* aAttribute,
265 int32_t aModType,
266 const nsAttrValue* aOldValue) {
267 if (aElement->IsInNativeAnonymousSubtree()) {
268 // Don't observe attribute changes in native-anonymous subtrees like
269 // scrollbars.
270 return;
273 // An attribute belonging to the element that we are observing *or one of its
274 // descendants* has changed.
276 // In the case of observing a gradient element, say, we want to know if any
277 // of its 'stop' element children change, but we don't actually want to do
278 // anything for changes to SMIL element children, for example. Maybe it's not
279 // worth having logic to optimize for that, but in most cases it could be a
280 // small check?
282 // XXXjwatt: do we really want to blindly break the link between our
283 // observers and ourselves for all attribute changes? For non-ID changes
284 // surely that is unnecessary.
286 if (mFlags & OBSERVE_ATTRIBUTE_CHANGES) {
287 OnRenderingChange();
291 void SVGRenderingObserver::ContentAppended(nsIContent* aFirstNewContent) {
292 if (mFlags & OBSERVE_CONTENT_CHANGES) {
293 OnRenderingChange();
297 void SVGRenderingObserver::ContentInserted(nsIContent* aChild) {
298 if (mFlags & OBSERVE_CONTENT_CHANGES) {
299 OnRenderingChange();
303 void SVGRenderingObserver::ContentRemoved(nsIContent* aChild,
304 nsIContent* aPreviousSibling) {
305 if (mFlags & OBSERVE_CONTENT_CHANGES) {
306 OnRenderingChange();
311 * SVG elements reference supporting resources by element ID. We need to
312 * track when those resources change and when the document changes in ways
313 * that affect which element is referenced by a given ID (e.g., when
314 * element IDs change). The code here is responsible for that.
316 * When a frame references a supporting resource, we create a property
317 * object derived from SVGIDRenderingObserver to manage the relationship. The
318 * property object is attached to the referencing frame.
320 class SVGIDRenderingObserver : public SVGRenderingObserver {
321 public:
322 // Callback for checking if the element being observed is valid for this
323 // observer. Note that this may be called during construction, before the
324 // deriving class is fully constructed.
325 using TargetIsValidCallback = bool (*)(const Element&);
326 SVGIDRenderingObserver(
327 URLAndReferrerInfo* aURI, nsIContent* aObservingContent,
328 bool aReferenceImage,
329 uint32_t aFlags = OBSERVE_ATTRIBUTE_CHANGES | OBSERVE_CONTENT_CHANGES,
330 TargetIsValidCallback aTargetIsValidCallback = nullptr);
332 void Traverse(nsCycleCollectionTraversalCallback* aCB);
334 protected:
335 virtual ~SVGIDRenderingObserver() {
336 // This needs to call our GetReferencedElementWithoutObserving override,
337 // so must be called here rather than in our base class's dtor.
338 StopObserving();
341 void TargetChanged() {
342 mTargetIsValid = ([this] {
343 Element* observed = mObservedElementTracker.get();
344 if (!observed) {
345 return false;
347 // If the content is observing an ancestor, then return the target is not
348 // valid.
350 // TODO(emilio): Should we allow content observing its own descendants?
351 // That seems potentially-bad as well.
352 if (observed->OwnerDoc() == mObservingContent->OwnerDoc() &&
353 nsContentUtils::ContentIsHostIncludingDescendantOf(mObservingContent,
354 observed)) {
355 return false;
357 if (mTargetIsValidCallback) {
358 return mTargetIsValidCallback(*observed);
360 return true;
361 }());
364 Element* GetReferencedElementWithoutObserving() final {
365 return mTargetIsValid ? mObservedElementTracker.get() : nullptr;
368 void OnRenderingChange() override;
371 * Helper that provides a reference to the element with the ID that our
372 * observer wants to observe, and that will invalidate our observer if the
373 * element that that ID identifies changes to a different element (or none).
375 class ElementTracker final : public IDTracker {
376 public:
377 explicit ElementTracker(SVGIDRenderingObserver* aOwningObserver)
378 : mOwningObserver(aOwningObserver) {}
380 protected:
381 void ElementChanged(Element* aFrom, Element* aTo) override {
382 // Call OnRenderingChange() before the target changes, so that
383 // mIsTargetValid reflects the right state.
384 mOwningObserver->OnRenderingChange();
385 mOwningObserver->StopObserving();
386 IDTracker::ElementChanged(aFrom, aTo);
387 mOwningObserver->TargetChanged();
388 mOwningObserver->StartObserving();
389 // And same after the target changes, for the same reason.
390 mOwningObserver->OnRenderingChange();
393 * Override IsPersistent because we want to keep tracking the element
394 * for the ID even when it changes.
396 bool IsPersistent() override { return true; }
398 private:
399 SVGIDRenderingObserver* mOwningObserver;
402 ElementTracker mObservedElementTracker;
403 RefPtr<Element> mObservingContent;
404 bool mTargetIsValid = false;
405 TargetIsValidCallback mTargetIsValidCallback;
409 * Note that in the current setup there are two separate observer lists.
411 * In SVGIDRenderingObserver's ctor, the new object adds itself to the
412 * mutation observer list maintained by the referenced element. In this way the
413 * SVGIDRenderingObserver is notified if there are any attribute or content
414 * tree changes to the element or any of its *descendants*.
416 * In SVGIDRenderingObserver::GetAndObserveReferencedElement() the
417 * SVGIDRenderingObserver object also adds itself to an
418 * SVGRenderingObserverSet object belonging to the referenced
419 * element.
421 * XXX: it would be nice to have a clear and concise executive summary of the
422 * benefits/necessity of maintaining a second observer list.
424 SVGIDRenderingObserver::SVGIDRenderingObserver(
425 URLAndReferrerInfo* aURI, nsIContent* aObservingContent,
426 bool aReferenceImage, uint32_t aFlags,
427 TargetIsValidCallback aTargetIsValidCallback)
428 : SVGRenderingObserver(aFlags),
429 mObservedElementTracker(this),
430 mObservingContent(aObservingContent->AsElement()),
431 mTargetIsValidCallback(aTargetIsValidCallback) {
432 // Start watching the target element
433 nsIURI* uri = nullptr;
434 nsIReferrerInfo* referrerInfo = nullptr;
435 if (aURI) {
436 uri = aURI->GetURI();
437 referrerInfo = aURI->GetReferrerInfo();
440 mObservedElementTracker.ResetToURIFragmentID(
441 aObservingContent, uri, referrerInfo, true, aReferenceImage);
442 TargetChanged();
443 StartObserving();
446 void SVGIDRenderingObserver::Traverse(nsCycleCollectionTraversalCallback* aCB) {
447 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mObservingContent");
448 aCB->NoteXPCOMChild(mObservingContent);
449 mObservedElementTracker.Traverse(aCB);
452 void SVGIDRenderingObserver::OnRenderingChange() {
453 if (mObservedElementTracker.get() && mInObserverSet) {
454 SVGObserverUtils::RemoveRenderingObserver(mObservedElementTracker.get(),
455 this);
456 mInObserverSet = false;
460 class SVGRenderingObserverProperty : public SVGIDRenderingObserver {
461 public:
462 NS_DECL_ISUPPORTS
464 SVGRenderingObserverProperty(
465 URLAndReferrerInfo* aURI, nsIFrame* aFrame, bool aReferenceImage,
466 uint32_t aFlags = OBSERVE_ATTRIBUTE_CHANGES | OBSERVE_CONTENT_CHANGES,
467 TargetIsValidCallback aTargetIsValidCallback = nullptr)
468 : SVGIDRenderingObserver(aURI, aFrame->GetContent(), aReferenceImage,
469 aFlags, aTargetIsValidCallback),
470 mFrameReference(aFrame) {}
472 protected:
473 virtual ~SVGRenderingObserverProperty() = default; // non-public
475 void OnRenderingChange() override;
477 SVGFrameReferenceFromProperty mFrameReference;
480 NS_IMPL_ISUPPORTS(SVGRenderingObserverProperty, nsIMutationObserver)
482 void SVGRenderingObserverProperty::OnRenderingChange() {
483 SVGIDRenderingObserver::OnRenderingChange();
485 if (!mTargetIsValid) {
486 return;
489 nsIFrame* frame = mFrameReference.Get();
491 if (frame && frame->HasAllStateBits(NS_FRAME_SVG_LAYOUT)) {
492 // We need to notify anything that is observing the referencing frame or
493 // any of its ancestors that the referencing frame has been invalidated.
494 // Since walking the parent chain checking for observers is expensive we
495 // do that using a change hint (multiple change hints of the same type are
496 // coalesced).
497 nsLayoutUtils::PostRestyleEvent(frame->GetContent()->AsElement(),
498 RestyleHint{0},
499 nsChangeHint_InvalidateRenderingObservers);
503 static bool IsSVGGeometryElement(const Element& aObserved) {
504 return aObserved.IsSVGGeometryElement();
507 class SVGTextPathObserver final : public SVGRenderingObserverProperty {
508 public:
509 SVGTextPathObserver(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
510 bool aReferenceImage)
511 : SVGRenderingObserverProperty(aURI, aFrame, aReferenceImage,
512 OBSERVE_ATTRIBUTE_CHANGES,
513 IsSVGGeometryElement) {}
515 protected:
516 void OnRenderingChange() override;
519 void SVGTextPathObserver::OnRenderingChange() {
520 SVGRenderingObserverProperty::OnRenderingChange();
522 if (!mTargetIsValid) {
523 return;
526 nsIFrame* frame = mFrameReference.Get();
527 if (!frame) {
528 return;
531 MOZ_ASSERT(
532 frame->IsFrameOfType(nsIFrame::eSVG) || frame->IsInSVGTextSubtree(),
533 "SVG frame expected");
535 MOZ_ASSERT(frame->GetContent()->IsSVGElement(nsGkAtoms::textPath),
536 "expected frame for a <textPath> element");
538 auto* text = static_cast<SVGTextFrame*>(
539 nsLayoutUtils::GetClosestFrameOfType(frame, LayoutFrameType::SVGText));
540 MOZ_ASSERT(text, "expected to find an ancestor SVGTextFrame");
541 if (text) {
542 text->AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
544 if (SVGUtils::AnyOuterSVGIsCallingReflowSVG(text)) {
545 text->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
546 if (text->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
547 text->ReflowSVGNonDisplayText();
548 } else {
549 text->ReflowSVG();
551 } else {
552 text->ScheduleReflowSVG();
557 class SVGMPathObserver final : public SVGIDRenderingObserver {
558 public:
559 NS_DECL_ISUPPORTS
561 SVGMPathObserver(URLAndReferrerInfo* aURI, SVGMPathElement* aElement)
562 : SVGIDRenderingObserver(aURI, aElement, /* aReferenceImage = */ false,
563 OBSERVE_ATTRIBUTE_CHANGES,
564 IsSVGGeometryElement) {}
566 protected:
567 virtual ~SVGMPathObserver() = default; // non-public
569 void OnRenderingChange() override;
572 NS_IMPL_ISUPPORTS(SVGMPathObserver, nsIMutationObserver)
574 void SVGMPathObserver::OnRenderingChange() {
575 SVGIDRenderingObserver::OnRenderingChange();
577 if (!mTargetIsValid) {
578 return;
581 auto* element = static_cast<SVGMPathElement*>(mObservingContent.get());
582 element->NotifyParentOfMpathChange();
585 class SVGMarkerObserver final : public SVGRenderingObserverProperty {
586 public:
587 SVGMarkerObserver(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
588 bool aReferenceImage)
589 : SVGRenderingObserverProperty(
590 aURI, aFrame, aReferenceImage,
591 OBSERVE_ATTRIBUTE_CHANGES | OBSERVE_CONTENT_CHANGES) {}
593 protected:
594 void OnRenderingChange() override;
597 void SVGMarkerObserver::OnRenderingChange() {
598 SVGRenderingObserverProperty::OnRenderingChange();
600 nsIFrame* frame = mFrameReference.Get();
601 if (!frame) {
602 return;
605 MOZ_ASSERT(frame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
607 // Don't need to request ReflowFrame if we're being reflowed.
608 // Because mRect for SVG frames includes the bounds of any markers
609 // (see the comment for nsIFrame::GetRect), the referencing frame must be
610 // reflowed for any marker changes.
611 if (!frame->HasAnyStateBits(NS_FRAME_IN_REFLOW)) {
612 // XXXjwatt: We need to unify SVG into standard reflow so we can just use
613 // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
614 // XXXSDL KILL THIS!!!
615 SVGUtils::ScheduleReflowSVG(frame);
617 frame->PresContext()->RestyleManager()->PostRestyleEvent(
618 frame->GetContent()->AsElement(), RestyleHint{0},
619 nsChangeHint_RepaintFrame);
622 class SVGPaintingProperty : public SVGRenderingObserverProperty {
623 public:
624 SVGPaintingProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
625 bool aReferenceImage)
626 : SVGRenderingObserverProperty(aURI, aFrame, aReferenceImage) {}
628 protected:
629 void OnRenderingChange() override;
632 void SVGPaintingProperty::OnRenderingChange() {
633 SVGRenderingObserverProperty::OnRenderingChange();
635 nsIFrame* frame = mFrameReference.Get();
636 if (!frame) {
637 return;
640 if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
641 frame->InvalidateFrameSubtree();
642 } else {
643 for (nsIFrame* f = frame; f;
644 f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
645 f->InvalidateFrame();
650 // Observer for -moz-element(#element). Note that the observed element does not
651 // have to be an SVG element.
652 class SVGMozElementObserver final : public SVGPaintingProperty {
653 public:
654 SVGMozElementObserver(URLAndReferrerInfo* aURI, nsIFrame* aFrame)
655 : SVGPaintingProperty(aURI, aFrame, /* aReferenceImage = */ true) {}
657 // We only return true here because GetAndObserveBackgroundImage uses us
658 // to implement observing of arbitrary elements (including HTML elements)
659 // that may require us to repaint if the referenced element is reflowed.
660 // Bug 1496065 has been filed to remove that support though.
661 bool ObservesReflow() override { return true; }
665 * For content with `background-clip: text`.
667 * This observer is unusual in that the observing frame and observed frame are
668 * the same frame. This is because the observing frame is observing for reflow
669 * of its descendant text nodes, since such reflows may not result in the
670 * frame's nsDisplayBackground changing. In other words, Display List Based
671 * Invalidation may not invalidate the frame's background, so we need this
672 * observer to make sure that happens.
674 * XXX: It's questionable whether we should even be [ab]using the SVG observer
675 * mechanism for `background-clip:text`. Since we know that the observed frame
676 * is the frame we need to invalidate, we could just check the computed style
677 * in the (one) place where we pass INVALIDATE_REFLOW and invalidate there...
679 class BackgroundClipRenderingObserver : public SVGRenderingObserver {
680 public:
681 explicit BackgroundClipRenderingObserver(nsIFrame* aFrame) : mFrame(aFrame) {}
683 NS_DECL_ISUPPORTS
685 private:
686 // We do not call StopObserving() since the observing and observed element
687 // are the same element (and because we could crash - see bug 1556441).
688 virtual ~BackgroundClipRenderingObserver() = default;
690 Element* GetReferencedElementWithoutObserving() final {
691 return mFrame->GetContent()->AsElement();
694 void OnRenderingChange() final;
697 * Observing for mutations is not enough. A new font loading and applying
698 * to the text content could cause it to reflow, and we need to invalidate
699 * for that.
701 bool ObservesReflow() final { return true; }
703 // The observer and observee!
704 nsIFrame* mFrame;
707 NS_IMPL_ISUPPORTS(BackgroundClipRenderingObserver, nsIMutationObserver)
709 void BackgroundClipRenderingObserver::OnRenderingChange() {
710 for (nsIFrame* f = mFrame; f;
711 f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
712 f->InvalidateFrame();
716 static bool IsSVGFilterElement(const Element& aObserved) {
717 return aObserved.IsSVGElement(nsGkAtoms::filter);
721 * In a filter chain, there can be multiple SVG reference filters.
722 * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
724 * This class keeps track of one SVG reference filter in a filter chain.
725 * e.g. url(#svg-filter-1)
727 * It fires invalidations when the SVG filter element's id changes or when
728 * the SVG filter element's content changes.
730 * The SVGFilterObserverList class manages a list of SVGFilterObservers.
732 class SVGFilterObserver final : public SVGIDRenderingObserver {
733 public:
734 SVGFilterObserver(URLAndReferrerInfo* aURI, nsIContent* aObservingContent,
735 SVGFilterObserverList* aFilterChainObserver)
736 : SVGIDRenderingObserver(
737 aURI, aObservingContent, false,
738 OBSERVE_ATTRIBUTE_CHANGES | OBSERVE_CONTENT_CHANGES,
739 IsSVGFilterElement),
740 mFilterObserverList(aFilterChainObserver) {}
742 void DetachFromChainObserver() { mFilterObserverList = nullptr; }
745 * @return the filter frame, or null if there is no filter frame
747 SVGFilterFrame* GetAndObserveFilterFrame();
749 // nsISupports
750 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
751 NS_DECL_CYCLE_COLLECTION_CLASS(SVGFilterObserver)
753 // SVGIDRenderingObserver
754 void OnRenderingChange() override;
756 protected:
757 virtual ~SVGFilterObserver() = default; // non-public
759 SVGFilterObserverList* mFilterObserverList;
762 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGFilterObserver)
763 NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGFilterObserver)
765 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGFilterObserver)
766 NS_INTERFACE_MAP_ENTRY(nsISupports)
767 NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
768 NS_INTERFACE_MAP_END
770 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGFilterObserver)
772 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SVGFilterObserver)
773 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservedElementTracker)
774 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservingContent)
775 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
777 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SVGFilterObserver)
778 tmp->StopObserving();
779 NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservedElementTracker);
780 NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservingContent)
781 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
783 SVGFilterFrame* SVGFilterObserver::GetAndObserveFilterFrame() {
784 return static_cast<SVGFilterFrame*>(
785 GetAndObserveReferencedFrame(LayoutFrameType::SVGFilter, nullptr));
789 * This class manages a list of SVGFilterObservers, which correspond to
790 * reference to SVG filters in a list of filters in a given 'filter' property.
791 * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
793 * In the above example, the SVGFilterObserverList will manage two
794 * SVGFilterObservers, one for each of the references to SVG filters. CSS
795 * filters like "blur(10px)" don't reference filter elements, so they don't
796 * need an SVGFilterObserver. The style system invalidates changes to CSS
797 * filters.
799 * FIXME(emilio): Why do we need this as opposed to the individual observers we
800 * create in the constructor?
802 class SVGFilterObserverList : public nsISupports {
803 public:
804 SVGFilterObserverList(Span<const StyleFilter> aFilters,
805 nsIContent* aFilteredElement,
806 nsIFrame* aFilteredFrame = nullptr);
808 const nsTArray<RefPtr<SVGFilterObserver>>& GetObservers() const {
809 return mObservers;
812 // nsISupports
813 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
814 NS_DECL_CYCLE_COLLECTION_CLASS(SVGFilterObserverList)
816 virtual void OnRenderingChange() = 0;
818 protected:
819 virtual ~SVGFilterObserverList();
821 void DetachObservers() {
822 for (auto& observer : mObservers) {
823 observer->DetachFromChainObserver();
827 nsTArray<RefPtr<SVGFilterObserver>> mObservers;
830 void SVGFilterObserver::OnRenderingChange() {
831 SVGIDRenderingObserver::OnRenderingChange();
833 if (mFilterObserverList) {
834 mFilterObserverList->OnRenderingChange();
837 if (!mTargetIsValid) {
838 return;
841 nsIFrame* frame = mObservingContent->GetPrimaryFrame();
842 if (!frame) {
843 return;
846 // Repaint asynchronously in case the filter frame is being torn down
847 nsChangeHint changeHint = nsChangeHint(nsChangeHint_RepaintFrame);
849 // Since we don't call SVGRenderingObserverProperty::
850 // OnRenderingChange, we have to add this bit ourselves.
851 if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
852 // Changes should propagate out to things that might be observing
853 // the referencing frame or its ancestors.
854 changeHint |= nsChangeHint_InvalidateRenderingObservers;
857 // Don't need to request UpdateOverflow if we're being reflowed.
858 if (!frame->HasAnyStateBits(NS_FRAME_IN_REFLOW)) {
859 changeHint |= nsChangeHint_UpdateOverflow;
861 frame->PresContext()->RestyleManager()->PostRestyleEvent(
862 mObservingContent, RestyleHint{0}, changeHint);
865 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGFilterObserverList)
866 NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGFilterObserverList)
868 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGFilterObserverList)
870 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SVGFilterObserverList)
871 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
872 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
874 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SVGFilterObserverList)
875 tmp->DetachObservers();
876 NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers);
877 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
879 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGFilterObserverList)
880 NS_INTERFACE_MAP_ENTRY(nsISupports)
881 NS_INTERFACE_MAP_END
883 SVGFilterObserverList::SVGFilterObserverList(Span<const StyleFilter> aFilters,
884 nsIContent* aFilteredElement,
885 nsIFrame* aFilteredFrame) {
886 for (const auto& filter : aFilters) {
887 if (!filter.IsUrl()) {
888 continue;
891 const auto& url = filter.AsUrl();
893 // aFilteredFrame can be null if this filter belongs to a
894 // CanvasRenderingContext2D.
895 RefPtr<URLAndReferrerInfo> filterURL;
896 if (aFilteredFrame) {
897 filterURL = ResolveURLUsingLocalRef(aFilteredFrame, url);
898 } else {
899 nsCOMPtr<nsIURI> resolvedURI = url.ResolveLocalRef(aFilteredElement);
900 if (resolvedURI) {
901 filterURL = new URLAndReferrerInfo(resolvedURI, url.ExtraData());
905 RefPtr<SVGFilterObserver> observer =
906 new SVGFilterObserver(filterURL, aFilteredElement, this);
907 mObservers.AppendElement(observer);
911 SVGFilterObserverList::~SVGFilterObserverList() { DetachObservers(); }
913 class SVGFilterObserverListForCSSProp final : public SVGFilterObserverList {
914 public:
915 SVGFilterObserverListForCSSProp(Span<const StyleFilter> aFilters,
916 nsIFrame* aFilteredFrame)
917 : SVGFilterObserverList(aFilters, aFilteredFrame->GetContent(),
918 aFilteredFrame) {}
920 protected:
921 void OnRenderingChange() override;
922 bool mInvalidating = false;
925 void SVGFilterObserverListForCSSProp::OnRenderingChange() {
926 if (mInvalidating) {
927 return;
929 AutoRestore<bool> guard(mInvalidating);
930 mInvalidating = true;
931 for (auto& observer : mObservers) {
932 observer->OnRenderingChange();
936 class SVGFilterObserverListForCanvasContext final
937 : public SVGFilterObserverList {
938 public:
939 SVGFilterObserverListForCanvasContext(CanvasRenderingContext2D* aContext,
940 Element* aCanvasElement,
941 Span<const StyleFilter> aFilters)
942 : SVGFilterObserverList(aFilters, aCanvasElement), mContext(aContext) {}
944 void OnRenderingChange() override;
945 void DetachFromContext() { mContext = nullptr; }
947 private:
948 CanvasRenderingContext2D* mContext;
951 void SVGFilterObserverListForCanvasContext::OnRenderingChange() {
952 if (!mContext) {
953 NS_WARNING(
954 "GFX: This should never be called without a context, except during "
955 "cycle collection (when DetachFromContext has been called)");
956 return;
958 // Refresh the cached FilterDescription in mContext->CurrentState().filter.
959 // If this filter is not at the top of the state stack, we'll refresh the
960 // wrong filter, but that's ok, because we'll refresh the right filter
961 // when we pop the state stack in CanvasRenderingContext2D::Restore().
962 RefPtr<CanvasRenderingContext2D> kungFuDeathGrip(mContext);
963 kungFuDeathGrip->UpdateFilter();
966 class SVGMaskObserverList final : public nsISupports {
967 public:
968 explicit SVGMaskObserverList(nsIFrame* aFrame);
970 // nsISupports
971 NS_DECL_ISUPPORTS
973 const nsTArray<RefPtr<SVGPaintingProperty>>& GetObservers() const {
974 return mProperties;
977 void ResolveImage(uint32_t aIndex);
979 private:
980 virtual ~SVGMaskObserverList() = default; // non-public
981 nsTArray<RefPtr<SVGPaintingProperty>> mProperties;
982 nsIFrame* mFrame;
985 NS_IMPL_ISUPPORTS(SVGMaskObserverList, nsISupports)
987 SVGMaskObserverList::SVGMaskObserverList(nsIFrame* aFrame) : mFrame(aFrame) {
988 const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
990 for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
991 const StyleComputedImageUrl* data =
992 svgReset->mMask.mLayers[i].mImage.GetImageRequestURLValue();
993 RefPtr<URLAndReferrerInfo> maskUri;
994 if (data) {
995 maskUri = ResolveURLUsingLocalRef(aFrame, *data);
998 bool hasRef = false;
999 if (maskUri) {
1000 maskUri->GetURI()->GetHasRef(&hasRef);
1003 // Accrording to maskUri, SVGPaintingProperty's ctor may trigger an
1004 // external SVG resource download, so we should pass maskUri in only if
1005 // maskUri has a chance pointing to an SVG mask resource.
1007 // And, an URL may refer to an SVG mask resource if it consists of
1008 // a fragment.
1009 SVGPaintingProperty* prop = new SVGPaintingProperty(
1010 hasRef ? maskUri.get() : nullptr, aFrame, false);
1011 mProperties.AppendElement(prop);
1015 void SVGMaskObserverList::ResolveImage(uint32_t aIndex) {
1016 const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset();
1017 MOZ_ASSERT(aIndex < svgReset->mMask.mImageCount);
1019 auto& image = const_cast<StyleImage&>(svgReset->mMask.mLayers[aIndex].mImage);
1020 if (image.IsResolved()) {
1021 return;
1023 MOZ_ASSERT(image.IsImageRequestType());
1024 Document* doc = mFrame->PresContext()->Document();
1025 image.ResolveImage(*doc, nullptr);
1026 if (imgRequestProxy* req = image.GetImageRequest()) {
1027 // FIXME(emilio): What disassociates this request?
1028 doc->StyleImageLoader()->AssociateRequestToFrame(req, mFrame);
1033 * Used for gradient-to-gradient, pattern-to-pattern and filter-to-filter
1034 * references to "template" elements (specified via the 'href' attributes).
1036 class SVGTemplateElementObserver : public SVGIDRenderingObserver {
1037 public:
1038 NS_DECL_ISUPPORTS
1040 SVGTemplateElementObserver(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
1041 bool aReferenceImage)
1042 : SVGIDRenderingObserver(
1043 aURI, aFrame->GetContent(), aReferenceImage,
1044 OBSERVE_ATTRIBUTE_CHANGES | OBSERVE_CONTENT_CHANGES),
1045 mFrameReference(aFrame) {}
1047 protected:
1048 virtual ~SVGTemplateElementObserver() = default; // non-public
1050 void OnRenderingChange() override;
1052 SVGFrameReferenceFromProperty mFrameReference;
1055 NS_IMPL_ISUPPORTS(SVGTemplateElementObserver, nsIMutationObserver)
1057 void SVGTemplateElementObserver::OnRenderingChange() {
1058 SVGIDRenderingObserver::OnRenderingChange();
1060 if (nsIFrame* frame = mFrameReference.Get()) {
1061 SVGObserverUtils::InvalidateRenderingObservers(frame);
1066 * An instance of this class is stored on an observed frame (as a frame
1067 * property) whenever the frame has active rendering observers. It is used to
1068 * store pointers to the SVGRenderingObserver instances belonging to any
1069 * observing frames, allowing invalidations from the observed frame to be sent
1070 * to all observing frames.
1072 * SVGRenderingObserver instances that are added are not strongly referenced,
1073 * so they must remove themselves before they die.
1075 * This class is "single-shot", which is to say that when something about the
1076 * observed element changes, InvalidateAll() clears our hashtable of
1077 * SVGRenderingObservers. SVGRenderingObserver objects will be added back
1078 * again if/when the observing frame looks up our observed frame to use it.
1080 * XXXjwatt: is this the best thing to do nowadays? Back when that mechanism
1081 * landed in bug 330498 we had two pass, recursive invalidation up the frame
1082 * tree, and I think reference loops were a problem. Nowadays maybe a flag
1083 * on the SVGRenderingObserver objects to coalesce invalidations may work
1084 * better?
1086 * InvalidateAll must be called before this object is destroyed, i.e.
1087 * before the referenced frame is destroyed. This should normally happen
1088 * via SVGContainerFrame::RemoveFrame, since only frames in the frame
1089 * tree should be referenced.
1091 class SVGRenderingObserverSet {
1092 public:
1093 SVGRenderingObserverSet() : mObservers(4) {
1094 MOZ_COUNT_CTOR(SVGRenderingObserverSet);
1097 ~SVGRenderingObserverSet() {
1098 InvalidateAll();
1099 MOZ_COUNT_DTOR(SVGRenderingObserverSet);
1102 void Add(SVGRenderingObserver* aObserver) { mObservers.Insert(aObserver); }
1103 void Remove(SVGRenderingObserver* aObserver) { mObservers.Remove(aObserver); }
1104 #ifdef DEBUG
1105 bool Contains(SVGRenderingObserver* aObserver) {
1106 return mObservers.Contains(aObserver);
1108 #endif
1109 bool IsEmpty() { return mObservers.IsEmpty(); }
1112 * Drop all our observers, and notify them that we have changed and dropped
1113 * our reference to them.
1115 void InvalidateAll();
1118 * Drop all observers that observe reflow, and notify them that we have
1119 * changed and dropped our reference to them.
1121 void InvalidateAllForReflow();
1124 * Drop all our observers, and notify them that we have dropped our reference
1125 * to them.
1127 void RemoveAll();
1129 private:
1130 nsTHashSet<SVGRenderingObserver*> mObservers;
1133 void SVGRenderingObserverSet::InvalidateAll() {
1134 if (mObservers.IsEmpty()) {
1135 return;
1138 const auto observers = std::move(mObservers);
1140 for (const auto& observer : observers) {
1141 observer->OnNonDOMMutationRenderingChange();
1145 void SVGRenderingObserverSet::InvalidateAllForReflow() {
1146 if (mObservers.IsEmpty()) {
1147 return;
1150 AutoTArray<SVGRenderingObserver*, 10> observers;
1152 for (auto it = mObservers.cbegin(), end = mObservers.cend(); it != end;
1153 ++it) {
1154 SVGRenderingObserver* obs = *it;
1155 if (obs->ObservesReflow()) {
1156 observers.AppendElement(obs);
1157 mObservers.Remove(it);
1161 for (uint32_t i = 0; i < observers.Length(); ++i) {
1162 observers[i]->OnNonDOMMutationRenderingChange();
1166 void SVGRenderingObserverSet::RemoveAll() {
1167 const auto observers = std::move(mObservers);
1169 // Our list is now cleared. We need to notify the observers we've removed,
1170 // so they can update their state & remove themselves as mutation-observers.
1171 for (const auto& observer : observers) {
1172 observer->NotifyEvictedFromRenderingObserverSet();
1176 static SVGRenderingObserverSet* GetObserverSet(Element* aElement) {
1177 return static_cast<SVGRenderingObserverSet*>(
1178 aElement->GetProperty(nsGkAtoms::renderingobserverset));
1181 #ifdef DEBUG
1182 // Defined down here because we need SVGRenderingObserverSet's definition.
1183 void SVGRenderingObserver::DebugObserverSet() {
1184 Element* referencedElement = GetReferencedElementWithoutObserving();
1185 if (referencedElement) {
1186 SVGRenderingObserverSet* observers = GetObserverSet(referencedElement);
1187 bool inObserverSet = observers && observers->Contains(this);
1188 MOZ_ASSERT(inObserverSet == mInObserverSet,
1189 "failed to track whether we're in our referenced element's "
1190 "observer set!");
1191 } else {
1192 MOZ_ASSERT(!mInObserverSet, "In whose observer set are we, then?");
1195 #endif
1197 using URIObserverHashtable =
1198 nsInterfaceHashtable<URLAndReferrerInfoHashKey, nsIMutationObserver>;
1200 using PaintingPropertyDescriptor =
1201 const FramePropertyDescriptor<SVGPaintingProperty>*;
1203 static void DestroyFilterProperty(SVGFilterObserverListForCSSProp* aProp) {
1204 aProp->Release();
1207 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefToTemplateProperty,
1208 SVGTemplateElementObserver)
1209 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(FilterProperty,
1210 SVGFilterObserverListForCSSProp,
1211 DestroyFilterProperty)
1212 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MaskProperty, SVGMaskObserverList)
1213 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(ClipPathProperty, SVGPaintingProperty)
1214 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerStartProperty, SVGMarkerObserver)
1215 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerMidProperty, SVGMarkerObserver)
1216 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerEndProperty, SVGMarkerObserver)
1217 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(FillProperty, SVGPaintingProperty)
1218 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(StrokeProperty, SVGPaintingProperty)
1219 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefAsTextPathProperty,
1220 SVGTextPathObserver)
1221 NS_DECLARE_FRAME_PROPERTY_DELETABLE(BackgroundImageProperty,
1222 URIObserverHashtable)
1223 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(BackgroundClipObserverProperty,
1224 BackgroundClipRenderingObserver)
1225 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(OffsetPathProperty,
1226 SVGRenderingObserverProperty)
1228 template <class T>
1229 static T* GetEffectProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
1230 const FramePropertyDescriptor<T>* aProperty) {
1231 if (!aURI) {
1232 return nullptr;
1235 bool found;
1236 T* prop = aFrame->GetProperty(aProperty, &found);
1237 if (found) {
1238 MOZ_ASSERT(prop, "this property should only store non-null values");
1239 return prop;
1241 prop = new T(aURI, aFrame, false);
1242 NS_ADDREF(prop);
1243 aFrame->AddProperty(aProperty, prop);
1244 return prop;
1247 static SVGPaintingProperty* GetPaintingProperty(
1248 URLAndReferrerInfo* aURI, nsIFrame* aFrame,
1249 const FramePropertyDescriptor<SVGPaintingProperty>* aProperty) {
1250 return GetEffectProperty(aURI, aFrame, aProperty);
1253 static already_AddRefed<URLAndReferrerInfo> GetMarkerURI(
1254 nsIFrame* aFrame, const StyleUrlOrNone nsStyleSVG::*aMarker) {
1255 const StyleUrlOrNone& url = aFrame->StyleSVG()->*aMarker;
1256 if (url.IsNone()) {
1257 return nullptr;
1259 return ResolveURLUsingLocalRef(aFrame, url.AsUrl());
1262 bool SVGObserverUtils::GetAndObserveMarkers(nsIFrame* aMarkedFrame,
1263 SVGMarkerFrame* (*aFrames)[3]) {
1264 MOZ_ASSERT(!aMarkedFrame->GetPrevContinuation() &&
1265 aMarkedFrame->IsSVGGeometryFrame() &&
1266 static_cast<SVGGeometryElement*>(aMarkedFrame->GetContent())
1267 ->IsMarkable(),
1268 "Bad frame");
1270 bool foundMarker = false;
1271 RefPtr<URLAndReferrerInfo> markerURL;
1272 SVGMarkerObserver* observer;
1273 nsIFrame* marker;
1275 #define GET_MARKER(type) \
1276 markerURL = GetMarkerURI(aMarkedFrame, &nsStyleSVG::mMarker##type); \
1277 observer = \
1278 GetEffectProperty(markerURL, aMarkedFrame, Marker##type##Property()); \
1279 marker = observer ? observer->GetAndObserveReferencedFrame( \
1280 LayoutFrameType::SVGMarker, nullptr) \
1281 : nullptr; \
1282 foundMarker = foundMarker || bool(marker); \
1283 (*aFrames)[SVGMark::e##type] = static_cast<SVGMarkerFrame*>(marker);
1285 GET_MARKER(Start)
1286 GET_MARKER(Mid)
1287 GET_MARKER(End)
1289 #undef GET_MARKER
1291 return foundMarker;
1294 // Note that the returned list will be empty in the case of a 'filter' property
1295 // that only specifies CSS filter functions (no url()'s to SVG filters).
1296 static SVGFilterObserverListForCSSProp* GetOrCreateFilterObserverListForCSS(
1297 nsIFrame* aFrame) {
1298 MOZ_ASSERT(!aFrame->GetPrevContinuation(), "Require first continuation");
1300 const nsStyleEffects* effects = aFrame->StyleEffects();
1301 if (!effects->HasFilters()) {
1302 return nullptr;
1305 bool found;
1306 SVGFilterObserverListForCSSProp* observers =
1307 aFrame->GetProperty(FilterProperty(), &found);
1308 if (found) {
1309 MOZ_ASSERT(observers, "this property should only store non-null values");
1310 return observers;
1312 observers =
1313 new SVGFilterObserverListForCSSProp(effects->mFilters.AsSpan(), aFrame);
1314 NS_ADDREF(observers);
1315 aFrame->AddProperty(FilterProperty(), observers);
1316 return observers;
1319 static SVGObserverUtils::ReferenceState GetAndObserveFilters(
1320 SVGFilterObserverList* aObserverList,
1321 nsTArray<SVGFilterFrame*>* aFilterFrames) {
1322 if (!aObserverList) {
1323 return SVGObserverUtils::eHasNoRefs;
1326 const nsTArray<RefPtr<SVGFilterObserver>>& observers =
1327 aObserverList->GetObservers();
1328 if (observers.IsEmpty()) {
1329 return SVGObserverUtils::eHasNoRefs;
1332 for (uint32_t i = 0; i < observers.Length(); i++) {
1333 SVGFilterFrame* filter = observers[i]->GetAndObserveFilterFrame();
1334 if (!filter) {
1335 if (aFilterFrames) {
1336 aFilterFrames->Clear();
1338 return SVGObserverUtils::eHasRefsSomeInvalid;
1340 if (aFilterFrames) {
1341 aFilterFrames->AppendElement(filter);
1345 return SVGObserverUtils::eHasRefsAllValid;
1348 SVGObserverUtils::ReferenceState SVGObserverUtils::GetAndObserveFilters(
1349 nsIFrame* aFilteredFrame, nsTArray<SVGFilterFrame*>* aFilterFrames) {
1350 SVGFilterObserverListForCSSProp* observerList =
1351 GetOrCreateFilterObserverListForCSS(aFilteredFrame);
1352 return mozilla::GetAndObserveFilters(observerList, aFilterFrames);
1355 SVGObserverUtils::ReferenceState SVGObserverUtils::GetAndObserveFilters(
1356 nsISupports* aObserverList, nsTArray<SVGFilterFrame*>* aFilterFrames) {
1357 return mozilla::GetAndObserveFilters(
1358 static_cast<SVGFilterObserverListForCanvasContext*>(aObserverList),
1359 aFilterFrames);
1362 SVGObserverUtils::ReferenceState SVGObserverUtils::GetFiltersIfObserving(
1363 nsIFrame* aFilteredFrame, nsTArray<SVGFilterFrame*>* aFilterFrames) {
1364 SVGFilterObserverListForCSSProp* observerList =
1365 aFilteredFrame->GetProperty(FilterProperty());
1366 return mozilla::GetAndObserveFilters(observerList, aFilterFrames);
1369 already_AddRefed<nsISupports> SVGObserverUtils::ObserveFiltersForCanvasContext(
1370 CanvasRenderingContext2D* aContext, Element* aCanvasElement,
1371 const Span<const StyleFilter> aFilters) {
1372 return do_AddRef(new SVGFilterObserverListForCanvasContext(
1373 aContext, aCanvasElement, aFilters));
1376 void SVGObserverUtils::DetachFromCanvasContext(nsISupports* aAutoObserver) {
1377 static_cast<SVGFilterObserverListForCanvasContext*>(aAutoObserver)
1378 ->DetachFromContext();
1381 static SVGPaintingProperty* GetOrCreateClipPathObserver(
1382 nsIFrame* aClippedFrame) {
1383 MOZ_ASSERT(!aClippedFrame->GetPrevContinuation(),
1384 "Require first continuation");
1386 const nsStyleSVGReset* svgStyleReset = aClippedFrame->StyleSVGReset();
1387 if (!svgStyleReset->mClipPath.IsUrl()) {
1388 return nullptr;
1390 const auto& url = svgStyleReset->mClipPath.AsUrl();
1391 RefPtr<URLAndReferrerInfo> pathURI =
1392 ResolveURLUsingLocalRef(aClippedFrame, url);
1393 return GetPaintingProperty(pathURI, aClippedFrame, ClipPathProperty());
1396 SVGObserverUtils::ReferenceState SVGObserverUtils::GetAndObserveClipPath(
1397 nsIFrame* aClippedFrame, SVGClipPathFrame** aClipPathFrame) {
1398 if (aClipPathFrame) {
1399 *aClipPathFrame = nullptr;
1401 SVGPaintingProperty* observers = GetOrCreateClipPathObserver(aClippedFrame);
1402 if (!observers) {
1403 return eHasNoRefs;
1405 bool frameTypeOK = true;
1406 SVGClipPathFrame* frame =
1407 static_cast<SVGClipPathFrame*>(observers->GetAndObserveReferencedFrame(
1408 LayoutFrameType::SVGClipPath, &frameTypeOK));
1409 // Note that, unlike for filters, a reference to an ID that doesn't exist
1410 // is not invalid for clip-path or mask.
1411 if (!frameTypeOK || (frame && !frame->IsValid())) {
1412 return eHasRefsSomeInvalid;
1414 if (aClipPathFrame) {
1415 *aClipPathFrame = frame;
1417 return frame ? eHasRefsAllValid : eHasNoRefs;
1420 static SVGRenderingObserverProperty* GetOrCreateGeometryObserver(
1421 nsIFrame* aFrame) {
1422 // Now only offset-path property uses this. See MotionPathUtils.cpp.
1423 const nsStyleDisplay* disp = aFrame->StyleDisplay();
1424 if (!disp->mOffsetPath.IsUrl()) {
1425 return nullptr;
1427 const auto& url = disp->mOffsetPath.AsUrl();
1428 RefPtr<URLAndReferrerInfo> pathURI = ResolveURLUsingLocalRef(aFrame, url);
1429 return GetEffectProperty(pathURI, aFrame, OffsetPathProperty());
1432 SVGGeometryElement* SVGObserverUtils::GetAndObserveGeometry(nsIFrame* aFrame) {
1433 SVGRenderingObserverProperty* observers = GetOrCreateGeometryObserver(aFrame);
1434 if (!observers) {
1435 return nullptr;
1438 bool frameTypeOK = true;
1439 SVGGeometryFrame* frame =
1440 do_QueryFrame(observers->GetAndObserveReferencedFrame(
1441 LayoutFrameType::SVGGeometry, &frameTypeOK));
1442 if (!frameTypeOK || !frame) {
1443 return nullptr;
1446 return static_cast<dom::SVGGeometryElement*>(frame->GetContent());
1449 static SVGMaskObserverList* GetOrCreateMaskObserverList(
1450 nsIFrame* aMaskedFrame) {
1451 MOZ_ASSERT(!aMaskedFrame->GetPrevContinuation(),
1452 "Require first continuation");
1454 const nsStyleSVGReset* style = aMaskedFrame->StyleSVGReset();
1455 if (!style->HasMask()) {
1456 return nullptr;
1459 MOZ_ASSERT(style->mMask.mImageCount > 0);
1461 bool found;
1462 SVGMaskObserverList* prop = aMaskedFrame->GetProperty(MaskProperty(), &found);
1463 if (found) {
1464 MOZ_ASSERT(prop, "this property should only store non-null values");
1465 return prop;
1467 prop = new SVGMaskObserverList(aMaskedFrame);
1468 NS_ADDREF(prop);
1469 aMaskedFrame->AddProperty(MaskProperty(), prop);
1470 return prop;
1473 SVGObserverUtils::ReferenceState SVGObserverUtils::GetAndObserveMasks(
1474 nsIFrame* aMaskedFrame, nsTArray<SVGMaskFrame*>* aMaskFrames) {
1475 SVGMaskObserverList* observerList = GetOrCreateMaskObserverList(aMaskedFrame);
1476 if (!observerList) {
1477 return eHasNoRefs;
1480 const nsTArray<RefPtr<SVGPaintingProperty>>& observers =
1481 observerList->GetObservers();
1482 if (observers.IsEmpty()) {
1483 return eHasNoRefs;
1486 ReferenceState state = eHasRefsAllValid;
1488 for (size_t i = 0; i < observers.Length(); i++) {
1489 bool frameTypeOK = true;
1490 SVGMaskFrame* maskFrame =
1491 static_cast<SVGMaskFrame*>(observers[i]->GetAndObserveReferencedFrame(
1492 LayoutFrameType::SVGMask, &frameTypeOK));
1493 MOZ_ASSERT(!maskFrame || frameTypeOK);
1494 // XXXjwatt: this looks fishy
1495 if (!frameTypeOK) {
1496 // We can not find the specific SVG mask resource in the downloaded SVG
1497 // document. There are two possibilities:
1498 // 1. The given resource id is invalid.
1499 // 2. The given resource id refers to a viewbox.
1501 // Hand it over to the style image.
1502 observerList->ResolveImage(i);
1503 state = eHasRefsSomeInvalid;
1505 if (aMaskFrames) {
1506 aMaskFrames->AppendElement(maskFrame);
1510 return state;
1513 SVGGeometryElement* SVGObserverUtils::GetAndObserveTextPathsPath(
1514 nsIFrame* aTextPathFrame) {
1515 // Continuations can come and go during reflow, and we don't need to observe
1516 // the referenced element more than once for a given node.
1517 aTextPathFrame = aTextPathFrame->FirstContinuation();
1519 SVGTextPathObserver* property =
1520 aTextPathFrame->GetProperty(HrefAsTextPathProperty());
1522 if (!property) {
1523 nsIContent* content = aTextPathFrame->GetContent();
1524 nsAutoString href;
1525 static_cast<SVGTextPathElement*>(content)->HrefAsString(href);
1526 if (href.IsEmpty()) {
1527 return nullptr; // no URL
1530 // There's no clear refererer policy spec about non-CSS SVG resource
1531 // references Bug 1415044 to investigate which referrer we should use
1532 nsIReferrerInfo* referrerInfo =
1533 content->OwnerDoc()->ReferrerInfoForInternalCSSAndSVGResources();
1534 RefPtr<URLAndReferrerInfo> target =
1535 ResolveURLUsingLocalRef(aTextPathFrame, href, referrerInfo);
1537 property =
1538 GetEffectProperty(target, aTextPathFrame, HrefAsTextPathProperty());
1539 if (!property) {
1540 return nullptr;
1544 return SVGGeometryElement::FromNodeOrNull(
1545 property->GetAndObserveReferencedElement());
1548 SVGGeometryElement* SVGObserverUtils::GetAndObserveMPathsPath(
1549 SVGMPathElement* aSVGMPathElement) {
1550 if (!aSVGMPathElement->mMPathObserver) {
1551 nsAutoString href;
1552 aSVGMPathElement->HrefAsString(href);
1553 if (href.IsEmpty()) {
1554 return nullptr; // no URL
1557 nsIReferrerInfo* referrerInfo =
1558 aSVGMPathElement->OwnerDoc()
1559 ->ReferrerInfoForInternalCSSAndSVGResources();
1561 RefPtr<URLAndReferrerInfo> target =
1562 ResolveURLUsingLocalRef(aSVGMPathElement, href, referrerInfo);
1564 aSVGMPathElement->mMPathObserver =
1565 new SVGMPathObserver(target, aSVGMPathElement);
1568 return SVGGeometryElement::FromNodeOrNull(
1569 static_cast<SVGMPathObserver*>(aSVGMPathElement->mMPathObserver.get())
1570 ->GetAndObserveReferencedElement());
1573 void SVGObserverUtils::TraverseMPathObserver(
1574 SVGMPathElement* aSVGMPathElement,
1575 nsCycleCollectionTraversalCallback* aCB) {
1576 if (aSVGMPathElement->mMPathObserver) {
1577 static_cast<SVGMPathObserver*>(aSVGMPathElement->mMPathObserver.get())
1578 ->Traverse(aCB);
1582 void SVGObserverUtils::InitiateResourceDocLoads(nsIFrame* aFrame) {
1583 // We create observer objects and attach them to aFrame, but we do not
1584 // make aFrame start observing the referenced frames.
1585 Unused << GetOrCreateFilterObserverListForCSS(aFrame);
1586 Unused << GetOrCreateClipPathObserver(aFrame);
1587 Unused << GetOrCreateGeometryObserver(aFrame);
1588 Unused << GetOrCreateMaskObserverList(aFrame);
1591 void SVGObserverUtils::RemoveTextPathObserver(nsIFrame* aTextPathFrame) {
1592 aTextPathFrame->RemoveProperty(HrefAsTextPathProperty());
1595 nsIFrame* SVGObserverUtils::GetAndObserveTemplate(
1596 nsIFrame* aFrame, HrefToTemplateCallback aGetHref) {
1597 SVGTemplateElementObserver* observer =
1598 aFrame->GetProperty(HrefToTemplateProperty());
1600 if (!observer) {
1601 nsAutoString href;
1602 aGetHref(href);
1603 if (href.IsEmpty()) {
1604 return nullptr; // no URL
1607 // Convert href to an nsIURI
1608 nsIContent* content = aFrame->GetContent();
1610 nsCOMPtr<nsIURI> baseURI = content->GetBaseURI();
1611 if (nsContentUtils::IsLocalRefURL(href)) {
1612 baseURI = GetBaseURLForLocalRef(content, baseURI);
1614 nsCOMPtr<nsIURI> targetURI;
1615 nsContentUtils::NewURIWithDocumentCharset(
1616 getter_AddRefs(targetURI), href, content->GetUncomposedDoc(), baseURI);
1618 // There's no clear refererer policy spec about non-CSS SVG resource
1619 // references. Bug 1415044 to investigate which referrer we should use.
1620 nsIReferrerInfo* referrerInfo =
1621 content->OwnerDoc()->ReferrerInfoForInternalCSSAndSVGResources();
1622 RefPtr<URLAndReferrerInfo> target =
1623 new URLAndReferrerInfo(targetURI, referrerInfo);
1625 observer = GetEffectProperty(target, aFrame, HrefToTemplateProperty());
1628 return observer ? observer->GetAndObserveReferencedFrame() : nullptr;
1631 void SVGObserverUtils::RemoveTemplateObserver(nsIFrame* aFrame) {
1632 aFrame->RemoveProperty(HrefToTemplateProperty());
1635 Element* SVGObserverUtils::GetAndObserveBackgroundImage(nsIFrame* aFrame,
1636 const nsAtom* aHref) {
1637 bool found;
1638 URIObserverHashtable* hashtable =
1639 aFrame->GetProperty(BackgroundImageProperty(), &found);
1640 if (!found) {
1641 hashtable = new URIObserverHashtable();
1642 aFrame->AddProperty(BackgroundImageProperty(), hashtable);
1643 } else {
1644 MOZ_ASSERT(hashtable, "this property should only store non-null values");
1647 nsAutoString elementId = u"#"_ns + nsDependentAtomString(aHref);
1648 nsCOMPtr<nsIURI> targetURI;
1649 nsContentUtils::NewURIWithDocumentCharset(
1650 getter_AddRefs(targetURI), elementId,
1651 aFrame->GetContent()->GetUncomposedDoc(),
1652 aFrame->GetContent()->GetBaseURI());
1653 nsIReferrerInfo* referrerInfo =
1654 aFrame->GetContent()
1655 ->OwnerDoc()
1656 ->ReferrerInfoForInternalCSSAndSVGResources();
1657 RefPtr<URLAndReferrerInfo> url =
1658 new URLAndReferrerInfo(targetURI, referrerInfo);
1660 return static_cast<SVGMozElementObserver*>(
1661 hashtable
1662 ->LookupOrInsertWith(
1663 url,
1664 [&] {
1665 return MakeRefPtr<SVGMozElementObserver>(url, aFrame);
1667 .get())
1668 ->GetAndObserveReferencedElement();
1671 Element* SVGObserverUtils::GetAndObserveBackgroundClip(nsIFrame* aFrame) {
1672 bool found;
1673 BackgroundClipRenderingObserver* obs =
1674 aFrame->GetProperty(BackgroundClipObserverProperty(), &found);
1675 if (!found) {
1676 obs = new BackgroundClipRenderingObserver(aFrame);
1677 NS_ADDREF(obs);
1678 aFrame->AddProperty(BackgroundClipObserverProperty(), obs);
1681 return obs->GetAndObserveReferencedElement();
1684 SVGPaintServerFrame* SVGObserverUtils::GetAndObservePaintServer(
1685 nsIFrame* aPaintedFrame, StyleSVGPaint nsStyleSVG::*aPaint) {
1686 // If we're looking at a frame within SVG text, then we need to look up
1687 // to find the right frame to get the painting property off. We should at
1688 // least look up past a text frame, and if the text frame's parent is the
1689 // anonymous block frame, then we look up to its parent (the SVGTextFrame).
1690 nsIFrame* paintedFrame = aPaintedFrame;
1691 if (paintedFrame->IsInSVGTextSubtree()) {
1692 paintedFrame = paintedFrame->GetParent();
1693 nsIFrame* grandparent = paintedFrame->GetParent();
1694 if (grandparent && grandparent->IsSVGTextFrame()) {
1695 paintedFrame = grandparent;
1699 const nsStyleSVG* svgStyle = paintedFrame->StyleSVG();
1700 if (!(svgStyle->*aPaint).kind.IsPaintServer()) {
1701 return nullptr;
1704 RefPtr<URLAndReferrerInfo> paintServerURL = ResolveURLUsingLocalRef(
1705 paintedFrame, (svgStyle->*aPaint).kind.AsPaintServer());
1707 MOZ_ASSERT(aPaint == &nsStyleSVG::mFill || aPaint == &nsStyleSVG::mStroke);
1708 PaintingPropertyDescriptor propDesc =
1709 (aPaint == &nsStyleSVG::mFill) ? FillProperty() : StrokeProperty();
1710 if (auto* property =
1711 GetPaintingProperty(paintServerURL, paintedFrame, propDesc)) {
1712 return do_QueryFrame(property->GetAndObserveReferencedFrame());
1714 return nullptr;
1717 void SVGObserverUtils::UpdateEffects(nsIFrame* aFrame) {
1718 NS_ASSERTION(aFrame->GetContent()->IsElement(),
1719 "aFrame's content should be an element");
1721 aFrame->RemoveProperty(FilterProperty());
1722 aFrame->RemoveProperty(MaskProperty());
1723 aFrame->RemoveProperty(ClipPathProperty());
1724 aFrame->RemoveProperty(MarkerStartProperty());
1725 aFrame->RemoveProperty(MarkerMidProperty());
1726 aFrame->RemoveProperty(MarkerEndProperty());
1727 aFrame->RemoveProperty(FillProperty());
1728 aFrame->RemoveProperty(StrokeProperty());
1729 aFrame->RemoveProperty(BackgroundImageProperty());
1731 // Ensure that the filter is repainted correctly
1732 // We can't do that in OnRenderingChange as the referenced frame may
1733 // not be valid
1734 GetOrCreateFilterObserverListForCSS(aFrame);
1736 if (aFrame->IsSVGGeometryFrame() &&
1737 static_cast<SVGGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
1738 // Set marker properties here to avoid reference loops
1739 RefPtr<URLAndReferrerInfo> markerURL =
1740 GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
1741 GetEffectProperty(markerURL, aFrame, MarkerStartProperty());
1742 markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
1743 GetEffectProperty(markerURL, aFrame, MarkerMidProperty());
1744 markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
1745 GetEffectProperty(markerURL, aFrame, MarkerEndProperty());
1749 void SVGObserverUtils::AddRenderingObserver(Element* aElement,
1750 SVGRenderingObserver* aObserver) {
1751 SVGRenderingObserverSet* observers = GetObserverSet(aElement);
1752 if (!observers) {
1753 observers = new SVGRenderingObserverSet();
1754 aElement->SetProperty(nsGkAtoms::renderingobserverset, observers,
1755 nsINode::DeleteProperty<SVGRenderingObserverSet>);
1757 aElement->SetHasRenderingObservers(true);
1758 observers->Add(aObserver);
1761 void SVGObserverUtils::RemoveRenderingObserver(
1762 Element* aElement, SVGRenderingObserver* aObserver) {
1763 SVGRenderingObserverSet* observers = GetObserverSet(aElement);
1764 if (observers) {
1765 NS_ASSERTION(observers->Contains(aObserver),
1766 "removing observer from an element we're not observing?");
1767 observers->Remove(aObserver);
1768 if (observers->IsEmpty()) {
1769 aElement->RemoveProperty(nsGkAtoms::renderingobserverset);
1770 aElement->SetHasRenderingObservers(false);
1775 void SVGObserverUtils::RemoveAllRenderingObservers(Element* aElement) {
1776 SVGRenderingObserverSet* observers = GetObserverSet(aElement);
1777 if (observers) {
1778 observers->RemoveAll();
1779 aElement->RemoveProperty(nsGkAtoms::renderingobserverset);
1780 aElement->SetHasRenderingObservers(false);
1784 void SVGObserverUtils::InvalidateRenderingObservers(nsIFrame* aFrame) {
1785 NS_ASSERTION(!aFrame->GetPrevContinuation(),
1786 "aFrame must be first continuation");
1788 auto* element = Element::FromNodeOrNull(aFrame->GetContent());
1789 if (!element) {
1790 return;
1793 // If the rendering has changed, the bounds may well have changed too:
1794 aFrame->RemoveProperty(SVGUtils::ObjectBoundingBoxProperty());
1796 if (auto* observers = GetObserverSet(element)) {
1797 observers->InvalidateAll();
1798 return;
1801 if (aFrame->IsRenderingObserverContainer()) {
1802 return;
1805 // Check ancestor SVG containers. The root frame cannot be of type
1806 // eSVGContainer so we don't have to check f for null here.
1807 for (nsIFrame* f = aFrame->GetParent();
1808 f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
1809 if (auto* element = Element::FromNode(f->GetContent())) {
1810 if (auto* observers = GetObserverSet(element)) {
1811 observers->InvalidateAll();
1812 return;
1815 if (f->IsRenderingObserverContainer()) {
1816 return;
1821 void SVGObserverUtils::InvalidateDirectRenderingObservers(
1822 Element* aElement, uint32_t aFlags /* = 0 */) {
1823 if (nsIFrame* frame = aElement->GetPrimaryFrame()) {
1824 // If the rendering has changed, the bounds may well have changed too:
1825 frame->RemoveProperty(SVGUtils::ObjectBoundingBoxProperty());
1828 if (aElement->HasRenderingObservers()) {
1829 SVGRenderingObserverSet* observers = GetObserverSet(aElement);
1830 if (observers) {
1831 if (aFlags & INVALIDATE_REFLOW) {
1832 observers->InvalidateAllForReflow();
1833 } else {
1834 observers->InvalidateAll();
1840 void SVGObserverUtils::InvalidateDirectRenderingObservers(
1841 nsIFrame* aFrame, uint32_t aFlags /* = 0 */) {
1842 if (auto* element = Element::FromNodeOrNull(aFrame->GetContent())) {
1843 InvalidateDirectRenderingObservers(element, aFlags);
1847 already_AddRefed<nsIURI> SVGObserverUtils::GetBaseURLForLocalRef(
1848 nsIContent* content, nsIURI* aDocURI) {
1849 MOZ_ASSERT(content);
1851 // Content is in a shadow tree. If this URL was specified in the subtree
1852 // referenced by the <use>, element, and that subtree came from a separate
1853 // resource document, then we want the fragment-only URL to resolve to an
1854 // element from the resource document. Otherwise, the URL was specified
1855 // somewhere in the document with the <use> element, and we want the
1856 // fragment-only URL to resolve to an element in that document.
1857 if (SVGUseElement* use = content->GetContainingSVGUseShadowHost()) {
1858 if (nsIURI* originalURI = use->GetSourceDocURI()) {
1859 bool isEqualsExceptRef = false;
1860 aDocURI->EqualsExceptRef(originalURI, &isEqualsExceptRef);
1861 if (isEqualsExceptRef) {
1862 return do_AddRef(originalURI);
1867 // For a local-reference URL, resolve that fragment against the current
1868 // document that relative URLs are resolved against.
1869 return do_AddRef(content->OwnerDoc()->GetDocumentURI());
1872 already_AddRefed<URLAndReferrerInfo> SVGObserverUtils::GetFilterURI(
1873 nsIFrame* aFrame, const StyleFilter& aFilter) {
1874 MOZ_ASSERT(!aFrame->StyleEffects()->mFilters.IsEmpty() ||
1875 !aFrame->StyleEffects()->mBackdropFilters.IsEmpty() ||
1876 !aFrame->GetContent()->GetParent());
1877 MOZ_ASSERT(aFilter.IsUrl());
1878 return ResolveURLUsingLocalRef(aFrame, aFilter.AsUrl());
1881 } // namespace mozilla