diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 7e555df9f6..134108667a 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -149,6 +149,8 @@ #include "nsDOMStringMap.h" #include "DOMIntersectionObserver.h" +#include "nsDocShell.h" // for ::Cast + using namespace mozilla; using namespace mozilla::dom; @@ -2259,12 +2261,15 @@ Element::GetPrimaryFrame(mozFlushType aType) nsresult Element::LeaveLink(nsPresContext* aPresContext) { - nsILinkHandler *handler = aPresContext->GetLinkHandler(); - if (!handler) { + if (!aPresContext || !aPresContext->Document()->LinkHandlingEnabled()) { return NS_OK; } - return handler->OnLeaveLink(); + nsIDocShell* shell = aPresContext->Document()->GetDocShell(); + if (!shell) { + return NS_OK; + } + return nsDocShell::Cast(shell)->OnLeaveLink(); } nsresult @@ -3175,7 +3180,6 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor, (aVisitor.mEvent->mMessage != eMouseClick) && (aVisitor.mEvent->mMessage != eKeyPress) && (aVisitor.mEvent->mMessage != eLegacyDOMActivate)) || - !aVisitor.mPresContext || aVisitor.mEvent->mFlags.mMultipleActionsPrevented) { return false; } @@ -3220,7 +3224,7 @@ Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor) if (!focusEvent || !focusEvent->mIsRefocus) { nsAutoString target; GetLinkTarget(target); - nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target, + nsContentUtils::TriggerLink(this, absURI, target, false, true, true); // Make sure any ancestor links don't also TriggerLink aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true; @@ -3272,20 +3276,20 @@ Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) switch (aVisitor.mEvent->mMessage) { case eMouseDown: { - if (aVisitor.mEvent->AsMouseEvent()->button == - WidgetMouseEvent::eLeftButton) { - // don't make the link grab the focus if there is no link handler - nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler(); - nsIDocument *document = GetComposedDoc(); - if (handler && document) { + if (aVisitor.mEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton && + OwnerDoc()->LinkHandlingEnabled()) { + aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true; + + if (IsInComposedDoc()) { nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) { - aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true; nsCOMPtr elem = do_QueryInterface(this); fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL); } - + } + + if (aVisitor.mPresContext) { EventStateManager::SetActiveManager( aVisitor.mPresContext->EventStateManager(), this); } @@ -3302,19 +3306,18 @@ Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) } // The default action is simply to dispatch DOMActivate - nsCOMPtr shell = aVisitor.mPresContext->GetPresShell(); - if (shell) { - // single-click - nsEventStatus status = nsEventStatus_eIgnore; - // DOMActive event should be trusted since the activation is actually - // occurred even if the cause is an untrusted click event. - InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent); - actEvent.mDetail = 1; - - rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status); - if (NS_SUCCEEDED(rv)) { - aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; - } + nsEventStatus status = nsEventStatus_eIgnore; + // The DOMActive event should be trusted since the activation has actually + // occurred even if the cause is an untrusted click event. + // This is a hack to allow click events to happen on anchors outside document + // contexts (where there is no presShell)... Thanks, Google, for another ugly one. + InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent); + actEvent.mDetail = 1; + + rv = EventDispatcher::Dispatch(this, aVisitor.mPresContext, &actEvent, + nullptr, &status); + if (NS_SUCCEEDED(rv)) { + aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } break; @@ -3326,7 +3329,7 @@ Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) GetLinkTarget(target); const InternalUIEvent* activeEvent = aVisitor.mEvent->AsUIEvent(); MOZ_ASSERT(activeEvent); - nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target, + nsContentUtils::TriggerLink(this, absURI, target, true, true, activeEvent->IsTrustable()); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index e4b49f0d13..ab7eb59774 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -89,6 +89,7 @@ #include "nsCycleCollectionParticipant.h" #include "nsCycleCollector.h" #include "nsDataHashtable.h" +#include "nsDocShell.h" #include "nsDocShellCID.h" #include "nsDocument.h" #include "nsDOMCID.h" @@ -5336,25 +5337,24 @@ nsContentUtils::CombineResourcePrincipals(nsCOMPtr* aResourcePrinc /* static */ void -nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext, +nsContentUtils::TriggerLink(nsIContent *aContent, nsIURI *aLinkURI, const nsString &aTargetSpec, bool aClick, bool aIsUserTriggered, bool aIsTrusted) { - NS_ASSERTION(aPresContext, "Need a nsPresContext"); NS_PRECONDITION(aLinkURI, "No link URI"); - if (aContent->IsEditable()) { + if (aContent->IsEditable() || !aContent->OwnerDoc()->LinkHandlingEnabled()) { return; } - nsILinkHandler *handler = aPresContext->GetLinkHandler(); - if (!handler) { + nsCOMPtr docShell = aContent->OwnerDoc()->GetDocShell(); + if (!docShell) { return; } if (!aClick) { - handler->OnOverLink(aContent, aLinkURI, aTargetSpec.get()); + nsDocShell::Cast(docShell)->OnOverLink(aContent, aLinkURI, aTargetSpec.get()); return; } @@ -5397,9 +5397,9 @@ nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext, } } - handler->OnLinkClick(aContent, aLinkURI, - fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(), - fileName, nullptr, nullptr, aIsTrusted, aContent->NodePrincipal()); + nsDocShell::Cast(docShell)->OnLinkClick(aContent, aLinkURI, + fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(), + fileName, nullptr, nullptr, aIsTrusted, aContent->NodePrincipal()); } } diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 00871628cf..6a372d9a73 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1711,7 +1711,6 @@ public: * security check using aContent's principal. * * @param aContent the node on which a link was triggered. - * @param aPresContext the pres context, must be non-null. * @param aLinkURI the URI of the link, must be non-null. * @param aTargetSpec the target (like target=, may be empty). * @param aClick whether this was a click or not (if false, this method @@ -1722,7 +1721,7 @@ public: * @param aIsTrusted If false, JS Context will be pushed to stack * when the link is triggered. */ - static void TriggerLink(nsIContent *aContent, nsPresContext *aPresContext, + static void TriggerLink(nsIContent *aContent, nsIURI *aLinkURI, const nsString& aTargetSpec, bool aClick, bool aIsUserTriggered, bool aIsTrusted); diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 079aa0fdae..2aff040382 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1288,6 +1288,7 @@ nsIDocument::nsIDocument() nsDocument::nsDocument(const char* aContentType) : nsIDocument() + , mLinksEnabled(true) , mViewportType(Unknown) { SetContentTypeInternal(nsDependentCString(aContentType)); diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 70bda75fed..417aa39cdf 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -412,6 +412,14 @@ public: virtual void RemoveIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver, void* aData, bool aForImage) override; + virtual void SetLinkHandlingEnabled(bool aValue) override { + mLinksEnabled = aValue; + } + + virtual bool LinkHandlingEnabled() override { + return mLinksEnabled; + } + /** * Access HTTP header data (this may also get set from other sources, like * HTML META tags). @@ -1223,6 +1231,10 @@ public: // Recorded time of change to 'loading' state. mozilla::TimeStamp mLoadingTimeStamp; + // False if we've disabled link handling for elements inside this document, + // true otherwise. + bool mLinksEnabled : 1; + // True if the document has been detached from its content viewer. bool mIsGoingAway:1; // True if the document is being destroyed. diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index bf4b053f5e..395287e09d 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -767,6 +767,9 @@ public: mSandboxFlags = sandboxFlags; } + virtual void SetLinkHandlingEnabled(bool aValue) = 0; + virtual bool LinkHandlingEnabled() = 0; + /** * Access HTTP header data (this may also get set from other * sources, like HTML META tags). diff --git a/dom/html/HTMLAnchorElement.cpp b/dom/html/HTMLAnchorElement.cpp index 01e1ab1759..aef6dbb386 100644 --- a/dom/html/HTMLAnchorElement.cpp +++ b/dom/html/HTMLAnchorElement.cpp @@ -199,16 +199,9 @@ HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse, } // cannot focus links if there is no link handler - nsIDocument* doc = GetComposedDoc(); - if (doc) { - nsIPresShell* presShell = doc->GetShell(); - if (presShell) { - nsPresContext* presContext = presShell->GetPresContext(); - if (presContext && !presContext->GetLinkHandler()) { - *aIsFocusable = false; - return false; - } - } + if (!OwnerDoc()->LinkHandlingEnabled()) { + *aIsFocusable = false; + return false; } // Links that are in an editable region should never be focusable, even if diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index 950982f8a2..536701e076 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -581,17 +581,16 @@ nsGenericHTMLElement::FindAncestorForm(HTMLFormElement* aCurrentForm) } bool -nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions( - EventChainVisitor& aVisitor) +nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(EventChainVisitor& aVisitor) { NS_PRECONDITION(nsCOMPtr(do_QueryObject(this)), "should be called only when |this| implements |Link|"); if (!aVisitor.mPresContext) { - // We need a pres context to do link stuff. Some events (e.g. mutation - // events) don't have one. - // XXX: ideally, shouldn't we be able to do what we need without one? - return false; + // When not in the composed document DOM, only should navigate away per + // the exception in https://html.spec.whatwg.org/#cannot-navigate + // Thanks, Google, for another ugly one. :| + return IsInComposedDoc() || IsHTMLElement(nsGkAtoms::a); } //Need to check if we hit an imagemap area and if so see if we're handling diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index bc253b213b..4739783b43 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -165,11 +165,10 @@ HTMLEditor::~HTMLEditor() // free any default style propItems RemoveAllDefaultProperties(); - if (mLinkHandler && IsInitialized()) { - nsCOMPtr ps = GetPresShell(); - - if (ps && ps->GetPresContext()) { - ps->GetPresContext()->SetLinkHandler(mLinkHandler); + if (mDisabledLinkHandling) { + nsCOMPtr doc = GetDocument(); + if (doc) { + doc->SetLinkHandlingEnabled(mOldLinkHandlingEnabled); } } @@ -290,13 +289,14 @@ HTMLEditor::Init(nsIDOMDocument* aDoc, mCSSEditUtils = MakeUnique(this); // disable links - nsCOMPtr presShell = GetPresShell(); - NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); - nsPresContext *context = presShell->GetPresContext(); - NS_ENSURE_TRUE(context, NS_ERROR_NULL_POINTER); + nsCOMPtr doc = GetDocument(); + if (NS_WARN_IF(!doc)) { + return NS_ERROR_FAILURE; + } if (!IsPlaintextEditor() && !IsInteractionAllowed()) { - mLinkHandler = context->GetLinkHandler(); - context->SetLinkHandler(nullptr); + mDisabledLinkHandling = true; + mOldLinkHandlingEnabled = doc->LinkHandlingEnabled(); + doc->SetLinkHandlingEnabled(false); } // init the type-in state diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index 494e7c3834..e90e7ebe6e 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -41,7 +41,6 @@ class nsDocumentFragment; class nsIDOMKeyEvent; class nsITransferable; class nsIClipboard; -class nsILinkHandler; class nsTableWrapperFrame; class nsIDOMRange; class nsRange; @@ -1079,7 +1078,8 @@ protected: void AddMouseClickListener(nsIDOMElement* aElement); void RemoveMouseClickListener(nsIDOMElement* aElement); - nsCOMPtr mLinkHandler; + bool mDisabledLinkHandling = false; + bool mOldLinkHandlingEnabled = false; public: friend class HTMLEditorEventListener; diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index ac48fa6656..e10980aecc 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -910,12 +910,7 @@ nsDocumentViewer::InitInternal(nsIWidget* aParentWidget, nsCOMPtr requestor(mContainer); if (requestor) { if (mPresContext) { - nsCOMPtr linkHandler; - requestor->GetInterface(NS_GET_IID(nsILinkHandler), - getter_AddRefs(linkHandler)); - mPresContext->SetContainer(mContainer); - mPresContext->SetLinkHandler(linkHandler); } // Set script-context-owner in the document @@ -1421,8 +1416,6 @@ AttachContainerRecurse(nsIDocShell* aShell) viewer->GetPresContext(getter_AddRefs(pc)); if (pc) { pc->SetContainer(static_cast(aShell)); - nsCOMPtr handler = do_QueryInterface(aShell); - pc->SetLinkHandler(handler); } nsCOMPtr presShell; viewer->GetPresShell(getter_AddRefs(presShell)); @@ -2146,12 +2139,6 @@ nsDocumentViewer::Show(void) return rv; if (mPresContext && base_win) { - nsCOMPtr linkHandler(do_GetInterface(base_win)); - - if (linkHandler) { - mPresContext->SetLinkHandler(linkHandler); - } - mPresContext->SetContainer(mContainer); } diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index ff7cefb111..367d0f8233 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -1504,7 +1504,6 @@ nsPresContext::GetDocShell() const nsPresContext::Detach() { SetContainer(nullptr); - SetLinkHandler(nullptr); if (mShell) { mShell->CancelInvalidatePresShellIfHidden(); } diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index ee7427018b..ba99cdf070 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -457,13 +457,9 @@ public: nsIDocShell* GetDocShell() const; - // XXX this are going to be replaced with set/get container - void SetLinkHandler(nsILinkHandler* aHandler) { mLinkHandler = aHandler; } - nsILinkHandler* GetLinkHandler() { return mLinkHandler; } - /** * Detach this pres context - i.e. cancel relevant timers, - * SetLinkHandler(null), SetContainer(null) etc. + * SetContainer(null) etc. * Only to be used by the DocumentViewer. */ virtual void Detach(); @@ -1245,10 +1241,6 @@ protected: nsIAtom* MOZ_UNSAFE_REF("always a static atom") mMedium; // initialized by subclass ctors nsCOMPtr mMediaEmulated; - // This pointer is nulled out through SetLinkHandler() in the destructors of - // the classes which set it. (using SetLinkHandler() again). - nsILinkHandler* MOZ_NON_OWNING_REF mLinkHandler; - // Formerly mLangGroup; moving from charset-oriented langGroup to // maintaining actual language settings everywhere (see bug 524107). // This may in fact hold a langGroup such as x-western rather than diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index f27ad60407..8016703b0a 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1309,9 +1309,6 @@ PresShell::Destroy() // to us. To avoid the pres context having a dangling reference, set its // pres shell to nullptr mPresContext->DetachShell(); - - // Clear the link handler (weak reference) as well - mPresContext->SetLinkHandler(nullptr); } mHaveShutDown = true; diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 6a7672a513..a3429db0cf 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -2046,7 +2046,7 @@ nsImageFrame::HandleEvent(nsPresContext* aPresContext, *aEventStatus = nsEventStatus_eConsumeDoDefault; clicked = true; } - nsContentUtils::TriggerLink(anchorNode, aPresContext, uri, target, + nsContentUtils::TriggerLink(anchorNode, uri, target, clicked, true, true); } }