Bug 1218456 - Allow navigating when there's no pres context. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D37404
This commit is contained in:
Emilio Cobos Álvarez 2019-07-09 16:17:27 +00:00
parent 54b3d5a085
commit 28801c9e84
17 changed files with 68 additions and 147 deletions

View File

@ -1245,6 +1245,7 @@ Document::Document(const char* aContentType)
mDidCallBeginLoad(false),
mAllowPaymentRequest(false),
mEncodingMenuDisabled(false),
mLinksEnabled(true),
mIsSVGGlyphsDocument(false),
mInDestructor(false),
mIsGoingAway(false),

View File

@ -1367,6 +1367,9 @@ class Document : public nsINode,
*/
void DisableCookieAccess() { mDisableCookieAccess = true; }
void SetLinkHandlingEnabled(bool aValue) { mLinksEnabled = aValue; }
bool LinkHandlingEnabled() { return mLinksEnabled; }
/**
* Set compatibility mode for this document
*/
@ -4661,6 +4664,10 @@ class Document : public nsINode,
// True if the encoding menu should be disabled.
bool mEncodingMenuDisabled : 1;
// False if we've disabled link handling for elements inside this document,
// true otherwise.
bool mLinksEnabled : 1;
// True if this document is for an SVG-in-OpenType font.
bool mIsSVGGlyphsDocument : 1;

View File

