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