gecko-dev/dom/events/Event.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

841 lines
26 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2012-05-21 11:12:37 +00:00
/* 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/EventDispatcher.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 "nsIContentInlines.h"
#include "mozilla/dom/Document.h"
#include "nsIPresShell.h"
#include "nsIScrollableFrame.h"
#include "nsJSEnvironment.h"
#include "nsLayoutUtils.h"
#include "nsPIWindowRoot.h"
#include "nsRFPService.h"
namespace mozilla {
namespace dom {
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(Event)
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;
}
if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
mouseEvent->mClickTarget = nullptr;
}
}
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;
}
if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClickTarget");
cb.NoteXPCOMChild(mouseEvent->mClickTarget);
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv The only manual changes here are to BindingUtils.h, BindingUtils.cpp, Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp, dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp, Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp, Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The rest of this diff was generated by running the following commands: find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 14:13:33 +00:00
JSObject* Event::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
return WrapObjectInternal(aCx, aGivenProto);
}
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv The only manual changes here are to BindingUtils.h, BindingUtils.cpp, Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp, dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp, Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp, Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The rest of this diff was generated by running the following commands: find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g' find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 14:13:33 +00:00
JSObject* Event::WrapObjectInternal(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return Event_Binding::Wrap(aCx, this, aGivenProto);
}
void Event::GetType(nsAString& aType) const {
GetWidgetEventType(mEvent, aType);
}
EventTarget* Event::GetTarget() const { return mEvent->GetDOMEventTarget(); }
already_AddRefed<Document> Event::GetDocument() const {
nsCOMPtr<EventTarget> eventTarget = GetTarget();
if (!eventTarget) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowInner> win =
do_QueryInterface(eventTarget->GetOwnerGlobal());
if (!win) {
return nullptr;
}
nsCOMPtr<Document> doc;
doc = win->GetExtantDoc();
return doc.forget();
}
EventTarget* Event::GetCurrentTarget() const {
return mEvent->GetCurrentDOMEventTarget();
}
void Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath) {
EventDispatcher::GetComposedPathFor(mEvent, aPath);
}
//
// 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();
}
EventTarget* Event::GetOriginalTarget() const {
return mEvent->GetOriginalDOMEventTarget();
}
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());
}
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<Document> 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 Event_Binding::AT_TARGET;
}
if (mEvent->mFlags.mInCapturePhase) {
return Event_Binding::CAPTURING_PHASE;
}
if (mEvent->mFlags.mInBubblingPhase) {
return Event_Binding::BUBBLING_PHASE;
}
return Event_Binding::NONE;
}
void Event::StopPropagation() { mEvent->StopPropagation(); }
void Event::StopImmediatePropagation() { mEvent->StopImmediatePropagation(); }
void Event::StopCrossProcessForwarding() {
mEvent->StopCrossProcessForwarding();
}
void Event::PreventDefault() {
// This method is called only from C++ code which must handle default action
// of this event. So, pass true always.
PreventDefaultInternal(true);
}
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 (Document* doc = win->GetExtantDoc()) {
nsString type;
GetType(type);
const char16_t* params[] = {type.get()};
doc->WarnOnceAbout(Document::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) {
mEvent->mSpecifiedEventTypeString.Truncate();
if (mIsMainThreadEvent) {
mEvent->mSpecifiedEventType = nsContentUtils::GetEventMessageAndAtom(
aEventTypeArg, mEvent->mClass, &(mEvent->mMessage));
mEvent->SetDefaultComposed();
} else {
mEvent->mSpecifiedEventType =
NS_Atomize(NS_LITERAL_STRING("on") + aEventTypeArg);
mEvent->mMessage = eUnidentifiedEvent;
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 = content;
}
if (relatedTarget) {
relatedTarget = relatedTarget->GetTargetForDOMEvent();
}
}
return relatedTarget.forget();
}
void Event::InitEvent(const nsAString& aEventTypeArg,
mozilla::CanBubble aCanBubbleArg,
mozilla::Cancelable aCancelableArg,
mozilla::Composed aComposedArg) {
// 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 == CanBubble::eYes;
mEvent->mFlags.mCancelable = aCancelableArg == Cancelable::eYes;
if (aComposedArg != Composed::eDefault) {
mEvent->mFlags.mComposed = aComposedArg == Composed::eYes;
}
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;
}
void Event::DuplicatePrivateData() {
NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
if (mEventIsInternal) {
return;
}
mEvent = mEvent->Duplicate();
mPresContext = nullptr;
mEventIsInternal = true;
mPrivateDataDuplicated = true;
}
void Event::SetTarget(EventTarget* aTarget) { mEvent->mTarget = aTarget; }
bool Event::IsDispatchStopped() { return mEvent->PropagationStopped(); }
WidgetEvent* Event::WidgetEventPtr() { return mEvent; }
// 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;
}
bool Event::ReturnValue(CallerType aCallerType) const {
return !DefaultPrevented(aCallerType);
}
void Event::SetReturnValue(bool aReturnValue, CallerType aCallerType) {
if (!aReturnValue) {
PreventDefaultInternal(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());
}
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!
}
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;
}
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) {
Bug 1402247 - Use encoding_rs for XPCOM string encoding conversions. r=Nika,erahm,froydnj. Correctness improvements: * UTF errors are handled safely per spec instead of dangerously truncating strings. * There are fewer converter implementations. Performance improvements: * The old code did exact buffer length math, which meant doing UTF math twice on each input string (once for length calculation and another time for conversion). Exact length math is more complicated when handling errors properly, which the old code didn't do. The new code does UTF math on the string content only once (when converting) but risks allocating more than once. There are heuristics in place to lower the probability of reallocation in cases where the double math avoidance isn't enough of a saving to absorb an allocation and memcpy. * Previously, in UTF-16 <-> UTF-8 conversions, an ASCII prefix was optimized but a single non-ASCII code point pessimized the rest of the string. The new code tries to get back on the fast ASCII path. * UTF-16 to Latin1 conversion guarantees less about handling of out-of-range input to eliminate an operation from the inner loop on x86/x86_64. * When assigning to a pre-existing string, the new code tries to reuse the old buffer instead of first releasing the old buffer and then allocating a new one. * When reallocating from the new code, the memcpy covers only the data that is part of the logical length of the old string instead of memcpying the whole capacity. (For old callers old excess memcpy behavior is preserved due to bogus callers. See bug 1472113.) * UTF-8 strings in XPConnect that are in the Latin1 range are passed to SpiderMonkey as Latin1. New features: * Conversion between UTF-8 and Latin1 is added in order to enable faster future interop between Rust code (or otherwise UTF-8-using code) and text node and SpiderMonkey code that uses Latin1. MozReview-Commit-ID: JaJuExfILM9
2018-07-06 07:44:43 +00:00
CopyASCIItoUTF16(mozilla::MakeStringSpan(name), aType);
return;
} else if (aEvent->mMessage == eUnidentifiedEvent &&
aEvent->mSpecifiedEventType) {
// Remove "on"
aType = Substring(nsDependentAtomString(aEvent->mSpecifiedEventType), 2);
aEvent->mSpecifiedEventTypeString = aType;
return;
}
aType.Truncate();
}
} // namespace dom
} // namespace mozilla
using namespace mozilla;
using namespace mozilla::dom;
already_AddRefed<Event> NS_NewDOMEvent(EventTarget* aOwner,
nsPresContext* aPresContext,
WidgetEvent* aEvent) {
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 05:24:48 +00:00
RefPtr<Event> it = new Event(aOwner, aPresContext, aEvent);
return it.forget();
}