mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 20:25:44 +00:00
6ebcecc30e
We attach it to WorkerPrivate and DOMNavigationTiming so it will be re-used when it should. WorkerPrivate is used in the Performance APIs, Performance Storage Worker, and Event. DOMNavigationTiming is used only in the Performance APIs, but the crucial part is that when the individual DOMNavigationTiming object is re-used, so will the context seed. This in particular came up with the nav2_test_document_open.html Web Platform Test which illustrated the fact that even if you .open() a new document, the performance navigation data is not supposed to change. MozReview-Commit-ID: GIv6biEo2jY --HG-- extra : rebase_source : da2ad8d9d6e0172679c6af14dba72938e9d2012c
1291 lines
33 KiB
C++
1291 lines
33 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "AccessCheck.h"
|
|
#include "base/basictypes.h"
|
|
#include "ipc/IPCMessageUtils.h"
|
|
#include "mozilla/dom/Event.h"
|
|
#include "mozilla/dom/ShadowRoot.h"
|
|
#include "mozilla/ContentEvents.h"
|
|
#include "mozilla/DOMEventTargetHelper.h"
|
|
#include "mozilla/EventStateManager.h"
|
|
#include "mozilla/InternalMutationEvent.h"
|
|
#include "mozilla/dom/Performance.h"
|
|
#include "mozilla/dom/WorkerPrivate.h"
|
|
#include "mozilla/MiscEvents.h"
|
|
#include "mozilla/MouseEvents.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "mozilla/TextEvents.h"
|
|
#include "mozilla/TouchEvents.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsDeviceContext.h"
|
|
#include "nsError.h"
|
|
#include "nsGlobalWindow.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsIContent.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsIScrollableFrame.h"
|
|
#include "nsJSEnvironment.h"
|
|
#include "nsLayoutUtils.h"
|
|
#include "nsPIWindowRoot.h"
|
|
#include "nsRFPService.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
static char *sPopupAllowedEvents;
|
|
|
|
static bool sReturnHighResTimeStamp = false;
|
|
static bool sReturnHighResTimeStampIsSet = false;
|
|
|
|
Event::Event(EventTarget* aOwner,
|
|
nsPresContext* aPresContext,
|
|
WidgetEvent* aEvent)
|
|
{
|
|
ConstructorInit(aOwner, aPresContext, aEvent);
|
|
}
|
|
|
|
Event::Event(nsPIDOMWindowInner* aParent)
|
|
{
|
|
ConstructorInit(nsGlobalWindowInner::Cast(aParent), nullptr, nullptr);
|
|
}
|
|
|
|
void
|
|
Event::ConstructorInit(EventTarget* aOwner,
|
|
nsPresContext* aPresContext,
|
|
WidgetEvent* aEvent)
|
|
{
|
|
SetOwner(aOwner);
|
|
mIsMainThreadEvent = NS_IsMainThread();
|
|
|
|
if (mIsMainThreadEvent && !sReturnHighResTimeStampIsSet) {
|
|
Preferences::AddBoolVarCache(&sReturnHighResTimeStamp,
|
|
"dom.event.highrestimestamp.enabled",
|
|
sReturnHighResTimeStamp);
|
|
sReturnHighResTimeStampIsSet = true;
|
|
}
|
|
|
|
mPrivateDataDuplicated = false;
|
|
mWantsPopupControlCheck = false;
|
|
|
|
if (aEvent) {
|
|
mEvent = aEvent;
|
|
mEventIsInternal = false;
|
|
}
|
|
else {
|
|
mEventIsInternal = true;
|
|
/*
|
|
A derived class might want to allocate its own type of aEvent
|
|
(derived from WidgetEvent). To do this, it should take care to pass
|
|
a non-nullptr aEvent to this ctor, e.g.:
|
|
|
|
FooEvent::FooEvent(..., WidgetEvent* aEvent)
|
|
: Event(..., aEvent ? aEvent : new WidgetEvent())
|
|
|
|
Then, to override the mEventIsInternal assignments done by the
|
|
base ctor, it should do this in its own ctor:
|
|
|
|
FooEvent::FooEvent(..., WidgetEvent* aEvent)
|
|
...
|
|
{
|
|
...
|
|
if (aEvent) {
|
|
mEventIsInternal = false;
|
|
}
|
|
else {
|
|
mEventIsInternal = true;
|
|
}
|
|
...
|
|
}
|
|
*/
|
|
mEvent = new WidgetEvent(false, eVoidEvent);
|
|
mEvent->mTime = PR_Now();
|
|
}
|
|
|
|
InitPresContextData(aPresContext);
|
|
}
|
|
|
|
void
|
|
Event::InitPresContextData(nsPresContext* aPresContext)
|
|
{
|
|
mPresContext = aPresContext;
|
|
// Get the explicit original target (if it's anonymous make it null)
|
|
{
|
|
nsCOMPtr<nsIContent> content = GetTargetFromFrame();
|
|
mExplicitOriginalTarget = content;
|
|
if (content && content->IsInAnonymousSubtree()) {
|
|
mExplicitOriginalTarget = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
Event::~Event()
|
|
{
|
|
NS_ASSERT_OWNINGTHREAD(Event);
|
|
|
|
if (mEventIsInternal && mEvent) {
|
|
delete mEvent;
|
|
}
|
|
}
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEvent)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(Event)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(Event)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(Event)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
|
|
if (tmp->mEventIsInternal) {
|
|
tmp->mEvent->mTarget = nullptr;
|
|
tmp->mEvent->mCurrentTarget = nullptr;
|
|
tmp->mEvent->mOriginalTarget = nullptr;
|
|
tmp->mEvent->mRelatedTarget = nullptr;
|
|
tmp->mEvent->mOriginalRelatedTarget = nullptr;
|
|
switch (tmp->mEvent->mClass) {
|
|
case eDragEventClass: {
|
|
WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
|
|
dragEvent->mDataTransfer = nullptr;
|
|
break;
|
|
}
|
|
case eClipboardEventClass:
|
|
tmp->mEvent->AsClipboardEvent()->mClipboardData = nullptr;
|
|
break;
|
|
case eMutationEventClass:
|
|
tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
|
|
if (tmp->mEventIsInternal) {
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalRelatedTarget);
|
|
switch (tmp->mEvent->mClass) {
|
|
case eDragEventClass: {
|
|
WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
|
|
cb.NoteXPCOMChild(dragEvent->mDataTransfer);
|
|
break;
|
|
}
|
|
case eClipboardEventClass:
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClipboardData");
|
|
cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->mClipboardData);
|
|
break;
|
|
case eMutationEventClass:
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
|
|
cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
JSObject*
|
|
Event::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
{
|
|
return WrapObjectInternal(aCx, aGivenProto);
|
|
}
|
|
|
|
JSObject*
|
|
Event::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
{
|
|
return EventBinding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
// nsIDOMEventInterface
|
|
NS_IMETHODIMP
|
|
Event::GetType(nsAString& aType)
|
|
{
|
|
if (!mIsMainThreadEvent) {
|
|
aType = mEvent->mSpecifiedEventTypeString;
|
|
return NS_OK;
|
|
}
|
|
GetWidgetEventType(mEvent, aType);
|
|
return NS_OK;
|
|
}
|
|
|
|
EventTarget*
|
|
Event::GetTarget() const
|
|
{
|
|
return mEvent->GetDOMEventTarget();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetTarget(nsIDOMEventTarget** aTarget)
|
|
{
|
|
NS_IF_ADDREF(*aTarget = GetTarget());
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
Event::IsSrcElementEnabled(JSContext* /* unused */, JSObject* /* unused */)
|
|
{
|
|
// Not a pref, because that's a pain on workers.
|
|
#ifdef NIGHTLY_BUILD
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
EventTarget*
|
|
Event::GetCurrentTarget() const
|
|
{
|
|
return mEvent->GetCurrentDOMEventTarget();
|
|
}
|
|
|
|
void
|
|
Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath)
|
|
{
|
|
EventDispatcher::GetComposedPathFor(mEvent, aPath);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
|
|
{
|
|
NS_IF_ADDREF(*aCurrentTarget = GetCurrentTarget());
|
|
return NS_OK;
|
|
}
|
|
|
|
//
|
|
// Get the actual event target node (may have been retargeted for mouse events)
|
|
//
|
|
already_AddRefed<nsIContent>
|
|
Event::GetTargetFromFrame()
|
|
{
|
|
if (!mPresContext) { return nullptr; }
|
|
|
|
// Get the mTarget frame (have to get the ESM first)
|
|
nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
|
|
if (!targetFrame) { return nullptr; }
|
|
|
|
// get the real content
|
|
nsCOMPtr<nsIContent> realEventContent;
|
|
targetFrame->GetContentForEvent(mEvent, getter_AddRefs(realEventContent));
|
|
return realEventContent.forget();
|
|
}
|
|
|
|
EventTarget*
|
|
Event::GetExplicitOriginalTarget() const
|
|
{
|
|
if (mExplicitOriginalTarget) {
|
|
return mExplicitOriginalTarget;
|
|
}
|
|
return GetTarget();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetExplicitOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
|
|
{
|
|
NS_IF_ADDREF(*aRealEventTarget = GetExplicitOriginalTarget());
|
|
return NS_OK;
|
|
}
|
|
|
|
EventTarget*
|
|
Event::GetOriginalTarget() const
|
|
{
|
|
return mEvent->GetOriginalDOMEventTarget();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget)
|
|
{
|
|
NS_IF_ADDREF(*aOriginalTarget = GetOriginalTarget());
|
|
return NS_OK;
|
|
}
|
|
|
|
EventTarget*
|
|
Event::GetComposedTarget() const
|
|
{
|
|
EventTarget* et = GetOriginalTarget();
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(et);
|
|
if (!content) {
|
|
return et;
|
|
}
|
|
nsIContent* nonChrome = content->FindFirstNonChromeOnlyAccessContent();
|
|
return nonChrome ?
|
|
static_cast<EventTarget*>(nonChrome) :
|
|
static_cast<EventTarget*>(content->GetComposedDoc());
|
|
}
|
|
|
|
NS_IMETHODIMP_(void)
|
|
Event::SetTrusted(bool aTrusted)
|
|
{
|
|
mEvent->mFlags.mIsTrusted = aTrusted;
|
|
}
|
|
|
|
bool
|
|
Event::Init(mozilla::dom::EventTarget* aGlobal)
|
|
{
|
|
if (!mIsMainThreadEvent) {
|
|
return IsCurrentThreadRunningChromeWorker();
|
|
}
|
|
bool trusted = false;
|
|
nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(aGlobal);
|
|
if (w) {
|
|
nsCOMPtr<nsIDocument> d = w->GetExtantDoc();
|
|
if (d) {
|
|
trusted = nsContentUtils::IsChromeDoc(d);
|
|
nsPresContext* presContext = d->GetPresContext();
|
|
if (presContext) {
|
|
InitPresContextData(presContext);
|
|
}
|
|
}
|
|
}
|
|
return trusted;
|
|
}
|
|
|
|
// static
|
|
already_AddRefed<Event>
|
|
Event::Constructor(const GlobalObject& aGlobal,
|
|
const nsAString& aType,
|
|
const EventInit& aParam,
|
|
ErrorResult& aRv)
|
|
{
|
|
nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
|
|
return Constructor(t, aType, aParam);
|
|
}
|
|
|
|
// static
|
|
already_AddRefed<Event>
|
|
Event::Constructor(EventTarget* aEventTarget,
|
|
const nsAString& aType,
|
|
const EventInit& aParam)
|
|
{
|
|
RefPtr<Event> e = new Event(aEventTarget, nullptr, nullptr);
|
|
bool trusted = e->Init(aEventTarget);
|
|
e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
|
|
e->SetTrusted(trusted);
|
|
e->SetComposed(aParam.mComposed);
|
|
return e.forget();
|
|
}
|
|
|
|
uint16_t
|
|
Event::EventPhase() const
|
|
{
|
|
// Note, remember to check that this works also
|
|
// if or when Bug 235441 is fixed.
|
|
if ((mEvent->mCurrentTarget &&
|
|
mEvent->mCurrentTarget == mEvent->mTarget) ||
|
|
mEvent->mFlags.InTargetPhase()) {
|
|
return nsIDOMEvent::AT_TARGET;
|
|
}
|
|
if (mEvent->mFlags.mInCapturePhase) {
|
|
return nsIDOMEvent::CAPTURING_PHASE;
|
|
}
|
|
if (mEvent->mFlags.mInBubblingPhase) {
|
|
return nsIDOMEvent::BUBBLING_PHASE;
|
|
}
|
|
return nsIDOMEvent::NONE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetEventPhase(uint16_t* aEventPhase)
|
|
{
|
|
*aEventPhase = EventPhase();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetBubbles(bool* aBubbles)
|
|
{
|
|
*aBubbles = Bubbles();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetCancelable(bool* aCancelable)
|
|
{
|
|
*aCancelable = Cancelable();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetTimeStamp(uint64_t* aTimeStamp)
|
|
{
|
|
*aTimeStamp = mEvent->mTime;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::StopPropagation()
|
|
{
|
|
mEvent->StopPropagation();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::StopImmediatePropagation()
|
|
{
|
|
mEvent->StopImmediatePropagation();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::StopCrossProcessForwarding()
|
|
{
|
|
mEvent->StopCrossProcessForwarding();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetIsTrusted(bool* aIsTrusted)
|
|
{
|
|
*aIsTrusted = IsTrusted();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::PreventDefault()
|
|
{
|
|
// This method is called only from C++ code which must handle default action
|
|
// of this event. So, pass true always.
|
|
PreventDefaultInternal(true);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
Event::PreventDefault(JSContext* aCx, CallerType aCallerType)
|
|
{
|
|
// Note that at handling default action, another event may be dispatched.
|
|
// Then, JS in content mey be call preventDefault()
|
|
// even in the event is in system event group. Therefore, don't refer
|
|
// mInSystemGroup here.
|
|
nsIPrincipal* principal = mIsMainThreadEvent ?
|
|
nsContentUtils::SubjectPrincipal(aCx) : nullptr;
|
|
|
|
PreventDefaultInternal(aCallerType == CallerType::System, principal);
|
|
}
|
|
|
|
void
|
|
Event::PreventDefaultInternal(bool aCalledByDefaultHandler,
|
|
nsIPrincipal* aPrincipal)
|
|
{
|
|
if (!mEvent->mFlags.mCancelable) {
|
|
return;
|
|
}
|
|
if (mEvent->mFlags.mInPassiveListener) {
|
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(mOwner));
|
|
if (win) {
|
|
if (nsIDocument* doc = win->GetExtantDoc()) {
|
|
nsString type;
|
|
GetType(type);
|
|
const char16_t* params[] = { type.get() };
|
|
doc->WarnOnceAbout(nsIDocument::ePreventDefaultFromPassiveListener,
|
|
false, params, ArrayLength(params));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
mEvent->PreventDefault(aCalledByDefaultHandler, aPrincipal);
|
|
|
|
if (!IsTrusted()) {
|
|
return;
|
|
}
|
|
|
|
WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
|
|
if (!dragEvent) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->mCurrentTarget);
|
|
if (!node) {
|
|
nsCOMPtr<nsPIDOMWindowOuter> win =
|
|
do_QueryInterface(mEvent->mCurrentTarget);
|
|
if (!win) {
|
|
return;
|
|
}
|
|
node = win->GetExtantDoc();
|
|
}
|
|
if (!nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
|
|
dragEvent->mDefaultPreventedOnContent = true;
|
|
}
|
|
}
|
|
|
|
void
|
|
Event::SetEventType(const nsAString& aEventTypeArg)
|
|
{
|
|
if (mIsMainThreadEvent) {
|
|
mEvent->mSpecifiedEventTypeString.Truncate();
|
|
mEvent->mSpecifiedEventType =
|
|
nsContentUtils::GetEventMessageAndAtom(aEventTypeArg, mEvent->mClass,
|
|
&(mEvent->mMessage));
|
|
mEvent->SetDefaultComposed();
|
|
} else {
|
|
mEvent->mSpecifiedEventType = nullptr;
|
|
mEvent->mMessage = eUnidentifiedEvent;
|
|
mEvent->mSpecifiedEventTypeString = aEventTypeArg;
|
|
mEvent->SetComposed(aEventTypeArg);
|
|
}
|
|
mEvent->SetDefaultComposedInNativeAnonymousContent();
|
|
}
|
|
|
|
already_AddRefed<EventTarget>
|
|
Event::EnsureWebAccessibleRelatedTarget(EventTarget* aRelatedTarget)
|
|
{
|
|
nsCOMPtr<EventTarget> relatedTarget = aRelatedTarget;
|
|
if (relatedTarget) {
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
|
|
|
|
if (content && content->ChromeOnlyAccess() &&
|
|
!nsContentUtils::CanAccessNativeAnon()) {
|
|
content = content->FindFirstNonChromeOnlyAccessContent();
|
|
relatedTarget = do_QueryInterface(content);
|
|
}
|
|
|
|
if (relatedTarget) {
|
|
relatedTarget = relatedTarget->GetTargetForDOMEvent();
|
|
}
|
|
}
|
|
return relatedTarget.forget();
|
|
}
|
|
|
|
void
|
|
Event::InitEvent(const nsAString& aEventTypeArg,
|
|
bool aCanBubbleArg,
|
|
bool aCancelableArg)
|
|
{
|
|
// Make sure this event isn't already being dispatched.
|
|
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
|
|
|
|
if (IsTrusted()) {
|
|
// Ensure the caller is permitted to dispatch trusted DOM events.
|
|
if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
|
|
SetTrusted(false);
|
|
}
|
|
}
|
|
|
|
SetEventType(aEventTypeArg);
|
|
|
|
mEvent->mFlags.mBubbles = aCanBubbleArg;
|
|
mEvent->mFlags.mCancelable = aCancelableArg;
|
|
|
|
mEvent->mFlags.mDefaultPrevented = false;
|
|
mEvent->mFlags.mDefaultPreventedByContent = false;
|
|
mEvent->mFlags.mDefaultPreventedByChrome = false;
|
|
mEvent->mFlags.mPropagationStopped = false;
|
|
mEvent->mFlags.mImmediatePropagationStopped = false;
|
|
|
|
// Clearing the old targets, so that the event is targeted correctly when
|
|
// re-dispatching it.
|
|
mEvent->mTarget = nullptr;
|
|
mEvent->mOriginalTarget = nullptr;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::DuplicatePrivateData()
|
|
{
|
|
NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
|
|
if (mEventIsInternal) {
|
|
return NS_OK;
|
|
}
|
|
|
|
mEvent = mEvent->Duplicate();
|
|
mPresContext = nullptr;
|
|
mEventIsInternal = true;
|
|
mPrivateDataDuplicated = true;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::SetTarget(nsIDOMEventTarget* aTarget)
|
|
{
|
|
mEvent->mTarget = do_QueryInterface(aTarget);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP_(bool)
|
|
Event::IsDispatchStopped()
|
|
{
|
|
return mEvent->PropagationStopped();
|
|
}
|
|
|
|
NS_IMETHODIMP_(WidgetEvent*)
|
|
Event::WidgetEventPtr()
|
|
{
|
|
return mEvent;
|
|
}
|
|
|
|
NS_IMETHODIMP_(Event*)
|
|
Event::InternalDOMEvent()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
// return true if eventName is contained within events, delimited by
|
|
// spaces
|
|
static bool
|
|
PopupAllowedForEvent(const char *eventName)
|
|
{
|
|
if (!sPopupAllowedEvents) {
|
|
Event::PopupAllowedEventsChanged();
|
|
|
|
if (!sPopupAllowedEvents) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
nsDependentCString events(sPopupAllowedEvents);
|
|
|
|
nsCString::const_iterator start, end;
|
|
nsCString::const_iterator startiter(events.BeginReading(start));
|
|
events.EndReading(end);
|
|
|
|
while (startiter != end) {
|
|
nsCString::const_iterator enditer(end);
|
|
|
|
if (!FindInReadable(nsDependentCString(eventName), startiter, enditer))
|
|
return false;
|
|
|
|
// the match is surrounded by spaces, or at a string boundary
|
|
if ((startiter == start || *--startiter == ' ') &&
|
|
(enditer == end || *enditer == ' ')) {
|
|
return true;
|
|
}
|
|
|
|
// Move on and see if there are other matches. (The delimitation
|
|
// requirement makes it pointless to begin the next search before
|
|
// the end of the invalid match just found.)
|
|
startiter = enditer;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// static
|
|
PopupControlState
|
|
Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
|
|
{
|
|
// generally if an event handler is running, new windows are disallowed.
|
|
// check for exceptions:
|
|
PopupControlState abuse = openAbused;
|
|
|
|
if (aDOMEvent && aDOMEvent->InternalDOMEvent()->GetWantsPopupControlCheck()) {
|
|
nsAutoString type;
|
|
aDOMEvent->GetType(type);
|
|
if (PopupAllowedForEvent(NS_ConvertUTF16toUTF8(type).get())) {
|
|
return openAllowed;
|
|
}
|
|
}
|
|
|
|
switch(aEvent->mClass) {
|
|
case eBasicEventClass:
|
|
// For these following events only allow popups if they're
|
|
// triggered while handling user input. See
|
|
// nsPresShell::HandleEventInternal() for details.
|
|
if (EventStateManager::IsHandlingUserInput()) {
|
|
abuse = openBlocked;
|
|
switch(aEvent->mMessage) {
|
|
case eFormSelect:
|
|
if (PopupAllowedForEvent("select")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case eFormChange:
|
|
if (PopupAllowedForEvent("change")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case eEditorInputEventClass:
|
|
// For this following event only allow popups if it's triggered
|
|
// while handling user input. See
|
|
// nsPresShell::HandleEventInternal() for details.
|
|
if (EventStateManager::IsHandlingUserInput()) {
|
|
abuse = openBlocked;
|
|
switch(aEvent->mMessage) {
|
|
case eEditorInput:
|
|
if (PopupAllowedForEvent("input")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case eInputEventClass:
|
|
// For this following event only allow popups if it's triggered
|
|
// while handling user input. See
|
|
// nsPresShell::HandleEventInternal() for details.
|
|
if (EventStateManager::IsHandlingUserInput()) {
|
|
abuse = openBlocked;
|
|
switch(aEvent->mMessage) {
|
|
case eFormChange:
|
|
if (PopupAllowedForEvent("change")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case eXULCommand:
|
|
abuse = openControlled;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case eKeyboardEventClass:
|
|
if (aEvent->IsTrusted()) {
|
|
abuse = openBlocked;
|
|
uint32_t key = aEvent->AsKeyboardEvent()->mKeyCode;
|
|
switch(aEvent->mMessage) {
|
|
case eKeyPress:
|
|
// return key on focused button. see note at eMouseClick.
|
|
if (key == NS_VK_RETURN) {
|
|
abuse = openAllowed;
|
|
} else if (PopupAllowedForEvent("keypress")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case eKeyUp:
|
|
// space key on focused button. see note at eMouseClick.
|
|
if (key == NS_VK_SPACE) {
|
|
abuse = openAllowed;
|
|
} else if (PopupAllowedForEvent("keyup")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case eKeyDown:
|
|
if (PopupAllowedForEvent("keydown")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case eTouchEventClass:
|
|
if (aEvent->IsTrusted()) {
|
|
abuse = openBlocked;
|
|
switch (aEvent->mMessage) {
|
|
case eTouchStart:
|
|
if (PopupAllowedForEvent("touchstart")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case eTouchEnd:
|
|
if (PopupAllowedForEvent("touchend")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case eMouseEventClass:
|
|
if (aEvent->IsTrusted() &&
|
|
aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
|
|
abuse = openBlocked;
|
|
switch(aEvent->mMessage) {
|
|
case eMouseUp:
|
|
if (PopupAllowedForEvent("mouseup")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case eMouseDown:
|
|
if (PopupAllowedForEvent("mousedown")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case eMouseClick:
|
|
/* Click events get special treatment because of their
|
|
historical status as a more legitimate event handler. If
|
|
click popups are enabled in the prefs, clear the popup
|
|
status completely. */
|
|
if (PopupAllowedForEvent("click")) {
|
|
abuse = openAllowed;
|
|
}
|
|
break;
|
|
case eMouseDoubleClick:
|
|
if (PopupAllowedForEvent("dblclick")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case ePointerEventClass:
|
|
if (aEvent->IsTrusted() &&
|
|
aEvent->AsPointerEvent()->button == WidgetMouseEvent::eLeftButton) {
|
|
switch(aEvent->mMessage) {
|
|
case ePointerUp:
|
|
if (PopupAllowedForEvent("pointerup")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case ePointerDown:
|
|
if (PopupAllowedForEvent("pointerdown")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case eFormEventClass:
|
|
// For these following events only allow popups if they're
|
|
// triggered while handling user input. See
|
|
// nsPresShell::HandleEventInternal() for details.
|
|
if (EventStateManager::IsHandlingUserInput()) {
|
|
abuse = openBlocked;
|
|
switch(aEvent->mMessage) {
|
|
case eFormSubmit:
|
|
if (PopupAllowedForEvent("submit")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
case eFormReset:
|
|
if (PopupAllowedForEvent("reset")) {
|
|
abuse = openControlled;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return abuse;
|
|
}
|
|
|
|
// static
|
|
void
|
|
Event::PopupAllowedEventsChanged()
|
|
{
|
|
if (sPopupAllowedEvents) {
|
|
free(sPopupAllowedEvents);
|
|
}
|
|
|
|
nsAutoCString str;
|
|
Preferences::GetCString("dom.popup_allowed_events", str);
|
|
|
|
// We'll want to do this even if str is empty to avoid looking up
|
|
// this pref all the time if it's not set.
|
|
sPopupAllowedEvents = ToNewCString(str);
|
|
}
|
|
|
|
// static
|
|
void
|
|
Event::Shutdown()
|
|
{
|
|
if (sPopupAllowedEvents) {
|
|
free(sPopupAllowedEvents);
|
|
}
|
|
}
|
|
|
|
// static
|
|
CSSIntPoint
|
|
Event::GetScreenCoords(nsPresContext* aPresContext,
|
|
WidgetEvent* aEvent,
|
|
LayoutDeviceIntPoint aPoint)
|
|
{
|
|
if (EventStateManager::sIsPointerLocked) {
|
|
return EventStateManager::sLastScreenPoint;
|
|
}
|
|
|
|
if (!aEvent ||
|
|
(aEvent->mClass != eMouseEventClass &&
|
|
aEvent->mClass != eMouseScrollEventClass &&
|
|
aEvent->mClass != eWheelEventClass &&
|
|
aEvent->mClass != ePointerEventClass &&
|
|
aEvent->mClass != eTouchEventClass &&
|
|
aEvent->mClass != eDragEventClass &&
|
|
aEvent->mClass != eSimpleGestureEventClass)) {
|
|
return CSSIntPoint(0, 0);
|
|
}
|
|
|
|
// Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
|
|
// seem incorrect, but it is needed to maintain legacy functionality.
|
|
WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
|
|
if (!aPresContext || !(guiEvent && guiEvent->mWidget)) {
|
|
return CSSIntPoint(aPoint.x, aPoint.y);
|
|
}
|
|
|
|
nsPoint pt =
|
|
LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
|
|
|
|
if (nsIPresShell* ps = aPresContext->GetPresShell()) {
|
|
pt = pt.RemoveResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(ps));
|
|
}
|
|
|
|
pt += LayoutDevicePixel::ToAppUnits(guiEvent->mWidget->WidgetToScreenOffset(),
|
|
aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
|
|
|
|
return CSSPixel::FromAppUnitsRounded(pt);
|
|
}
|
|
|
|
// static
|
|
CSSIntPoint
|
|
Event::GetPageCoords(nsPresContext* aPresContext,
|
|
WidgetEvent* aEvent,
|
|
LayoutDeviceIntPoint aPoint,
|
|
CSSIntPoint aDefaultPoint)
|
|
{
|
|
CSSIntPoint pagePoint =
|
|
Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
|
|
|
|
// If there is some scrolling, add scroll info to client point.
|
|
if (aPresContext && aPresContext->GetPresShell()) {
|
|
nsIPresShell* shell = aPresContext->GetPresShell();
|
|
nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable();
|
|
if (scrollframe) {
|
|
pagePoint += CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
|
|
}
|
|
}
|
|
|
|
return pagePoint;
|
|
}
|
|
|
|
// static
|
|
CSSIntPoint
|
|
Event::GetClientCoords(nsPresContext* aPresContext,
|
|
WidgetEvent* aEvent,
|
|
LayoutDeviceIntPoint aPoint,
|
|
CSSIntPoint aDefaultPoint)
|
|
{
|
|
if (EventStateManager::sIsPointerLocked) {
|
|
return EventStateManager::sLastClientPoint;
|
|
}
|
|
|
|
if (!aEvent ||
|
|
(aEvent->mClass != eMouseEventClass &&
|
|
aEvent->mClass != eMouseScrollEventClass &&
|
|
aEvent->mClass != eWheelEventClass &&
|
|
aEvent->mClass != eTouchEventClass &&
|
|
aEvent->mClass != eDragEventClass &&
|
|
aEvent->mClass != ePointerEventClass &&
|
|
aEvent->mClass != eSimpleGestureEventClass) ||
|
|
!aPresContext ||
|
|
!aEvent->AsGUIEvent()->mWidget) {
|
|
return aDefaultPoint;
|
|
}
|
|
|
|
nsIPresShell* shell = aPresContext->GetPresShell();
|
|
if (!shell) {
|
|
return CSSIntPoint(0, 0);
|
|
}
|
|
nsIFrame* rootFrame = shell->GetRootFrame();
|
|
if (!rootFrame) {
|
|
return CSSIntPoint(0, 0);
|
|
}
|
|
nsPoint pt =
|
|
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aPoint, rootFrame);
|
|
|
|
return CSSIntPoint::FromAppUnitsRounded(pt);
|
|
}
|
|
|
|
// static
|
|
CSSIntPoint
|
|
Event::GetOffsetCoords(nsPresContext* aPresContext,
|
|
WidgetEvent* aEvent,
|
|
LayoutDeviceIntPoint aPoint,
|
|
CSSIntPoint aDefaultPoint)
|
|
{
|
|
if (!aEvent->mTarget) {
|
|
return GetPageCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
|
|
}
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->mTarget);
|
|
if (!content || !aPresContext) {
|
|
return CSSIntPoint(0, 0);
|
|
}
|
|
nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
|
|
if (!shell) {
|
|
return CSSIntPoint(0, 0);
|
|
}
|
|
shell->FlushPendingNotifications(FlushType::Layout);
|
|
nsIFrame* frame = content->GetPrimaryFrame();
|
|
if (!frame) {
|
|
return CSSIntPoint(0, 0);
|
|
}
|
|
nsIFrame* rootFrame = shell->GetRootFrame();
|
|
if (!rootFrame) {
|
|
return CSSIntPoint(0, 0);
|
|
}
|
|
CSSIntPoint clientCoords =
|
|
GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
|
|
nsPoint pt = CSSPixel::ToAppUnits(clientCoords);
|
|
if (nsLayoutUtils::TransformPoint(rootFrame, frame, pt) ==
|
|
nsLayoutUtils::TRANSFORM_SUCCEEDED) {
|
|
pt -= frame->GetPaddingRectRelativeToSelf().TopLeft();
|
|
return CSSPixel::FromAppUnitsRounded(pt);
|
|
}
|
|
return CSSIntPoint(0, 0);
|
|
}
|
|
|
|
// To be called ONLY by Event::GetType (which has the additional
|
|
// logic for handling user-defined events).
|
|
// static
|
|
const char*
|
|
Event::GetEventName(EventMessage aEventType)
|
|
{
|
|
switch(aEventType) {
|
|
#define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
|
|
case _message: return #name_;
|
|
#include "mozilla/EventNameList.h"
|
|
#undef MESSAGE_TO_EVENT
|
|
default:
|
|
break;
|
|
}
|
|
// XXXldb We can hit this case for WidgetEvent objects that we didn't
|
|
// create and that are not user defined events since this function and
|
|
// SetEventType are incomplete. (But fixing that requires fixing the
|
|
// arrays in nsEventListenerManager too, since the events for which
|
|
// this is a problem generally *are* created by Event.)
|
|
return nullptr;
|
|
}
|
|
|
|
bool
|
|
Event::DefaultPrevented(CallerType aCallerType) const
|
|
{
|
|
NS_ENSURE_TRUE(mEvent, false);
|
|
|
|
// If preventDefault() has never been called, just return false.
|
|
if (!mEvent->DefaultPrevented()) {
|
|
return false;
|
|
}
|
|
|
|
// If preventDefault() has been called by content, return true. Otherwise,
|
|
// i.e., preventDefault() has been called by chrome, return true only when
|
|
// this is called by chrome.
|
|
return mEvent->DefaultPreventedByContent() ||
|
|
aCallerType == CallerType::System;
|
|
}
|
|
|
|
double
|
|
Event::TimeStamp()
|
|
{
|
|
if (!sReturnHighResTimeStamp) {
|
|
// In the situation where you have set a very old, not-very-supported
|
|
// non-default preference, we will always reduce the precision,
|
|
// regardless of system principal or not.
|
|
// The timestamp is absolute, so we supply a zero context mix-in.
|
|
double ret = static_cast<double>(mEvent->mTime);
|
|
return nsRFPService::ReduceTimePrecisionAsMSecs(ret, 0);
|
|
}
|
|
|
|
if (mEvent->mTimeStamp.IsNull()) {
|
|
return 0.0;
|
|
}
|
|
|
|
if (mIsMainThreadEvent) {
|
|
if (NS_WARN_IF(!mOwner)) {
|
|
return 0.0;
|
|
}
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mOwner);
|
|
if (NS_WARN_IF(!win)) {
|
|
return 0.0;
|
|
}
|
|
|
|
Performance* perf = win->GetPerformance();
|
|
if (NS_WARN_IF(!perf)) {
|
|
return 0.0;
|
|
}
|
|
|
|
double ret = perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp);
|
|
MOZ_ASSERT(mOwner->PrincipalOrNull());
|
|
if (nsContentUtils::IsSystemPrincipal(mOwner->PrincipalOrNull()))
|
|
return ret;
|
|
|
|
return nsRFPService::ReduceTimePrecisionAsMSecs(ret,
|
|
perf->GetRandomTimelineSeed());
|
|
}
|
|
|
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
|
MOZ_ASSERT(workerPrivate);
|
|
|
|
double ret = workerPrivate->TimeStampToDOMHighRes(mEvent->mTimeStamp);
|
|
if (workerPrivate->UsesSystemPrincipal())
|
|
return ret;
|
|
|
|
return nsRFPService::ReduceTimePrecisionAsMSecs(ret,
|
|
workerPrivate->GetRandomTimelineSeed());
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetDefaultPrevented(bool* aReturn)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
// This method must be called by only event handlers implemented by C++.
|
|
// Then, the handlers must handle default action. So, this method don't need
|
|
// to check if preventDefault() has been called by content or chrome.
|
|
*aReturn = DefaultPrevented();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP_(void)
|
|
Event::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType)
|
|
{
|
|
if (aSerializeInterfaceType) {
|
|
IPC::WriteParam(aMsg, NS_LITERAL_STRING("event"));
|
|
}
|
|
|
|
nsString type;
|
|
GetType(type);
|
|
IPC::WriteParam(aMsg, type);
|
|
|
|
IPC::WriteParam(aMsg, Bubbles());
|
|
IPC::WriteParam(aMsg, Cancelable());
|
|
IPC::WriteParam(aMsg, IsTrusted());
|
|
IPC::WriteParam(aMsg, Composed());
|
|
|
|
// No timestamp serialization for now!
|
|
}
|
|
|
|
NS_IMETHODIMP_(bool)
|
|
Event::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
|
|
{
|
|
nsString type;
|
|
NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), false);
|
|
|
|
bool bubbles = false;
|
|
NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false);
|
|
|
|
bool cancelable = false;
|
|
NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), false);
|
|
|
|
bool trusted = false;
|
|
NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false);
|
|
|
|
bool composed = false;
|
|
NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &composed), false);
|
|
|
|
InitEvent(type, bubbles, cancelable);
|
|
SetTrusted(trusted);
|
|
SetComposed(composed);
|
|
|
|
return true;
|
|
}
|
|
|
|
NS_IMETHODIMP_(void)
|
|
Event::SetOwner(EventTarget* aOwner)
|
|
{
|
|
mOwner = nullptr;
|
|
|
|
if (!aOwner) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsINode> n = do_QueryInterface(aOwner);
|
|
if (n) {
|
|
mOwner = n->OwnerDoc()->GetScopeObject();
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(aOwner);
|
|
if (w) {
|
|
mOwner = do_QueryInterface(w);
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
|
|
if (eth) {
|
|
mOwner = eth->GetParentObject();
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
|
|
MOZ_ASSERT(root, "Unexpected EventTarget!");
|
|
#endif
|
|
}
|
|
|
|
void
|
|
Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType)
|
|
{
|
|
if (!aEvent->mSpecifiedEventTypeString.IsEmpty()) {
|
|
aType = aEvent->mSpecifiedEventTypeString;
|
|
return;
|
|
}
|
|
|
|
const char* name = GetEventName(aEvent->mMessage);
|
|
|
|
if (name) {
|
|
CopyASCIItoUTF16(name, aType);
|
|
return;
|
|
} else if (aEvent->mMessage == eUnidentifiedEvent &&
|
|
aEvent->mSpecifiedEventType) {
|
|
// Remove "on"
|
|
aType = Substring(nsDependentAtomString(aEvent->mSpecifiedEventType), 2);
|
|
aEvent->mSpecifiedEventTypeString = aType;
|
|
return;
|
|
}
|
|
|
|
aType.Truncate();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::GetCancelBubble(bool* aCancelBubble)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aCancelBubble);
|
|
*aCancelBubble = CancelBubble();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Event::SetCancelBubble(bool aCancelBubble)
|
|
{
|
|
if (aCancelBubble) {
|
|
mEvent->StopPropagation();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
already_AddRefed<Event>
|
|
NS_NewDOMEvent(EventTarget* aOwner,
|
|
nsPresContext* aPresContext,
|
|
WidgetEvent* aEvent)
|
|
{
|
|
RefPtr<Event> it = new Event(aOwner, aPresContext, aEvent);
|
|
return it.forget();
|
|
}
|