diff --git a/dom/base/Link.cpp b/dom/base/Link.cpp index 3ef511b021eba..c5ed77af3cced 100644 --- a/dom/base/Link.cpp +++ b/dom/base/Link.cpp @@ -475,12 +475,11 @@ void Link::ResetLinkState(bool aNotify, bool aHasHref) { } } - // If we have an href, and we're not a , we should register with the - // history. + // If we have an href, we should register with the history. // // FIXME(emilio): Do we really want to allow all MathML elements to be // :visited? That seems not great. - mNeedsRegistration = aHasHref && !mElement->IsHTMLElement(nsGkAtoms::link); + mNeedsRegistration = aHasHref; // If we've cached the URI, reset always invalidates it. UnregisterFromHistory(); @@ -539,11 +538,8 @@ void Link::SetHrefAttribute(nsIURI* aURI) { size_t Link::SizeOfExcludingThis(mozilla::SizeOfState& aState) const { size_t n = 0; - if (mCachedURI) { - nsCOMPtr iface = do_QueryInterface(mCachedURI); - if (iface) { - n += iface->SizeOfIncludingThis(aState.mMallocSizeOf); - } + if (nsCOMPtr iface = do_QueryInterface(mCachedURI)) { + n += iface->SizeOfIncludingThis(aState.mMallocSizeOf); } // The following members don't need to be measured: diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp index fc02934ae99f5..fcf468240fb9c 100644 --- a/dom/html/HTMLLinkElement.cpp +++ b/dom/html/HTMLLinkElement.cpp @@ -27,6 +27,7 @@ #include "mozilla/dom/Document.h" #include "nsINode.h" #include "nsIPrefetchService.h" +#include "nsISizeOf.h" #include "nsPIDOMWindow.h" #include "nsReadableUtils.h" #include "nsStyleConsts.h" @@ -47,11 +48,9 @@ namespace mozilla::dom { HTMLLinkElement::HTMLLinkElement( already_AddRefed&& aNodeInfo) - : nsGenericHTMLElement(std::move(aNodeInfo)), Link(this) {} + : nsGenericHTMLElement(std::move(aNodeInfo)) {} -HTMLLinkElement::~HTMLLinkElement() { - SupportsDNSPrefetch::Destroyed(*this); -} +HTMLLinkElement::~HTMLLinkElement() { SupportsDNSPrefetch::Destroyed(*this); } NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLLinkElement) @@ -69,8 +68,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLLinkElement, NS_IMPL_CYCLE_COLLECTION_UNLINK(mSizes) NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLLinkElement, - nsGenericHTMLElement, Link) +NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLLinkElement, + nsGenericHTMLElement) NS_IMPL_ELEMENT_CLONE(HTMLLinkElement) @@ -83,8 +82,6 @@ void HTMLLinkElement::SetDisabled(bool aDisabled, ErrorResult& aRv) { } nsresult HTMLLinkElement::BindToTree(BindContext& aContext, nsINode& aParent) { - Link::ResetLinkState(false, Link::ElementHasHref()); - nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent); NS_ENSURE_SUCCESS(rv, rv); @@ -117,16 +114,9 @@ void HTMLLinkElement::LinkRemoved() { } void HTMLLinkElement::UnbindFromTree(bool aNullParent) { - // Cancel any DNS prefetches - // Note: Must come before ResetLinkState. If called after, it will recreate - // mCachedURI based on data that is invalid - due to a call to GetHostname. CancelDNSPrefetch(*this); CancelPrefetchOrPreload(); - // Without removing the link state we risk a dangling pointer - // in the mStyledLinks hashtable - Link::ResetLinkState(false, Link::ElementHasHref()); - // If this is reinserted back into the document it will not be // from the parser. Document* oldDoc = GetUncomposedDoc(); @@ -221,23 +211,28 @@ nsresult HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aOldValue, nsIPrincipal* aSubjectPrincipal, bool aNotify) { - // It's safe to call ResetLinkState here because our new attr value has - // already been set or unset. ResetLinkState needs the updated attribute - // value because notifying the document that content states have changed will - // call IntrinsicState, which will try to get updated information about the - // visitedness from Link. - if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) { - bool hasHref = aValue; - Link::ResetLinkState(!!aNotify, hasHref); + if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::href) { + mCachedURI = nullptr; if (IsInUncomposedDoc()) { CreateAndDispatchEvent(OwnerDoc(), u"DOMLinkChanged"_ns); } - } - - if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::href) { mTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal( this, aValue ? aValue->GetStringValue() : EmptyString(), aSubjectPrincipal); + + // If the link has `rel=localization` and its `href` attribute is changed, + // update the list of localization links. + if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::rel, nsGkAtoms::localization, + eIgnoreCase)) { + if (Document* doc = GetUncomposedDoc()) { + if (aOldValue) { + doc->LocalizationLinkRemoved(this); + } + if (aValue) { + doc->LocalizationLinkAdded(this); + } + } + } } // If a link's `rel` attribute was changed from or to `localization`, @@ -257,21 +252,6 @@ nsresult HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, } } - // If the link has `rel=localization` and its `href` attribute is changed, - // update the list of localization links. - if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::href && - AttrValueIs(kNameSpaceID_None, nsGkAtoms::rel, nsGkAtoms::localization, - eIgnoreCase)) { - if (Document* doc = GetUncomposedDoc()) { - if (aOldValue) { - doc->LocalizationLinkRemoved(this); - } - if (aValue) { - doc->LocalizationLinkAdded(this); - } - } - } - if (aValue) { if (aNameSpaceID == kNameSpaceID_None && (aName == nsGkAtoms::href || aName == nsGkAtoms::rel || @@ -330,23 +310,6 @@ nsresult HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify); } -void HTMLLinkElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) { - GetEventTargetParentForAnchors(aVisitor); -} - -nsresult HTMLLinkElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { - return PostHandleEventForAnchors(aVisitor); -} - -bool HTMLLinkElement::IsLink(nsIURI** aURI) const { return IsHTMLLink(aURI); } - -void HTMLLinkElement::GetLinkTarget(nsAString& aTarget) { - GetAttr(kNameSpaceID_None, nsGkAtoms::target, aTarget); - if (aTarget.IsEmpty()) { - GetBaseTarget(aTarget); - } -} - static const DOMTokenListSupportedToken sSupportedRelValues[] = { // Keep this and the one below in sync with ToLinkMask in // LinkStyle.cpp. @@ -380,10 +343,6 @@ nsDOMTokenList* HTMLLinkElement::RelList() { return mRelList; } -already_AddRefed HTMLLinkElement::GetHrefURI() const { - return GetHrefURIForAnchors(); -} - Maybe HTMLLinkElement::GetStyleSheetInfo() { nsAutoString rel; GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel); @@ -410,16 +369,14 @@ Maybe HTMLLinkElement::GetStyleSheetInfo() { return Nothing(); } - nsAutoString href; - GetAttr(kNameSpaceID_None, nsGkAtoms::href, href); - if (href.IsEmpty()) { + if (!HasNonEmptyAttr(nsGkAtoms::href)) { return Nothing(); } nsAutoString integrity; - GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity); + GetAttr(nsGkAtoms::integrity, integrity); - nsCOMPtr uri = Link::GetURI(); + nsCOMPtr uri = GetURI(); nsCOMPtr prin = mTriggeringPrincipal; nsAutoString nonce; @@ -445,14 +402,12 @@ Maybe HTMLLinkElement::GetStyleSheetInfo() { }); } -EventStates HTMLLinkElement::IntrinsicState() const { - return Link::LinkState() | nsGenericHTMLElement::IntrinsicState(); -} - void HTMLLinkElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes, size_t* aNodeSize) const { nsGenericHTMLElement::AddSizeOfExcludingThis(aSizes, aNodeSize); - *aNodeSize += Link::SizeOfExcludingThis(aSizes.mState); + if (nsCOMPtr iface = do_QueryInterface(mCachedURI)) { + *aNodeSize += iface->SizeOfExcludingThis(aSizes.mState.mMallocSizeOf); + } } JSObject* HTMLLinkElement::WrapNode(JSContext* aCx, @@ -549,7 +504,7 @@ void HTMLLinkElement::GetContentPolicyMimeTypeMedia( void HTMLLinkElement:: TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender() { MOZ_ASSERT(IsInComposedDoc()); - if (!ElementHasHref()) { + if (!HasAttr(nsGkAtoms::href)) { return; } @@ -568,8 +523,7 @@ void HTMLLinkElement:: nsCOMPtr prefetchService( components::Prefetch::Service()); if (prefetchService) { - nsCOMPtr uri(GetURI()); - if (uri) { + if (nsCOMPtr uri = GetURI()) { auto referrerInfo = MakeRefPtr(*this); prefetchService->PrefetchURI(uri, referrerInfo, this, linkTypes & ePREFETCH); @@ -616,7 +570,7 @@ void HTMLLinkElement::UpdatePreload(nsAtom* aName, const nsAttrValue* aValue, const nsAttrValue* aOldValue) { MOZ_ASSERT(IsInComposedDoc()); - if (!ElementHasHref()) { + if (!HasAttr(nsGkAtoms::href)) { return; } @@ -635,7 +589,7 @@ void HTMLLinkElement::UpdatePreload(nsAtom* aName, const nsAttrValue* aValue, return; } - nsCOMPtr uri(GetURI()); + nsCOMPtr uri = GetURI(); if (!uri) { return; } diff --git a/dom/html/HTMLLinkElement.h b/dom/html/HTMLLinkElement.h index 5d0881af12b48..2d1c003532879 100644 --- a/dom/html/HTMLLinkElement.h +++ b/dom/html/HTMLLinkElement.h @@ -22,11 +22,8 @@ class PreloaderBase; namespace dom { -// NOTE(emilio): If we stop inheriting from Link, we need to remove the -// IsHTMLElement(nsGkAtoms::link) checks in Link.cpp. class HTMLLinkElement final : public nsGenericHTMLElement, public LinkStyle, - public Link, public SupportsDNSPrefetch { public: explicit HTMLLinkElement( @@ -45,11 +42,6 @@ class HTMLLinkElement final : public nsGenericHTMLElement, void LinkAdded(); void LinkRemoved(); - // EventTarget - void GetEventTargetParent(EventChainPreVisitor& aVisitor) override; - MOZ_CAN_RUN_SCRIPT - nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override; - // nsINode nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; JSObject* WrapNode(JSContext* aCx, @@ -64,16 +56,11 @@ class HTMLLinkElement final : public nsGenericHTMLElement, nsresult AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aValue, const nsAttrValue* aOldValue, nsIPrincipal* aSubjectPrincipal, bool aNotify) override; - bool IsLink(nsIURI** aURI) const override; - already_AddRefed GetHrefURI() const override; - // Element bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, const nsAString& aValue, nsIPrincipal* aMaybeScriptedPrincipal, nsAttrValue& aResult) override; - void GetLinkTarget(nsAString& aTarget) override; - EventStates IntrinsicState() const override; void CreateAndDispatchEvent(Document* aDoc, const nsAString& aEventName); @@ -81,6 +68,13 @@ class HTMLLinkElement final : public nsGenericHTMLElement, bool Disabled() const; void SetDisabled(bool aDisabled, ErrorResult& aRv); + nsIURI* GetURI() { + if (!mCachedURI) { + GetURIAttr(nsGkAtoms::href, nullptr, getter_AddRefs(mCachedURI)); + } + return mCachedURI.get(); + } + void GetHref(nsAString& aValue) { GetURIAttr(nsGkAtoms::href, nullptr, aValue); } @@ -178,7 +172,7 @@ class HTMLLinkElement final : public nsGenericHTMLElement, } void NodeInfoChanged(Document* aOldDoc) final { - ClearHasPendingLinkUpdate(); + mCachedURI = nullptr; nsGenericHTMLElement::NodeInfoChanged(aOldDoc); } @@ -218,6 +212,9 @@ class HTMLLinkElement final : public nsGenericHTMLElement, // the preload is held alive by other means. WeakPtr mPreload; + // The cached href attribute value. + nsCOMPtr mCachedURI; + // The "explicitly enabled" flag. This flag is set whenever the `disabled` // attribute is explicitly unset, and makes alternate stylesheets not be // disabled by default anymore. diff --git a/dom/html/test/test_bug372098.html b/dom/html/test/test_bug372098.html index 15611dcf3623c..900b20100d828 100644 --- a/dom/html/test/test_bug372098.html +++ b/dom/html/test/test_bug372098.html @@ -15,7 +15,6 @@