mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
Issue #2721 - Create special case exception for <A>.Click() outside of DOM
This removes the requirement for there to be a non-null PresShell to dispatch `Click()` events on `<A>` elements (only), since the exception to the rule has propagated to the spec. With these changes it should now be possible do create an anchor and `Click()` on it from JS without actually first attaching it to the DOM of the presented document, as abused by scripted downloads in pages (instead of using the A attribute to custom-name downloads).
This commit is contained in:
parent
72a17a5284
commit
37de431ac0
15 changed files with 79 additions and 94 deletions
|
|
@ -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<nsIDOMElement> 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<nsIPresShell> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<nsIPrincipal>* 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<nsIDocShell> 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1288,6 +1288,7 @@ nsIDocument::nsIDocument()
|
|||
|
||||
nsDocument::nsDocument(const char* aContentType)
|
||||
: nsIDocument()
|
||||
, mLinksEnabled(true)
|
||||
, mViewportType(Unknown)
|
||||
{
|
||||
SetContentTypeInternal(nsDependentCString(aContentType));
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -581,17 +581,16 @@ nsGenericHTMLElement::FindAncestorForm(HTMLFormElement* aCurrentForm)
|
|||
}
|
||||
|
||||
bool
|
||||
nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(
|
||||
EventChainVisitor& aVisitor)
|
||||
nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(EventChainVisitor& aVisitor)
|
||||
{
|
||||
NS_PRECONDITION(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 not in the composed document DOM, only <a> 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
|
||||
|
|
|
|||
|
|
@ -165,11 +165,10 @@ HTMLEditor::~HTMLEditor()
|
|||
// free any default style propItems
|
||||
RemoveAllDefaultProperties();
|
||||
|
||||
if (mLinkHandler && IsInitialized()) {
|
||||
nsCOMPtr<nsIPresShell> ps = GetPresShell();
|
||||
|
||||
if (ps && ps->GetPresContext()) {
|
||||
ps->GetPresContext()->SetLinkHandler(mLinkHandler);
|
||||
if (mDisabledLinkHandling) {
|
||||
nsCOMPtr<nsIDocument> doc = GetDocument();
|
||||
if (doc) {
|
||||
doc->SetLinkHandlingEnabled(mOldLinkHandlingEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -290,13 +289,14 @@ HTMLEditor::Init(nsIDOMDocument* aDoc,
|
|||
mCSSEditUtils = MakeUnique<CSSEditUtils>(this);
|
||||
|
||||
// disable links
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
nsPresContext *context = presShell->GetPresContext();
|
||||
NS_ENSURE_TRUE(context, NS_ERROR_NULL_POINTER);
|
||||
nsCOMPtr<nsIDocument> 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
|
||||
|
|
|
|||
|
|
@ -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<nsILinkHandler> mLinkHandler;
|
||||
bool mDisabledLinkHandling = false;
|
||||
bool mOldLinkHandlingEnabled = false;
|
||||
|
||||
public:
|
||||
friend class HTMLEditorEventListener;
|
||||
|
|
|
|||
|
|
@ -910,12 +910,7 @@ 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->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<nsDocShell*>(aShell));
|
||||
nsCOMPtr<nsILinkHandler> handler = do_QueryInterface(aShell);
|
||||
pc->SetLinkHandler(handler);
|
||||
}
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
viewer->GetPresShell(getter_AddRefs(presShell));
|
||||
|
|
@ -2146,12 +2139,6 @@ nsDocumentViewer::Show(void)
|
|||
return rv;
|
||||
|
||||
if (mPresContext && base_win) {
|
||||
nsCOMPtr<nsILinkHandler> linkHandler(do_GetInterface(base_win));
|
||||
|
||||
if (linkHandler) {
|
||||
mPresContext->SetLinkHandler(linkHandler);
|
||||
}
|
||||
|
||||
mPresContext->SetContainer(mContainer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1504,7 +1504,6 @@ nsPresContext::GetDocShell() const
|
|||
nsPresContext::Detach()
|
||||
{
|
||||
SetContainer(nullptr);
|
||||
SetLinkHandler(nullptr);
|
||||
if (mShell) {
|
||||
mShell->CancelInvalidatePresShellIfHidden();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<nsIAtom> 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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue