1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/Event.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1100 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "AccessCheck.h" 1.10 +#include "base/basictypes.h" 1.11 +#include "ipc/IPCMessageUtils.h" 1.12 +#include "mozilla/dom/Event.h" 1.13 +#include "mozilla/ContentEvents.h" 1.14 +#include "mozilla/DOMEventTargetHelper.h" 1.15 +#include "mozilla/EventStateManager.h" 1.16 +#include "mozilla/InternalMutationEvent.h" 1.17 +#include "mozilla/MiscEvents.h" 1.18 +#include "mozilla/MouseEvents.h" 1.19 +#include "mozilla/Preferences.h" 1.20 +#include "mozilla/TextEvents.h" 1.21 +#include "mozilla/TouchEvents.h" 1.22 +#include "nsContentUtils.h" 1.23 +#include "nsCOMPtr.h" 1.24 +#include "nsDeviceContext.h" 1.25 +#include "nsError.h" 1.26 +#include "nsGlobalWindow.h" 1.27 +#include "nsIFrame.h" 1.28 +#include "nsIContent.h" 1.29 +#include "nsIDocument.h" 1.30 +#include "nsIPresShell.h" 1.31 +#include "nsIScrollableFrame.h" 1.32 +#include "nsJSEnvironment.h" 1.33 +#include "nsLayoutUtils.h" 1.34 +#include "nsPIWindowRoot.h" 1.35 + 1.36 +namespace mozilla { 1.37 +namespace dom { 1.38 + 1.39 +namespace workers { 1.40 +extern bool IsCurrentThreadRunningChromeWorker(); 1.41 +} // namespace workers 1.42 + 1.43 +static char *sPopupAllowedEvents; 1.44 + 1.45 +Event::Event(EventTarget* aOwner, 1.46 + nsPresContext* aPresContext, 1.47 + WidgetEvent* aEvent) 1.48 +{ 1.49 + ConstructorInit(aOwner, aPresContext, aEvent); 1.50 +} 1.51 + 1.52 +Event::Event(nsPIDOMWindow* aParent) 1.53 +{ 1.54 + ConstructorInit(static_cast<nsGlobalWindow *>(aParent), nullptr, nullptr); 1.55 +} 1.56 + 1.57 +void 1.58 +Event::ConstructorInit(EventTarget* aOwner, 1.59 + nsPresContext* aPresContext, 1.60 + WidgetEvent* aEvent) 1.61 +{ 1.62 + SetIsDOMBinding(); 1.63 + SetOwner(aOwner); 1.64 + mIsMainThreadEvent = mOwner || NS_IsMainThread(); 1.65 + if (mIsMainThreadEvent) { 1.66 + nsJSContext::LikelyShortLivingObjectCreated(); 1.67 + } 1.68 + 1.69 + mPrivateDataDuplicated = false; 1.70 + 1.71 + if (aEvent) { 1.72 + mEvent = aEvent; 1.73 + mEventIsInternal = false; 1.74 + } 1.75 + else { 1.76 + mEventIsInternal = true; 1.77 + /* 1.78 + A derived class might want to allocate its own type of aEvent 1.79 + (derived from WidgetEvent). To do this, it should take care to pass 1.80 + a non-nullptr aEvent to this ctor, e.g.: 1.81 + 1.82 + FooEvent::FooEvent(..., WidgetEvent* aEvent) 1.83 + : Event(..., aEvent ? aEvent : new WidgetEvent()) 1.84 + 1.85 + Then, to override the mEventIsInternal assignments done by the 1.86 + base ctor, it should do this in its own ctor: 1.87 + 1.88 + FooEvent::FooEvent(..., WidgetEvent* aEvent) 1.89 + ... 1.90 + { 1.91 + ... 1.92 + if (aEvent) { 1.93 + mEventIsInternal = false; 1.94 + } 1.95 + else { 1.96 + mEventIsInternal = true; 1.97 + } 1.98 + ... 1.99 + } 1.100 + */ 1.101 + mEvent = new WidgetEvent(false, 0); 1.102 + mEvent->time = PR_Now(); 1.103 + } 1.104 + 1.105 + InitPresContextData(aPresContext); 1.106 +} 1.107 + 1.108 +void 1.109 +Event::InitPresContextData(nsPresContext* aPresContext) 1.110 +{ 1.111 + mPresContext = aPresContext; 1.112 + // Get the explicit original target (if it's anonymous make it null) 1.113 + { 1.114 + nsCOMPtr<nsIContent> content = GetTargetFromFrame(); 1.115 + mExplicitOriginalTarget = content; 1.116 + if (content && content->IsInAnonymousSubtree()) { 1.117 + mExplicitOriginalTarget = nullptr; 1.118 + } 1.119 + } 1.120 +} 1.121 + 1.122 +Event::~Event() 1.123 +{ 1.124 + NS_ASSERT_OWNINGTHREAD(Event); 1.125 + 1.126 + if (mEventIsInternal && mEvent) { 1.127 + delete mEvent; 1.128 + } 1.129 +} 1.130 + 1.131 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event) 1.132 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.133 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.134 + NS_INTERFACE_MAP_ENTRY(nsIDOMEvent) 1.135 +NS_INTERFACE_MAP_END 1.136 + 1.137 +NS_IMPL_CYCLE_COLLECTING_ADDREF(Event) 1.138 +NS_IMPL_CYCLE_COLLECTING_RELEASE(Event) 1.139 + 1.140 +NS_IMPL_CYCLE_COLLECTION_CLASS(Event) 1.141 + 1.142 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event) 1.143 + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 1.144 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.145 + 1.146 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event) 1.147 + if (tmp->mEventIsInternal) { 1.148 + tmp->mEvent->target = nullptr; 1.149 + tmp->mEvent->currentTarget = nullptr; 1.150 + tmp->mEvent->originalTarget = nullptr; 1.151 + switch (tmp->mEvent->eventStructType) { 1.152 + case NS_MOUSE_EVENT: 1.153 + case NS_MOUSE_SCROLL_EVENT: 1.154 + case NS_WHEEL_EVENT: 1.155 + case NS_SIMPLE_GESTURE_EVENT: 1.156 + case NS_POINTER_EVENT: 1.157 + tmp->mEvent->AsMouseEventBase()->relatedTarget = nullptr; 1.158 + break; 1.159 + case NS_DRAG_EVENT: { 1.160 + WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent(); 1.161 + dragEvent->dataTransfer = nullptr; 1.162 + dragEvent->relatedTarget = nullptr; 1.163 + break; 1.164 + } 1.165 + case NS_CLIPBOARD_EVENT: 1.166 + tmp->mEvent->AsClipboardEvent()->clipboardData = nullptr; 1.167 + break; 1.168 + case NS_MUTATION_EVENT: 1.169 + tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr; 1.170 + break; 1.171 + case NS_FOCUS_EVENT: 1.172 + tmp->mEvent->AsFocusEvent()->relatedTarget = nullptr; 1.173 + break; 1.174 + default: 1.175 + break; 1.176 + } 1.177 + } 1.178 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext); 1.179 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget); 1.180 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner); 1.181 + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 1.182 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.183 + 1.184 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event) 1.185 + if (tmp->mEventIsInternal) { 1.186 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->target) 1.187 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->currentTarget) 1.188 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->originalTarget) 1.189 + switch (tmp->mEvent->eventStructType) { 1.190 + case NS_MOUSE_EVENT: 1.191 + case NS_MOUSE_SCROLL_EVENT: 1.192 + case NS_WHEEL_EVENT: 1.193 + case NS_SIMPLE_GESTURE_EVENT: 1.194 + case NS_POINTER_EVENT: 1.195 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget"); 1.196 + cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget); 1.197 + break; 1.198 + case NS_DRAG_EVENT: { 1.199 + WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent(); 1.200 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->dataTransfer"); 1.201 + cb.NoteXPCOMChild(dragEvent->dataTransfer); 1.202 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget"); 1.203 + cb.NoteXPCOMChild(dragEvent->relatedTarget); 1.204 + break; 1.205 + } 1.206 + case NS_CLIPBOARD_EVENT: 1.207 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->clipboardData"); 1.208 + cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->clipboardData); 1.209 + break; 1.210 + case NS_MUTATION_EVENT: 1.211 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode"); 1.212 + cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode); 1.213 + break; 1.214 + case NS_FOCUS_EVENT: 1.215 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget"); 1.216 + cb.NoteXPCOMChild(tmp->mEvent->AsFocusEvent()->relatedTarget); 1.217 + break; 1.218 + default: 1.219 + break; 1.220 + } 1.221 + } 1.222 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext) 1.223 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget) 1.224 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) 1.225 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.226 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.227 + 1.228 +bool 1.229 +Event::IsChrome(JSContext* aCx) const 1.230 +{ 1.231 + return mIsMainThreadEvent ? 1.232 + xpc::AccessCheck::isChrome(js::GetContextCompartment(aCx)) : 1.233 + mozilla::dom::workers::IsCurrentThreadRunningChromeWorker(); 1.234 +} 1.235 + 1.236 +// nsIDOMEventInterface 1.237 +NS_METHOD 1.238 +Event::GetType(nsAString& aType) 1.239 +{ 1.240 + if (!mIsMainThreadEvent || !mEvent->typeString.IsEmpty()) { 1.241 + aType = mEvent->typeString; 1.242 + return NS_OK; 1.243 + } 1.244 + const char* name = GetEventName(mEvent->message); 1.245 + 1.246 + if (name) { 1.247 + CopyASCIItoUTF16(name, aType); 1.248 + return NS_OK; 1.249 + } else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) { 1.250 + aType = Substring(nsDependentAtomString(mEvent->userType), 2); // Remove "on" 1.251 + mEvent->typeString = aType; 1.252 + return NS_OK; 1.253 + } 1.254 + 1.255 + aType.Truncate(); 1.256 + return NS_OK; 1.257 +} 1.258 + 1.259 +static EventTarget* 1.260 +GetDOMEventTarget(nsIDOMEventTarget* aTarget) 1.261 +{ 1.262 + return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr; 1.263 +} 1.264 + 1.265 +EventTarget* 1.266 +Event::GetTarget() const 1.267 +{ 1.268 + return GetDOMEventTarget(mEvent->target); 1.269 +} 1.270 + 1.271 +NS_METHOD 1.272 +Event::GetTarget(nsIDOMEventTarget** aTarget) 1.273 +{ 1.274 + NS_IF_ADDREF(*aTarget = GetTarget()); 1.275 + return NS_OK; 1.276 +} 1.277 + 1.278 +EventTarget* 1.279 +Event::GetCurrentTarget() const 1.280 +{ 1.281 + return GetDOMEventTarget(mEvent->currentTarget); 1.282 +} 1.283 + 1.284 +NS_IMETHODIMP 1.285 +Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) 1.286 +{ 1.287 + NS_IF_ADDREF(*aCurrentTarget = GetCurrentTarget()); 1.288 + return NS_OK; 1.289 +} 1.290 + 1.291 +// 1.292 +// Get the actual event target node (may have been retargeted for mouse events) 1.293 +// 1.294 +already_AddRefed<nsIContent> 1.295 +Event::GetTargetFromFrame() 1.296 +{ 1.297 + if (!mPresContext) { return nullptr; } 1.298 + 1.299 + // Get the target frame (have to get the ESM first) 1.300 + nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget(); 1.301 + if (!targetFrame) { return nullptr; } 1.302 + 1.303 + // get the real content 1.304 + nsCOMPtr<nsIContent> realEventContent; 1.305 + targetFrame->GetContentForEvent(mEvent, getter_AddRefs(realEventContent)); 1.306 + return realEventContent.forget(); 1.307 +} 1.308 + 1.309 +EventTarget* 1.310 +Event::GetExplicitOriginalTarget() const 1.311 +{ 1.312 + if (mExplicitOriginalTarget) { 1.313 + return mExplicitOriginalTarget; 1.314 + } 1.315 + return GetTarget(); 1.316 +} 1.317 + 1.318 +NS_IMETHODIMP 1.319 +Event::GetExplicitOriginalTarget(nsIDOMEventTarget** aRealEventTarget) 1.320 +{ 1.321 + NS_IF_ADDREF(*aRealEventTarget = GetExplicitOriginalTarget()); 1.322 + return NS_OK; 1.323 +} 1.324 + 1.325 +EventTarget* 1.326 +Event::GetOriginalTarget() const 1.327 +{ 1.328 + if (mEvent->originalTarget) { 1.329 + return GetDOMEventTarget(mEvent->originalTarget); 1.330 + } 1.331 + 1.332 + return GetTarget(); 1.333 +} 1.334 + 1.335 +NS_IMETHODIMP 1.336 +Event::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget) 1.337 +{ 1.338 + NS_IF_ADDREF(*aOriginalTarget = GetOriginalTarget()); 1.339 + return NS_OK; 1.340 +} 1.341 + 1.342 +NS_IMETHODIMP_(void) 1.343 +Event::SetTrusted(bool aTrusted) 1.344 +{ 1.345 + mEvent->mFlags.mIsTrusted = aTrusted; 1.346 +} 1.347 + 1.348 +bool 1.349 +Event::Init(mozilla::dom::EventTarget* aGlobal) 1.350 +{ 1.351 + if (!mIsMainThreadEvent) { 1.352 + return nsContentUtils::ThreadsafeIsCallerChrome(); 1.353 + } 1.354 + bool trusted = false; 1.355 + nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal); 1.356 + if (w) { 1.357 + nsCOMPtr<nsIDocument> d = w->GetExtantDoc(); 1.358 + if (d) { 1.359 + trusted = nsContentUtils::IsChromeDoc(d); 1.360 + nsIPresShell* s = d->GetShell(); 1.361 + if (s) { 1.362 + InitPresContextData(s->GetPresContext()); 1.363 + } 1.364 + } 1.365 + } 1.366 + return trusted; 1.367 +} 1.368 + 1.369 +// static 1.370 +already_AddRefed<Event> 1.371 +Event::Constructor(const GlobalObject& aGlobal, 1.372 + const nsAString& aType, 1.373 + const EventInit& aParam, 1.374 + ErrorResult& aRv) 1.375 +{ 1.376 + nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports()); 1.377 + nsRefPtr<Event> e = new Event(t, nullptr, nullptr); 1.378 + bool trusted = e->Init(t); 1.379 + aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); 1.380 + e->SetTrusted(trusted); 1.381 + return e.forget(); 1.382 +} 1.383 + 1.384 +uint16_t 1.385 +Event::EventPhase() const 1.386 +{ 1.387 + // Note, remember to check that this works also 1.388 + // if or when Bug 235441 is fixed. 1.389 + if ((mEvent->currentTarget && 1.390 + mEvent->currentTarget == mEvent->target) || 1.391 + mEvent->mFlags.InTargetPhase()) { 1.392 + return nsIDOMEvent::AT_TARGET; 1.393 + } 1.394 + if (mEvent->mFlags.mInCapturePhase) { 1.395 + return nsIDOMEvent::CAPTURING_PHASE; 1.396 + } 1.397 + if (mEvent->mFlags.mInBubblingPhase) { 1.398 + return nsIDOMEvent::BUBBLING_PHASE; 1.399 + } 1.400 + return nsIDOMEvent::NONE; 1.401 +} 1.402 + 1.403 +NS_IMETHODIMP 1.404 +Event::GetEventPhase(uint16_t* aEventPhase) 1.405 +{ 1.406 + *aEventPhase = EventPhase(); 1.407 + return NS_OK; 1.408 +} 1.409 + 1.410 +NS_IMETHODIMP 1.411 +Event::GetBubbles(bool* aBubbles) 1.412 +{ 1.413 + *aBubbles = Bubbles(); 1.414 + return NS_OK; 1.415 +} 1.416 + 1.417 +NS_IMETHODIMP 1.418 +Event::GetCancelable(bool* aCancelable) 1.419 +{ 1.420 + *aCancelable = Cancelable(); 1.421 + return NS_OK; 1.422 +} 1.423 + 1.424 +NS_IMETHODIMP 1.425 +Event::GetTimeStamp(uint64_t* aTimeStamp) 1.426 +{ 1.427 + *aTimeStamp = TimeStamp(); 1.428 + return NS_OK; 1.429 +} 1.430 + 1.431 +NS_IMETHODIMP 1.432 +Event::StopPropagation() 1.433 +{ 1.434 + mEvent->mFlags.mPropagationStopped = true; 1.435 + return NS_OK; 1.436 +} 1.437 + 1.438 +NS_IMETHODIMP 1.439 +Event::StopImmediatePropagation() 1.440 +{ 1.441 + mEvent->mFlags.mPropagationStopped = true; 1.442 + mEvent->mFlags.mImmediatePropagationStopped = true; 1.443 + return NS_OK; 1.444 +} 1.445 + 1.446 +NS_IMETHODIMP 1.447 +Event::GetIsTrusted(bool* aIsTrusted) 1.448 +{ 1.449 + *aIsTrusted = IsTrusted(); 1.450 + return NS_OK; 1.451 +} 1.452 + 1.453 +NS_IMETHODIMP 1.454 +Event::PreventDefault() 1.455 +{ 1.456 + // This method is called only from C++ code which must handle default action 1.457 + // of this event. So, pass true always. 1.458 + PreventDefaultInternal(true); 1.459 + return NS_OK; 1.460 +} 1.461 + 1.462 +void 1.463 +Event::PreventDefault(JSContext* aCx) 1.464 +{ 1.465 + MOZ_ASSERT(aCx, "JS context must be specified"); 1.466 + 1.467 + // Note that at handling default action, another event may be dispatched. 1.468 + // Then, JS in content mey be call preventDefault() 1.469 + // even in the event is in system event group. Therefore, don't refer 1.470 + // mInSystemGroup here. 1.471 + PreventDefaultInternal(IsChrome(aCx)); 1.472 +} 1.473 + 1.474 +void 1.475 +Event::PreventDefaultInternal(bool aCalledByDefaultHandler) 1.476 +{ 1.477 + if (!mEvent->mFlags.mCancelable) { 1.478 + return; 1.479 + } 1.480 + 1.481 + mEvent->mFlags.mDefaultPrevented = true; 1.482 + 1.483 + // Note that even if preventDefault() has already been called by chrome, 1.484 + // a call of preventDefault() by content needs to overwrite 1.485 + // mDefaultPreventedByContent to true because in such case, defaultPrevented 1.486 + // must be true when web apps check it after they call preventDefault(). 1.487 + if (!aCalledByDefaultHandler) { 1.488 + mEvent->mFlags.mDefaultPreventedByContent = true; 1.489 + } 1.490 + 1.491 + if (!IsTrusted()) { 1.492 + return; 1.493 + } 1.494 + 1.495 + WidgetDragEvent* dragEvent = mEvent->AsDragEvent(); 1.496 + if (!dragEvent) { 1.497 + return; 1.498 + } 1.499 + 1.500 + nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->currentTarget); 1.501 + if (!node) { 1.502 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mEvent->currentTarget); 1.503 + if (!win) { 1.504 + return; 1.505 + } 1.506 + node = win->GetExtantDoc(); 1.507 + } 1.508 + if (!nsContentUtils::IsChromeDoc(node->OwnerDoc())) { 1.509 + dragEvent->mDefaultPreventedOnContent = true; 1.510 + } 1.511 +} 1.512 + 1.513 +void 1.514 +Event::SetEventType(const nsAString& aEventTypeArg) 1.515 +{ 1.516 + if (mIsMainThreadEvent) { 1.517 + mEvent->userType = 1.518 + nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType, 1.519 + &(mEvent->message)); 1.520 + } else { 1.521 + mEvent->userType = nullptr; 1.522 + mEvent->message = NS_USER_DEFINED_EVENT; 1.523 + mEvent->typeString = aEventTypeArg; 1.524 + } 1.525 +} 1.526 + 1.527 +NS_IMETHODIMP 1.528 +Event::InitEvent(const nsAString& aEventTypeArg, 1.529 + bool aCanBubbleArg, 1.530 + bool aCancelableArg) 1.531 +{ 1.532 + // Make sure this event isn't already being dispatched. 1.533 + NS_ENSURE_TRUE(!mEvent->mFlags.mIsBeingDispatched, NS_OK); 1.534 + 1.535 + if (IsTrusted()) { 1.536 + // Ensure the caller is permitted to dispatch trusted DOM events. 1.537 + if (!nsContentUtils::ThreadsafeIsCallerChrome()) { 1.538 + SetTrusted(false); 1.539 + } 1.540 + } 1.541 + 1.542 + SetEventType(aEventTypeArg); 1.543 + 1.544 + mEvent->mFlags.mBubbles = aCanBubbleArg; 1.545 + mEvent->mFlags.mCancelable = aCancelableArg; 1.546 + 1.547 + mEvent->mFlags.mDefaultPrevented = false; 1.548 + 1.549 + // Clearing the old targets, so that the event is targeted correctly when 1.550 + // re-dispatching it. 1.551 + mEvent->target = nullptr; 1.552 + mEvent->originalTarget = nullptr; 1.553 + return NS_OK; 1.554 +} 1.555 + 1.556 +NS_IMETHODIMP 1.557 +Event::DuplicatePrivateData() 1.558 +{ 1.559 + NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!"); 1.560 + if (mEventIsInternal) { 1.561 + return NS_OK; 1.562 + } 1.563 + 1.564 + mEvent = mEvent->Duplicate(); 1.565 + mPresContext = nullptr; 1.566 + mEventIsInternal = true; 1.567 + mPrivateDataDuplicated = true; 1.568 + 1.569 + return NS_OK; 1.570 +} 1.571 + 1.572 +NS_IMETHODIMP 1.573 +Event::SetTarget(nsIDOMEventTarget* aTarget) 1.574 +{ 1.575 +#ifdef DEBUG 1.576 + { 1.577 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget); 1.578 + 1.579 + NS_ASSERTION(!win || !win->IsInnerWindow(), 1.580 + "Uh, inner window set as event target!"); 1.581 + } 1.582 +#endif 1.583 + 1.584 + mEvent->target = do_QueryInterface(aTarget); 1.585 + return NS_OK; 1.586 +} 1.587 + 1.588 +NS_IMETHODIMP_(bool) 1.589 +Event::IsDispatchStopped() 1.590 +{ 1.591 + return mEvent->mFlags.mPropagationStopped; 1.592 +} 1.593 + 1.594 +NS_IMETHODIMP_(WidgetEvent*) 1.595 +Event::GetInternalNSEvent() 1.596 +{ 1.597 + return mEvent; 1.598 +} 1.599 + 1.600 +NS_IMETHODIMP_(Event*) 1.601 +Event::InternalDOMEvent() 1.602 +{ 1.603 + return this; 1.604 +} 1.605 + 1.606 +// return true if eventName is contained within events, delimited by 1.607 +// spaces 1.608 +static bool 1.609 +PopupAllowedForEvent(const char *eventName) 1.610 +{ 1.611 + if (!sPopupAllowedEvents) { 1.612 + Event::PopupAllowedEventsChanged(); 1.613 + 1.614 + if (!sPopupAllowedEvents) { 1.615 + return false; 1.616 + } 1.617 + } 1.618 + 1.619 + nsDependentCString events(sPopupAllowedEvents); 1.620 + 1.621 + nsAFlatCString::const_iterator start, end; 1.622 + nsAFlatCString::const_iterator startiter(events.BeginReading(start)); 1.623 + events.EndReading(end); 1.624 + 1.625 + while (startiter != end) { 1.626 + nsAFlatCString::const_iterator enditer(end); 1.627 + 1.628 + if (!FindInReadable(nsDependentCString(eventName), startiter, enditer)) 1.629 + return false; 1.630 + 1.631 + // the match is surrounded by spaces, or at a string boundary 1.632 + if ((startiter == start || *--startiter == ' ') && 1.633 + (enditer == end || *enditer == ' ')) { 1.634 + return true; 1.635 + } 1.636 + 1.637 + // Move on and see if there are other matches. (The delimitation 1.638 + // requirement makes it pointless to begin the next search before 1.639 + // the end of the invalid match just found.) 1.640 + startiter = enditer; 1.641 + } 1.642 + 1.643 + return false; 1.644 +} 1.645 + 1.646 +// static 1.647 +PopupControlState 1.648 +Event::GetEventPopupControlState(WidgetEvent* aEvent) 1.649 +{ 1.650 + // generally if an event handler is running, new windows are disallowed. 1.651 + // check for exceptions: 1.652 + PopupControlState abuse = openAbused; 1.653 + 1.654 + switch(aEvent->eventStructType) { 1.655 + case NS_EVENT : 1.656 + // For these following events only allow popups if they're 1.657 + // triggered while handling user input. See 1.658 + // nsPresShell::HandleEventInternal() for details. 1.659 + if (EventStateManager::IsHandlingUserInput()) { 1.660 + switch(aEvent->message) { 1.661 + case NS_FORM_SELECTED : 1.662 + if (PopupAllowedForEvent("select")) { 1.663 + abuse = openControlled; 1.664 + } 1.665 + break; 1.666 + case NS_FORM_CHANGE : 1.667 + if (PopupAllowedForEvent("change")) { 1.668 + abuse = openControlled; 1.669 + } 1.670 + break; 1.671 + } 1.672 + } 1.673 + break; 1.674 + case NS_EDITOR_INPUT_EVENT : 1.675 + // For this following event only allow popups if it's triggered 1.676 + // while handling user input. See 1.677 + // nsPresShell::HandleEventInternal() for details. 1.678 + if (EventStateManager::IsHandlingUserInput()) { 1.679 + switch(aEvent->message) { 1.680 + case NS_EDITOR_INPUT: 1.681 + if (PopupAllowedForEvent("input")) { 1.682 + abuse = openControlled; 1.683 + } 1.684 + break; 1.685 + } 1.686 + } 1.687 + break; 1.688 + case NS_INPUT_EVENT : 1.689 + // For this following event only allow popups if it's triggered 1.690 + // while handling user input. See 1.691 + // nsPresShell::HandleEventInternal() for details. 1.692 + if (EventStateManager::IsHandlingUserInput()) { 1.693 + switch(aEvent->message) { 1.694 + case NS_FORM_CHANGE : 1.695 + if (PopupAllowedForEvent("change")) { 1.696 + abuse = openControlled; 1.697 + } 1.698 + break; 1.699 + case NS_XUL_COMMAND: 1.700 + abuse = openControlled; 1.701 + break; 1.702 + } 1.703 + } 1.704 + break; 1.705 + case NS_KEY_EVENT : 1.706 + if (aEvent->mFlags.mIsTrusted) { 1.707 + uint32_t key = aEvent->AsKeyboardEvent()->keyCode; 1.708 + switch(aEvent->message) { 1.709 + case NS_KEY_PRESS : 1.710 + // return key on focused button. see note at NS_MOUSE_CLICK. 1.711 + if (key == nsIDOMKeyEvent::DOM_VK_RETURN) { 1.712 + abuse = openAllowed; 1.713 + } else if (PopupAllowedForEvent("keypress")) { 1.714 + abuse = openControlled; 1.715 + } 1.716 + break; 1.717 + case NS_KEY_UP : 1.718 + // space key on focused button. see note at NS_MOUSE_CLICK. 1.719 + if (key == nsIDOMKeyEvent::DOM_VK_SPACE) { 1.720 + abuse = openAllowed; 1.721 + } else if (PopupAllowedForEvent("keyup")) { 1.722 + abuse = openControlled; 1.723 + } 1.724 + break; 1.725 + case NS_KEY_DOWN : 1.726 + if (PopupAllowedForEvent("keydown")) { 1.727 + abuse = openControlled; 1.728 + } 1.729 + break; 1.730 + } 1.731 + } 1.732 + break; 1.733 + case NS_TOUCH_EVENT : 1.734 + if (aEvent->mFlags.mIsTrusted) { 1.735 + switch (aEvent->message) { 1.736 + case NS_TOUCH_START : 1.737 + if (PopupAllowedForEvent("touchstart")) { 1.738 + abuse = openControlled; 1.739 + } 1.740 + break; 1.741 + case NS_TOUCH_END : 1.742 + if (PopupAllowedForEvent("touchend")) { 1.743 + abuse = openControlled; 1.744 + } 1.745 + break; 1.746 + } 1.747 + } 1.748 + break; 1.749 + case NS_MOUSE_EVENT : 1.750 + if (aEvent->mFlags.mIsTrusted && 1.751 + aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { 1.752 + switch(aEvent->message) { 1.753 + case NS_MOUSE_BUTTON_UP : 1.754 + if (PopupAllowedForEvent("mouseup")) { 1.755 + abuse = openControlled; 1.756 + } 1.757 + break; 1.758 + case NS_MOUSE_BUTTON_DOWN : 1.759 + if (PopupAllowedForEvent("mousedown")) { 1.760 + abuse = openControlled; 1.761 + } 1.762 + break; 1.763 + case NS_MOUSE_CLICK : 1.764 + /* Click events get special treatment because of their 1.765 + historical status as a more legitimate event handler. If 1.766 + click popups are enabled in the prefs, clear the popup 1.767 + status completely. */ 1.768 + if (PopupAllowedForEvent("click")) { 1.769 + abuse = openAllowed; 1.770 + } 1.771 + break; 1.772 + case NS_MOUSE_DOUBLECLICK : 1.773 + if (PopupAllowedForEvent("dblclick")) { 1.774 + abuse = openControlled; 1.775 + } 1.776 + break; 1.777 + } 1.778 + } 1.779 + break; 1.780 + case NS_FORM_EVENT : 1.781 + // For these following events only allow popups if they're 1.782 + // triggered while handling user input. See 1.783 + // nsPresShell::HandleEventInternal() for details. 1.784 + if (EventStateManager::IsHandlingUserInput()) { 1.785 + switch(aEvent->message) { 1.786 + case NS_FORM_SUBMIT : 1.787 + if (PopupAllowedForEvent("submit")) { 1.788 + abuse = openControlled; 1.789 + } 1.790 + break; 1.791 + case NS_FORM_RESET : 1.792 + if (PopupAllowedForEvent("reset")) { 1.793 + abuse = openControlled; 1.794 + } 1.795 + break; 1.796 + } 1.797 + } 1.798 + break; 1.799 + default: 1.800 + break; 1.801 + } 1.802 + 1.803 + return abuse; 1.804 +} 1.805 + 1.806 +// static 1.807 +void 1.808 +Event::PopupAllowedEventsChanged() 1.809 +{ 1.810 + if (sPopupAllowedEvents) { 1.811 + nsMemory::Free(sPopupAllowedEvents); 1.812 + } 1.813 + 1.814 + nsAdoptingCString str = Preferences::GetCString("dom.popup_allowed_events"); 1.815 + 1.816 + // We'll want to do this even if str is empty to avoid looking up 1.817 + // this pref all the time if it's not set. 1.818 + sPopupAllowedEvents = ToNewCString(str); 1.819 +} 1.820 + 1.821 +// static 1.822 +void 1.823 +Event::Shutdown() 1.824 +{ 1.825 + if (sPopupAllowedEvents) { 1.826 + nsMemory::Free(sPopupAllowedEvents); 1.827 + } 1.828 +} 1.829 + 1.830 +nsIntPoint 1.831 +Event::GetScreenCoords(nsPresContext* aPresContext, 1.832 + WidgetEvent* aEvent, 1.833 + LayoutDeviceIntPoint aPoint) 1.834 +{ 1.835 + if (!nsContentUtils::IsCallerChrome()) { 1.836 + // For non-chrome callers, return client coordinates instead. 1.837 + // For some events, the result will be zero; specifically, for dragend 1.838 + // events (there is no widget associated with dragend events, which 1.839 + // causes GetClientX() to return zero). Since dragend is for the drag 1.840 + // originator and not for the receiver, it is probably not widely used 1.841 + // (receivers get a drop event). Therefore, returning 0 should not break 1.842 + // many web pages. Also, a few years ago Firefox returned 0. 1.843 + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=466379 1.844 + CSSIntPoint clientCoords = GetClientCoords(aPresContext, aEvent, aPoint, CSSIntPoint(0, 0)); 1.845 + return nsIntPoint(clientCoords.x, clientCoords.y); 1.846 + } 1.847 + 1.848 + if (EventStateManager::sIsPointerLocked) { 1.849 + return EventStateManager::sLastScreenPoint; 1.850 + } 1.851 + 1.852 + if (!aEvent || 1.853 + (aEvent->eventStructType != NS_MOUSE_EVENT && 1.854 + aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT && 1.855 + aEvent->eventStructType != NS_WHEEL_EVENT && 1.856 + aEvent->eventStructType != NS_POINTER_EVENT && 1.857 + aEvent->eventStructType != NS_TOUCH_EVENT && 1.858 + aEvent->eventStructType != NS_DRAG_EVENT && 1.859 + aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) { 1.860 + return nsIntPoint(0, 0); 1.861 + } 1.862 + 1.863 + WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent(); 1.864 + if (!guiEvent->widget) { 1.865 + return LayoutDeviceIntPoint::ToUntyped(aPoint); 1.866 + } 1.867 + 1.868 + LayoutDeviceIntPoint offset = aPoint + 1.869 + LayoutDeviceIntPoint::FromUntyped(guiEvent->widget->WidgetToScreenOffset()); 1.870 + nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel(); 1.871 + return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor), 1.872 + nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor)); 1.873 +} 1.874 + 1.875 +// static 1.876 +CSSIntPoint 1.877 +Event::GetPageCoords(nsPresContext* aPresContext, 1.878 + WidgetEvent* aEvent, 1.879 + LayoutDeviceIntPoint aPoint, 1.880 + CSSIntPoint aDefaultPoint) 1.881 +{ 1.882 + CSSIntPoint pagePoint = 1.883 + Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint); 1.884 + 1.885 + // If there is some scrolling, add scroll info to client point. 1.886 + if (aPresContext && aPresContext->GetPresShell()) { 1.887 + nsIPresShell* shell = aPresContext->GetPresShell(); 1.888 + nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable(); 1.889 + if (scrollframe) { 1.890 + pagePoint += CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition()); 1.891 + } 1.892 + } 1.893 + 1.894 + return pagePoint; 1.895 +} 1.896 + 1.897 +// static 1.898 +CSSIntPoint 1.899 +Event::GetClientCoords(nsPresContext* aPresContext, 1.900 + WidgetEvent* aEvent, 1.901 + LayoutDeviceIntPoint aPoint, 1.902 + CSSIntPoint aDefaultPoint) 1.903 +{ 1.904 + if (EventStateManager::sIsPointerLocked) { 1.905 + return EventStateManager::sLastClientPoint; 1.906 + } 1.907 + 1.908 + if (!aEvent || 1.909 + (aEvent->eventStructType != NS_MOUSE_EVENT && 1.910 + aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT && 1.911 + aEvent->eventStructType != NS_WHEEL_EVENT && 1.912 + aEvent->eventStructType != NS_TOUCH_EVENT && 1.913 + aEvent->eventStructType != NS_DRAG_EVENT && 1.914 + aEvent->eventStructType != NS_POINTER_EVENT && 1.915 + aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) || 1.916 + !aPresContext || 1.917 + !aEvent->AsGUIEvent()->widget) { 1.918 + return aDefaultPoint; 1.919 + } 1.920 + 1.921 + nsIPresShell* shell = aPresContext->GetPresShell(); 1.922 + if (!shell) { 1.923 + return CSSIntPoint(0, 0); 1.924 + } 1.925 + 1.926 + nsIFrame* rootFrame = shell->GetRootFrame(); 1.927 + if (!rootFrame) { 1.928 + return CSSIntPoint(0, 0); 1.929 + } 1.930 + nsPoint pt = 1.931 + nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, 1.932 + LayoutDeviceIntPoint::ToUntyped(aPoint), rootFrame); 1.933 + 1.934 + return CSSIntPoint::FromAppUnitsRounded(pt); 1.935 +} 1.936 + 1.937 +// To be called ONLY by Event::GetType (which has the additional 1.938 +// logic for handling user-defined events). 1.939 +// static 1.940 +const char* 1.941 +Event::GetEventName(uint32_t aEventType) 1.942 +{ 1.943 + switch(aEventType) { 1.944 +#define ID_TO_EVENT(name_, _id, _type, _struct) \ 1.945 + case _id: return #name_; 1.946 +#include "mozilla/EventNameList.h" 1.947 +#undef ID_TO_EVENT 1.948 + default: 1.949 + break; 1.950 + } 1.951 + // XXXldb We can hit this case for WidgetEvent objects that we didn't 1.952 + // create and that are not user defined events since this function and 1.953 + // SetEventType are incomplete. (But fixing that requires fixing the 1.954 + // arrays in nsEventListenerManager too, since the events for which 1.955 + // this is a problem generally *are* created by Event.) 1.956 + return nullptr; 1.957 +} 1.958 + 1.959 +bool 1.960 +Event::DefaultPrevented(JSContext* aCx) const 1.961 +{ 1.962 + MOZ_ASSERT(aCx, "JS context must be specified"); 1.963 + 1.964 + NS_ENSURE_TRUE(mEvent, false); 1.965 + 1.966 + // If preventDefault() has never been called, just return false. 1.967 + if (!mEvent->mFlags.mDefaultPrevented) { 1.968 + return false; 1.969 + } 1.970 + 1.971 + // If preventDefault() has been called by content, return true. Otherwise, 1.972 + // i.e., preventDefault() has been called by chrome, return true only when 1.973 + // this is called by chrome. 1.974 + return mEvent->mFlags.mDefaultPreventedByContent || IsChrome(aCx); 1.975 +} 1.976 + 1.977 +bool 1.978 +Event::GetPreventDefault() const 1.979 +{ 1.980 + if (mOwner) { 1.981 + if (nsIDocument* doc = mOwner->GetExtantDoc()) { 1.982 + doc->WarnOnceAbout(nsIDocument::eGetPreventDefault); 1.983 + } 1.984 + } 1.985 + // GetPreventDefault() is legacy and Gecko specific method. Although, 1.986 + // the result should be same as defaultPrevented, we don't need to break 1.987 + // backward compatibility of legacy method. Let's behave traditionally. 1.988 + return DefaultPrevented(); 1.989 +} 1.990 + 1.991 +NS_IMETHODIMP 1.992 +Event::GetPreventDefault(bool* aReturn) 1.993 +{ 1.994 + NS_ENSURE_ARG_POINTER(aReturn); 1.995 + *aReturn = GetPreventDefault(); 1.996 + return NS_OK; 1.997 +} 1.998 + 1.999 +NS_IMETHODIMP 1.1000 +Event::GetDefaultPrevented(bool* aReturn) 1.1001 +{ 1.1002 + NS_ENSURE_ARG_POINTER(aReturn); 1.1003 + // This method must be called by only event handlers implemented by C++. 1.1004 + // Then, the handlers must handle default action. So, this method don't need 1.1005 + // to check if preventDefault() has been called by content or chrome. 1.1006 + *aReturn = DefaultPrevented(); 1.1007 + return NS_OK; 1.1008 +} 1.1009 + 1.1010 +NS_IMETHODIMP_(void) 1.1011 +Event::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) 1.1012 +{ 1.1013 + if (aSerializeInterfaceType) { 1.1014 + IPC::WriteParam(aMsg, NS_LITERAL_STRING("event")); 1.1015 + } 1.1016 + 1.1017 + nsString type; 1.1018 + GetType(type); 1.1019 + IPC::WriteParam(aMsg, type); 1.1020 + 1.1021 + IPC::WriteParam(aMsg, Bubbles()); 1.1022 + IPC::WriteParam(aMsg, Cancelable()); 1.1023 + IPC::WriteParam(aMsg, IsTrusted()); 1.1024 + 1.1025 + // No timestamp serialization for now! 1.1026 +} 1.1027 + 1.1028 +NS_IMETHODIMP_(bool) 1.1029 +Event::Deserialize(const IPC::Message* aMsg, void** aIter) 1.1030 +{ 1.1031 + nsString type; 1.1032 + NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), false); 1.1033 + 1.1034 + bool bubbles = false; 1.1035 + NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false); 1.1036 + 1.1037 + bool cancelable = false; 1.1038 + NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), false); 1.1039 + 1.1040 + bool trusted = false; 1.1041 + NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false); 1.1042 + 1.1043 + nsresult rv = InitEvent(type, bubbles, cancelable); 1.1044 + NS_ENSURE_SUCCESS(rv, false); 1.1045 + SetTrusted(trusted); 1.1046 + 1.1047 + return true; 1.1048 +} 1.1049 + 1.1050 +NS_IMETHODIMP_(void) 1.1051 +Event::SetOwner(mozilla::dom::EventTarget* aOwner) 1.1052 +{ 1.1053 + mOwner = nullptr; 1.1054 + 1.1055 + if (!aOwner) { 1.1056 + return; 1.1057 + } 1.1058 + 1.1059 + nsCOMPtr<nsINode> n = do_QueryInterface(aOwner); 1.1060 + if (n) { 1.1061 + mOwner = do_QueryInterface(n->OwnerDoc()->GetScopeObject()); 1.1062 + return; 1.1063 + } 1.1064 + 1.1065 + nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aOwner); 1.1066 + if (w) { 1.1067 + if (w->IsOuterWindow()) { 1.1068 + mOwner = w->GetCurrentInnerWindow(); 1.1069 + } else { 1.1070 + mOwner.swap(w); 1.1071 + } 1.1072 + return; 1.1073 + } 1.1074 + 1.1075 + nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner); 1.1076 + if (eth) { 1.1077 + mOwner = eth->GetOwner(); 1.1078 + return; 1.1079 + } 1.1080 + 1.1081 +#ifdef DEBUG 1.1082 + nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner); 1.1083 + MOZ_ASSERT(root, "Unexpected EventTarget!"); 1.1084 +#endif 1.1085 +} 1.1086 + 1.1087 +} // namespace dom 1.1088 +} // namespace mozilla 1.1089 + 1.1090 +using namespace mozilla; 1.1091 +using namespace mozilla::dom; 1.1092 + 1.1093 +nsresult 1.1094 +NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult, 1.1095 + EventTarget* aOwner, 1.1096 + nsPresContext* aPresContext, 1.1097 + WidgetEvent* aEvent) 1.1098 +{ 1.1099 + Event* it = new Event(aOwner, aPresContext, aEvent); 1.1100 + NS_ADDREF(it); 1.1101 + *aInstancePtrResult = static_cast<Event*>(it); 1.1102 + return NS_OK; 1.1103 +}