@ -2172,12 +2172,14 @@ nsresult Element::DispatchClickEvent(nsPresContext* aPresContext,
//----------------------------------------------------------------------
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 Element::SetEventHandler(nsAtom* aEventName, const nsAString& aValue,
@ -2975,7 +2977,6 @@ bool Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
(aVisitor.mEvent->mMessage != eMouseClick) &&
(aVisitor.mEvent->mMessage != eKeyPress) &&
(aVisitor.mEvent->mMessage != eLegacyDOMActivate)) ||
!aVisitor.mPresContext ||
aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
return false;
}
@ -3016,7 +3017,7 @@ void Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor) {
if (!focusEvent || !focusEvent->mIsRefocus) {
nsAutoString target;
GetLinkTarget(target);
nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
nsContentUtils::TriggerLink(this, absURI, target,
/* click */ false, /* isTrusted */ true);
// Make sure any ancestor links don't also TriggerLink
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
@ -3064,27 +3065,29 @@ nsresult Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) {
switch (aVisitor.mEvent->mMessage) {
case eMouseDown: {
if (aVisitor.mEvent->AsMouseEvent()->mButton == MouseButton::eLeft) {
// don't make the link grab the focus if there is no link handler
nsILinkHandler* handler = aVisitor.mPresContext->GetLinkHandler();
Document* document = GetComposedDoc();
if (handler && document) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
if (aVisitor.mEvent->AsMouseEvent()->mButton == MouseButton::eLeft &&
OwnerDoc()->LinkHandlingEnabled()) {
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
if (IsInComposedDoc()) {
if (nsIFocusManager* fm = nsFocusManager::GetFocusManager()) {
RefPtr<Element> kungFuDeathGrip(this);
fm->SetFocus(kungFuDeathGrip, nsIFocusManager::FLAG_BYMOUSE |
nsIFocusManager::FLAG_NOSCROLL);
}
}
if (aVisitor.mPresContext) {
EventStateManager::SetActiveManager(
aVisitor.mPresContext->EventStateManager(), this);
}
// OK, we're pretty sure we're going to load, so warm up a speculative
// connection to be sure we have one ready when we open the channel.
// OK, we're pretty sure we're going to load, so warm up a speculative
// connection to be sure we have one ready when we open the channel.
if (nsIDocShell* shell = OwnerDoc()->GetDocShell()) {
nsCOMPtr<nsISpeculativeConnect> sc =
do_QueryInterface(nsContentUtils::GetIOService());
nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(handler);
nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(shell);
sc->SpeculativeConnect(absURI, NodePrincipal(), ir);
}
}
@ -3099,19 +3102,16 @@ nsresult Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) {
}
// The default action is simply to dispatch DOMActivate
if (RefPtr<PresShell> presShell =
aVisitor.mPresContext->GetPresShell()) {
// 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;
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 = presShell->HandleDOMEventWithTarget(this, &actEvent, &status);
if (NS_SUCCEEDED(rv)) {
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
}
rv = EventDispatcher::Dispatch(this, aVisitor.mPresContext, &actEvent,
nullptr, &status);
if (NS_SUCCEEDED(rv)) {
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
}
}
break;
@ -3122,8 +3122,7 @@ nsresult Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) {
GetLinkTarget(target);
const InternalUIEvent* activeEvent = aVisitor.mEvent->AsUIEvent();
MOZ_ASSERT(activeEvent);
nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
/* click */ true,
nsContentUtils::TriggerLink(this, absURI, target, /* click */ true,
activeEvent->IsTrustable());
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
}

View File

@ -5080,24 +5080,22 @@ bool nsContentUtils::CombineResourcePrincipals(
}
/* static */
void nsContentUtils::TriggerLink(nsIContent* aContent,
nsPresContext* aPresContext, nsIURI* aLinkURI,
void nsContentUtils::TriggerLink(nsIContent* aContent, nsIURI* aLinkURI,
const nsString& aTargetSpec, bool aClick,
bool aIsTrusted) {
NS_ASSERTION(aPresContext, "Need a nsPresContext");
MOZ_ASSERT(aLinkURI, "No link URI");
if (aContent->IsEditable()) {
if (aContent->IsEditable() || !aContent->OwnerDoc()->LinkHandlingEnabled()) {
return;
}
nsILinkHandler* handler = aPresContext->GetLinkHandler();
if (!handler) {
nsCOMPtr<nsIDocShell> docShell = aContent->OwnerDoc()->GetDocShell();
if (!docShell) {
return;
}
if (!aClick) {
handler->OnOverLink(aContent, aLinkURI, aTargetSpec);
nsDocShell::Cast(docShell)->OnOverLink(aContent, aLinkURI, aTargetSpec);
return;
}
@ -5132,7 +5130,7 @@ void nsContentUtils::TriggerLink(nsIContent* aContent,
nsCOMPtr<nsIPrincipal> triggeringPrincipal = aContent->NodePrincipal();
nsCOMPtr<nsIContentSecurityPolicy> csp = aContent->GetCsp();
handler->OnLinkClick(
nsDocShell::Cast(docShell)->OnLinkClick(
aContent, aLinkURI, fileName.IsVoid() ? aTargetSpec : EmptyString(),
fileName, nullptr, nullptr, EventStateManager::IsHandlingUserInput(),
aIsTrusted, triggeringPrincipal, csp);

View File

@ -1896,7 +1896,6 @@ class nsContentUtils {
* 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
@ -1904,9 +1903,9 @@ class nsContentUtils {
* @param aIsTrusted If false, JS Context will be pushed to stack
* when the link is triggered.
*/
static void TriggerLink(nsIContent* aContent, nsPresContext* aPresContext,
nsIURI* aLinkURI, const nsString& aTargetSpec,
bool aClick, bool aIsTrusted);
static void TriggerLink(nsIContent* aContent, nsIURI* aLinkURI,
const nsString& aTargetSpec, bool aClick,
bool aIsTrusted);
/**
* Get the link location.

View File

@ -142,13 +142,9 @@ bool HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
}
// cannot focus links if there is no link handler
Document* doc = GetComposedDoc();
if (doc) {
nsPresContext* presContext = doc->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

View File

@ -523,12 +523,10 @@ bool nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(
EventChainVisitor& aVisitor) {
MOZ_ASSERT(nsCOMPtr<Link>(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 disconnected, only <a> should navigate away per
// https://html.spec.whatwg.org/#cannot-navigate
return IsInComposedDoc() || IsHTMLElement(nsGkAtoms::a);
}
// Need to check if we hit an imagemap area and if so see if we're handling

View File

@ -214,13 +214,8 @@ bool SVGAElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) {
return isFocusable;
}
// cannot focus links if there is no link handler
Document* doc = GetComposedDoc();
if (doc) {
nsPresContext* presContext = doc->GetPresContext();
if (presContext && !presContext->GetLinkHandler()) {
return false;
}
if (!OwnerDoc()->LinkHandlingEnabled()) {
return false;
}
// Links that are in an editable region should never be focusable, even if

View File

@ -190,10 +190,9 @@ HTMLEditor::~HTMLEditor() {
mTypeInState = nullptr;
if (mLinkHandler && IsInitialized()) {
PresShell* presShell = GetPresShell();
if (presShell && presShell->GetPresContext()) {
presShell->GetPresContext()->SetLinkHandler(mLinkHandler);
if (mDisabledLinkHandling) {
if (Document* doc = GetDocument()) {
doc->SetLinkHandlingEnabled(mOldLinkHandlingEnabled);
}
}
@ -210,8 +209,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLEditor, TextEditor)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheets)
tmp->HideAnonymousEditingUIs();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLinkHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLEditor, TextEditor)
@ -243,8 +240,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLEditor, TextEditor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAddRowBeforeButton)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRemoveRowButton)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAddRowAfterButton)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLinkHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(HTMLEditor, EditorBase)
@ -295,15 +290,14 @@ nsresult HTMLEditor::Init(Document& aDoc, Element* aRoot,
mCSSEditUtils = MakeUnique<CSSEditUtils>(this);
// disable links
PresShell* presShell = GetPresShell();
if (NS_WARN_IF(!presShell)) {
Document* doc = GetDocument();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_FAILURE;
}
nsPresContext* context = presShell->GetPresContext();
NS_ENSURE_TRUE(context, NS_ERROR_NULL_POINTER);
if (!IsPlaintextEditor() && !IsInteractionAllowed()) {
mLinkHandler = context->GetLinkHandler();
context->SetLinkHandler(nullptr);
mDisabledLinkHandling = true;
mOldLinkHandlingEnabled = doc->LinkHandlingEnabled();
doc->SetLinkHandlingEnabled(false);
}
// init the type-in state

View File

@ -36,7 +36,6 @@ class nsDocumentFragment;
class nsHTMLDocument;
class nsITransferable;
class nsIClipboard;
class nsILinkHandler;
class nsTableWrapperFrame;
class nsRange;
@ -2626,7 +2625,8 @@ class HTMLEditor final : public TextEditor,
void AddMouseClickListener(Element* aElement);
void RemoveMouseClickListener(Element* aElement);
nsCOMPtr<nsILinkHandler> mLinkHandler;
bool mDisabledLinkHandling = false;
bool mOldLinkHandlingEnabled = false;
ParagraphSeparator mDefaultParagraphSeparator;

View File

@ -1379,9 +1379,6 @@ void PresShell::Destroy() {
// to us. To avoid the pres context having a dangling reference, set its
// pres shell to nullptr
mPresContext->DetachPresShell();
// Clear the link handler (weak reference) as well
mPresContext->SetLinkHandler(nullptr);
}
mHaveShutDown = true;

View File

@ -950,13 +950,6 @@ nsresult nsDocumentViewer::InitInternal(nsIWidget* aParentWidget,
nsCOMPtr<nsIInterfaceRequestor> requestor(mContainer);
if (requestor) {
if (mPresContext) {
nsCOMPtr<nsILinkHandler> linkHandler;
requestor->GetInterface(NS_GET_IID(nsILinkHandler),
getter_AddRefs(linkHandler));
mPresContext->SetLinkHandler(linkHandler);
}
// Set script-context-owner in the document
nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(requestor);
@ -1539,11 +1532,6 @@ static void AttachContainerRecurse(nsIDocShell* aShell) {
if (doc) {
doc->SetContainer(static_cast<nsDocShell*>(aShell));
}
RefPtr<nsPresContext> pc = viewer->GetPresContext();
if (pc) {
nsCOMPtr<nsILinkHandler> handler = do_QueryInterface(aShell);
pc->SetLinkHandler(handler);
}
if (PresShell* presShell = viewer->GetPresShell()) {
presShell->SetForwardingContainer(WeakPtr<nsDocShell>());
}
@ -1696,14 +1684,9 @@ static void DetachContainerRecurse(nsIDocShell* aShell) {
nsCOMPtr<nsIContentViewer> viewer;
aShell->GetContentViewer(getter_AddRefs(viewer));
if (viewer) {
Document* doc = viewer->GetDocument();
if (doc) {
if (Document* doc = viewer->GetDocument()) {
doc->SetContainer(nullptr);
}
RefPtr<nsPresContext> pc = viewer->GetPresContext();
if (pc) {
pc->Detach();
}
if (PresShell* presShell = viewer->GetPresShell()) {
auto weakShell = static_cast<nsDocShell*>(aShell);
presShell->SetForwardingContainer(weakShell);
@ -1844,9 +1827,6 @@ nsDocumentViewer::Destroy() {
if (mDocument) {
mDocument->SetContainer(nullptr);
}
if (mPresContext) {
mPresContext->Detach();
}
if (mPresShell) {
mPresShell->SetForwardingContainer(mContainer);
}
@ -2258,14 +2238,6 @@ nsDocumentViewer::Show(void) {
containerView);
if (NS_FAILED(rv)) return rv;
if (mPresContext && base_win) {
nsCOMPtr<nsILinkHandler> linkHandler(do_GetInterface(base_win));
if (linkHandler) {
mPresContext->SetLinkHandler(linkHandler);
}
}
if (mPresContext) {
Hide();
@ -4209,7 +4181,6 @@ void nsDocumentViewer::DestroyPresShell() {
}
void nsDocumentViewer::DestroyPresContext() {
mPresContext->Detach();
mPresContext = nullptr;
}

View File

@ -145,7 +145,6 @@ nsPresContext::nsPresContext(dom::Document* aDocument, nsPresContextType aType)
mDocument(aDocument),
mMedium(aType == eContext_Galley ? nsGkAtoms::screen : nsGkAtoms::print),
mMediaEmulated(mMedium),
mLinkHandler(nullptr),
mInflationDisabledForShrinkWrap(false),
mSystemFontScale(1.0),
mTextZoom(1.0),
@ -1132,9 +1131,6 @@ nsIDocShell* nsPresContext::GetDocShell() const {
return mDocument->GetDocShell();
}
/* virtual */
void nsPresContext::Detach() { SetLinkHandler(nullptr); }
bool nsPresContext::BidiEnabled() const { return Document()->GetBidiEnabled(); }
void nsPresContext::SetBidiEnabled() const { Document()->SetBidiEnabled(); }
@ -2470,12 +2466,6 @@ nsRootPresContext::~nsRootPresContext() {
CancelApplyPluginGeometryTimer();
}
/* virtual */
void nsRootPresContext::Detach() {
// XXXmats maybe also CancelApplyPluginGeometryTimer(); ?
nsPresContext::Detach();
}
void nsRootPresContext::RegisterPluginForGeometryUpdates(nsIContent* aPlugin) {
mRegisteredPlugins.PutEntry(aPlugin);
}

View File

@ -347,17 +347,6 @@ class nsPresContext : public nsISupports,
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), etc.
* Only to be used by the DocumentViewer.
*/
virtual void Detach();
/**
* Get the visible area associated with this presentation context.
* This is the size of the visible area that is used for
@ -1135,10 +1124,6 @@ class nsPresContext : public nsISupports,
RefPtr<nsAtom> mMediaEmulated;
RefPtr<gfxFontFeatureValueSet> mFontFeatureValuesLookup;
// 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;
public:
// The following are public member variables so that we can use them
// with mozilla::AutoToggle or mozilla::AutoRestore.
@ -1304,7 +1289,6 @@ class nsRootPresContext final : public nsPresContext {
public:
nsRootPresContext(mozilla::dom::Document* aDocument, nsPresContextType aType);
virtual ~nsRootPresContext();
virtual void Detach() override;
/**
* Registers a plugin to receive geometry updates (position and clip

View File

@ -2270,8 +2270,8 @@ nsresult nsImageFrame::HandleEvent(nsPresContext* aPresContext,
*aEventStatus = nsEventStatus_eConsumeDoDefault;
clicked = true;
}
nsContentUtils::TriggerLink(anchorNode, aPresContext, uri, target,
clicked, /* isTrusted */ true);
nsContentUtils::TriggerLink(anchorNode, uri, target, clicked,
/* isTrusted */ true);
}
}
}

View File

@ -1,4 +0,0 @@
[blob-url-in-main-window-self-navigate-inherits.sub.html]
[Violation report status OK.]
expected: FAIL

View File

@ -1,4 +0,0 @@
[activation-behavior.window.html]
[<a> that is not connected should be followed]
expected: FAIL