1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/UIEvent.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,514 @@ 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 "base/basictypes.h" 1.10 +#include "ipc/IPCMessageUtils.h" 1.11 +#include "mozilla/dom/UIEvent.h" 1.12 +#include "mozilla/ArrayUtils.h" 1.13 +#include "mozilla/Assertions.h" 1.14 +#include "mozilla/ContentEvents.h" 1.15 +#include "mozilla/EventStateManager.h" 1.16 +#include "mozilla/TextEvents.h" 1.17 +#include "nsCOMPtr.h" 1.18 +#include "nsContentUtils.h" 1.19 +#include "nsIContent.h" 1.20 +#include "nsIInterfaceRequestorUtils.h" 1.21 +#include "nsIDOMWindow.h" 1.22 +#include "nsIDOMNode.h" 1.23 +#include "nsIFrame.h" 1.24 +#include "prtime.h" 1.25 + 1.26 +namespace mozilla { 1.27 +namespace dom { 1.28 + 1.29 +UIEvent::UIEvent(EventTarget* aOwner, 1.30 + nsPresContext* aPresContext, 1.31 + WidgetGUIEvent* aEvent) 1.32 + : Event(aOwner, aPresContext, 1.33 + aEvent ? aEvent : new InternalUIEvent(false, 0)) 1.34 + , mClientPoint(0, 0) 1.35 + , mLayerPoint(0, 0) 1.36 + , mPagePoint(0, 0) 1.37 + , mMovementPoint(0, 0) 1.38 + , mIsPointerLocked(EventStateManager::sIsPointerLocked) 1.39 + , mLastClientPoint(EventStateManager::sLastClientPoint) 1.40 +{ 1.41 + if (aEvent) { 1.42 + mEventIsInternal = false; 1.43 + } 1.44 + else { 1.45 + mEventIsInternal = true; 1.46 + mEvent->time = PR_Now(); 1.47 + } 1.48 + 1.49 + // Fill mDetail and mView according to the mEvent (widget-generated 1.50 + // event) we've got 1.51 + switch(mEvent->eventStructType) 1.52 + { 1.53 + case NS_UI_EVENT: 1.54 + { 1.55 + mDetail = mEvent->AsUIEvent()->detail; 1.56 + break; 1.57 + } 1.58 + 1.59 + case NS_SCROLLPORT_EVENT: 1.60 + { 1.61 + InternalScrollPortEvent* scrollEvent = mEvent->AsScrollPortEvent(); 1.62 + mDetail = (int32_t)scrollEvent->orient; 1.63 + break; 1.64 + } 1.65 + 1.66 + default: 1.67 + mDetail = 0; 1.68 + break; 1.69 + } 1.70 + 1.71 + mView = nullptr; 1.72 + if (mPresContext) 1.73 + { 1.74 + nsISupports* container = mPresContext->GetContainerWeak(); 1.75 + if (container) 1.76 + { 1.77 + nsCOMPtr<nsIDOMWindow> window = do_GetInterface(container); 1.78 + if (window) 1.79 + mView = do_QueryInterface(window); 1.80 + } 1.81 + } 1.82 +} 1.83 + 1.84 +// static 1.85 +already_AddRefed<UIEvent> 1.86 +UIEvent::Constructor(const GlobalObject& aGlobal, 1.87 + const nsAString& aType, 1.88 + const UIEventInit& aParam, 1.89 + ErrorResult& aRv) 1.90 +{ 1.91 + nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports()); 1.92 + nsRefPtr<UIEvent> e = new UIEvent(t, nullptr, nullptr); 1.93 + bool trusted = e->Init(t); 1.94 + aRv = e->InitUIEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView, 1.95 + aParam.mDetail); 1.96 + e->SetTrusted(trusted); 1.97 + return e.forget(); 1.98 +} 1.99 + 1.100 +NS_IMPL_CYCLE_COLLECTION_INHERITED(UIEvent, Event, 1.101 + mView) 1.102 + 1.103 +NS_IMPL_ADDREF_INHERITED(UIEvent, Event) 1.104 +NS_IMPL_RELEASE_INHERITED(UIEvent, Event) 1.105 + 1.106 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(UIEvent) 1.107 + NS_INTERFACE_MAP_ENTRY(nsIDOMUIEvent) 1.108 +NS_INTERFACE_MAP_END_INHERITING(Event) 1.109 + 1.110 +static nsIntPoint 1.111 +DevPixelsToCSSPixels(const LayoutDeviceIntPoint& aPoint, 1.112 + nsPresContext* aContext) 1.113 +{ 1.114 + return nsIntPoint(aContext->DevPixelsToIntCSSPixels(aPoint.x), 1.115 + aContext->DevPixelsToIntCSSPixels(aPoint.y)); 1.116 +} 1.117 + 1.118 +nsIntPoint 1.119 +UIEvent::GetMovementPoint() 1.120 +{ 1.121 + if (mPrivateDataDuplicated) { 1.122 + return mMovementPoint; 1.123 + } 1.124 + 1.125 + if (!mEvent || 1.126 + (mEvent->eventStructType != NS_MOUSE_EVENT && 1.127 + mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT && 1.128 + mEvent->eventStructType != NS_WHEEL_EVENT && 1.129 + mEvent->eventStructType != NS_DRAG_EVENT && 1.130 + mEvent->eventStructType != NS_POINTER_EVENT && 1.131 + mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) || 1.132 + !mEvent->AsGUIEvent()->widget) { 1.133 + return nsIntPoint(0, 0); 1.134 + } 1.135 + 1.136 + // Calculate the delta between the last screen point and the current one. 1.137 + nsIntPoint current = DevPixelsToCSSPixels(mEvent->refPoint, mPresContext); 1.138 + nsIntPoint last = DevPixelsToCSSPixels(mEvent->lastRefPoint, mPresContext); 1.139 + return current - last; 1.140 +} 1.141 + 1.142 +NS_IMETHODIMP 1.143 +UIEvent::GetView(nsIDOMWindow** aView) 1.144 +{ 1.145 + *aView = mView; 1.146 + NS_IF_ADDREF(*aView); 1.147 + return NS_OK; 1.148 +} 1.149 + 1.150 +NS_IMETHODIMP 1.151 +UIEvent::GetDetail(int32_t* aDetail) 1.152 +{ 1.153 + *aDetail = mDetail; 1.154 + return NS_OK; 1.155 +} 1.156 + 1.157 +NS_IMETHODIMP 1.158 +UIEvent::InitUIEvent(const nsAString& typeArg, 1.159 + bool canBubbleArg, 1.160 + bool cancelableArg, 1.161 + nsIDOMWindow* viewArg, 1.162 + int32_t detailArg) 1.163 +{ 1.164 + if (viewArg) { 1.165 + nsCOMPtr<nsPIDOMWindow> view = do_QueryInterface(viewArg); 1.166 + NS_ENSURE_TRUE(view, NS_ERROR_INVALID_ARG); 1.167 + } 1.168 + nsresult rv = Event::InitEvent(typeArg, canBubbleArg, cancelableArg); 1.169 + NS_ENSURE_SUCCESS(rv, rv); 1.170 + 1.171 + mDetail = detailArg; 1.172 + mView = viewArg; 1.173 + 1.174 + return NS_OK; 1.175 +} 1.176 + 1.177 +NS_IMETHODIMP 1.178 +UIEvent::GetPageX(int32_t* aPageX) 1.179 +{ 1.180 + NS_ENSURE_ARG_POINTER(aPageX); 1.181 + *aPageX = PageX(); 1.182 + return NS_OK; 1.183 +} 1.184 + 1.185 +int32_t 1.186 +UIEvent::PageX() const 1.187 +{ 1.188 + if (mPrivateDataDuplicated) { 1.189 + return mPagePoint.x; 1.190 + } 1.191 + 1.192 + return Event::GetPageCoords(mPresContext, mEvent, mEvent->refPoint, 1.193 + mClientPoint).x; 1.194 +} 1.195 + 1.196 +NS_IMETHODIMP 1.197 +UIEvent::GetPageY(int32_t* aPageY) 1.198 +{ 1.199 + NS_ENSURE_ARG_POINTER(aPageY); 1.200 + *aPageY = PageY(); 1.201 + return NS_OK; 1.202 +} 1.203 + 1.204 +int32_t 1.205 +UIEvent::PageY() const 1.206 +{ 1.207 + if (mPrivateDataDuplicated) { 1.208 + return mPagePoint.y; 1.209 + } 1.210 + 1.211 + return Event::GetPageCoords(mPresContext, mEvent, mEvent->refPoint, 1.212 + mClientPoint).y; 1.213 +} 1.214 + 1.215 +NS_IMETHODIMP 1.216 +UIEvent::GetWhich(uint32_t* aWhich) 1.217 +{ 1.218 + NS_ENSURE_ARG_POINTER(aWhich); 1.219 + *aWhich = Which(); 1.220 + return NS_OK; 1.221 +} 1.222 + 1.223 +already_AddRefed<nsINode> 1.224 +UIEvent::GetRangeParent() 1.225 +{ 1.226 + nsIFrame* targetFrame = nullptr; 1.227 + 1.228 + if (mPresContext) { 1.229 + targetFrame = mPresContext->EventStateManager()->GetEventTarget(); 1.230 + } 1.231 + 1.232 + if (targetFrame) { 1.233 + nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent, 1.234 + targetFrame); 1.235 + nsCOMPtr<nsIContent> parent = targetFrame->GetContentOffsetsFromPoint(pt).content; 1.236 + if (parent) { 1.237 + if (parent->ChromeOnlyAccess() && 1.238 + !nsContentUtils::CanAccessNativeAnon()) { 1.239 + return nullptr; 1.240 + } 1.241 + return parent.forget(); 1.242 + } 1.243 + } 1.244 + 1.245 + return nullptr; 1.246 +} 1.247 + 1.248 +NS_IMETHODIMP 1.249 +UIEvent::GetRangeParent(nsIDOMNode** aRangeParent) 1.250 +{ 1.251 + NS_ENSURE_ARG_POINTER(aRangeParent); 1.252 + *aRangeParent = nullptr; 1.253 + nsCOMPtr<nsINode> n = GetRangeParent(); 1.254 + if (n) { 1.255 + CallQueryInterface(n, aRangeParent); 1.256 + } 1.257 + return NS_OK; 1.258 +} 1.259 + 1.260 +NS_IMETHODIMP 1.261 +UIEvent::GetRangeOffset(int32_t* aRangeOffset) 1.262 +{ 1.263 + NS_ENSURE_ARG_POINTER(aRangeOffset); 1.264 + *aRangeOffset = RangeOffset(); 1.265 + return NS_OK; 1.266 +} 1.267 + 1.268 +int32_t 1.269 +UIEvent::RangeOffset() const 1.270 +{ 1.271 + if (!mPresContext) { 1.272 + return 0; 1.273 + } 1.274 + 1.275 + nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget(); 1.276 + if (!targetFrame) { 1.277 + return 0; 1.278 + } 1.279 + 1.280 + nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent, 1.281 + targetFrame); 1.282 + return targetFrame->GetContentOffsetsFromPoint(pt).offset; 1.283 +} 1.284 + 1.285 +NS_IMETHODIMP 1.286 +UIEvent::GetCancelBubble(bool* aCancelBubble) 1.287 +{ 1.288 + NS_ENSURE_ARG_POINTER(aCancelBubble); 1.289 + *aCancelBubble = CancelBubble(); 1.290 + return NS_OK; 1.291 +} 1.292 + 1.293 +NS_IMETHODIMP 1.294 +UIEvent::SetCancelBubble(bool aCancelBubble) 1.295 +{ 1.296 + mEvent->mFlags.mPropagationStopped = aCancelBubble; 1.297 + return NS_OK; 1.298 +} 1.299 + 1.300 +nsIntPoint 1.301 +UIEvent::GetLayerPoint() const 1.302 +{ 1.303 + if (!mEvent || 1.304 + (mEvent->eventStructType != NS_MOUSE_EVENT && 1.305 + mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT && 1.306 + mEvent->eventStructType != NS_WHEEL_EVENT && 1.307 + mEvent->eventStructType != NS_POINTER_EVENT && 1.308 + mEvent->eventStructType != NS_TOUCH_EVENT && 1.309 + mEvent->eventStructType != NS_DRAG_EVENT && 1.310 + mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) || 1.311 + !mPresContext || 1.312 + mEventIsInternal) { 1.313 + return mLayerPoint; 1.314 + } 1.315 + // XXX I'm not really sure this is correct; it's my best shot, though 1.316 + nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget(); 1.317 + if (!targetFrame) 1.318 + return mLayerPoint; 1.319 + nsIFrame* layer = nsLayoutUtils::GetClosestLayer(targetFrame); 1.320 + nsPoint pt(nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent, layer)); 1.321 + return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x), 1.322 + nsPresContext::AppUnitsToIntCSSPixels(pt.y)); 1.323 +} 1.324 + 1.325 +NS_IMETHODIMP 1.326 +UIEvent::GetLayerX(int32_t* aLayerX) 1.327 +{ 1.328 + NS_ENSURE_ARG_POINTER(aLayerX); 1.329 + *aLayerX = GetLayerPoint().x; 1.330 + return NS_OK; 1.331 +} 1.332 + 1.333 +NS_IMETHODIMP 1.334 +UIEvent::GetLayerY(int32_t* aLayerY) 1.335 +{ 1.336 + NS_ENSURE_ARG_POINTER(aLayerY); 1.337 + *aLayerY = GetLayerPoint().y; 1.338 + return NS_OK; 1.339 +} 1.340 + 1.341 +NS_IMETHODIMP 1.342 +UIEvent::GetIsChar(bool* aIsChar) 1.343 +{ 1.344 + *aIsChar = IsChar(); 1.345 + return NS_OK; 1.346 +} 1.347 + 1.348 +bool 1.349 +UIEvent::IsChar() const 1.350 +{ 1.351 + WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent(); 1.352 + if (keyEvent) { 1.353 + return keyEvent->isChar; 1.354 + } 1.355 + WidgetTextEvent* textEvent = mEvent->AsTextEvent(); 1.356 + return textEvent ? textEvent->isChar : false; 1.357 +} 1.358 + 1.359 +NS_IMETHODIMP 1.360 +UIEvent::DuplicatePrivateData() 1.361 +{ 1.362 + mClientPoint = 1.363 + Event::GetClientCoords(mPresContext, mEvent, mEvent->refPoint, 1.364 + mClientPoint); 1.365 + mMovementPoint = GetMovementPoint(); 1.366 + mLayerPoint = GetLayerPoint(); 1.367 + mPagePoint = 1.368 + Event::GetPageCoords(mPresContext, mEvent, mEvent->refPoint, mClientPoint); 1.369 + // GetScreenPoint converts mEvent->refPoint to right coordinates. 1.370 + nsIntPoint screenPoint = 1.371 + Event::GetScreenCoords(mPresContext, mEvent, mEvent->refPoint); 1.372 + nsresult rv = Event::DuplicatePrivateData(); 1.373 + if (NS_SUCCEEDED(rv)) { 1.374 + mEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(screenPoint); 1.375 + } 1.376 + return rv; 1.377 +} 1.378 + 1.379 +NS_IMETHODIMP_(void) 1.380 +UIEvent::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) 1.381 +{ 1.382 + if (aSerializeInterfaceType) { 1.383 + IPC::WriteParam(aMsg, NS_LITERAL_STRING("uievent")); 1.384 + } 1.385 + 1.386 + Event::Serialize(aMsg, false); 1.387 + 1.388 + int32_t detail = 0; 1.389 + GetDetail(&detail); 1.390 + IPC::WriteParam(aMsg, detail); 1.391 +} 1.392 + 1.393 +NS_IMETHODIMP_(bool) 1.394 +UIEvent::Deserialize(const IPC::Message* aMsg, void** aIter) 1.395 +{ 1.396 + NS_ENSURE_TRUE(Event::Deserialize(aMsg, aIter), false); 1.397 + NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &mDetail), false); 1.398 + return true; 1.399 +} 1.400 + 1.401 +// XXX Following struct and array are used only in 1.402 +// UIEvent::ComputeModifierState(), but if we define them in it, 1.403 +// we fail to build on Mac at calling mozilla::ArrayLength(). 1.404 +struct ModifierPair 1.405 +{ 1.406 + Modifier modifier; 1.407 + const char* name; 1.408 +}; 1.409 +static const ModifierPair kPairs[] = { 1.410 + { MODIFIER_ALT, NS_DOM_KEYNAME_ALT }, 1.411 + { MODIFIER_ALTGRAPH, NS_DOM_KEYNAME_ALTGRAPH }, 1.412 + { MODIFIER_CAPSLOCK, NS_DOM_KEYNAME_CAPSLOCK }, 1.413 + { MODIFIER_CONTROL, NS_DOM_KEYNAME_CONTROL }, 1.414 + { MODIFIER_FN, NS_DOM_KEYNAME_FN }, 1.415 + { MODIFIER_META, NS_DOM_KEYNAME_META }, 1.416 + { MODIFIER_NUMLOCK, NS_DOM_KEYNAME_NUMLOCK }, 1.417 + { MODIFIER_SCROLLLOCK, NS_DOM_KEYNAME_SCROLLLOCK }, 1.418 + { MODIFIER_SHIFT, NS_DOM_KEYNAME_SHIFT }, 1.419 + { MODIFIER_SYMBOLLOCK, NS_DOM_KEYNAME_SYMBOLLOCK }, 1.420 + { MODIFIER_OS, NS_DOM_KEYNAME_OS } 1.421 +}; 1.422 + 1.423 +// static 1.424 +Modifiers 1.425 +UIEvent::ComputeModifierState(const nsAString& aModifiersList) 1.426 +{ 1.427 + if (aModifiersList.IsEmpty()) { 1.428 + return 0; 1.429 + } 1.430 + 1.431 + // Be careful about the performance. If aModifiersList is too long, 1.432 + // parsing it needs too long time. 1.433 + // XXX Should we abort if aModifiersList is too long? 1.434 + 1.435 + Modifiers modifiers = 0; 1.436 + 1.437 + nsAString::const_iterator listStart, listEnd; 1.438 + aModifiersList.BeginReading(listStart); 1.439 + aModifiersList.EndReading(listEnd); 1.440 + 1.441 + for (uint32_t i = 0; i < ArrayLength(kPairs); i++) { 1.442 + nsAString::const_iterator start(listStart), end(listEnd); 1.443 + if (!FindInReadable(NS_ConvertASCIItoUTF16(kPairs[i].name), start, end)) { 1.444 + continue; 1.445 + } 1.446 + 1.447 + if ((start != listStart && !NS_IsAsciiWhitespace(*(--start))) || 1.448 + (end != listEnd && !NS_IsAsciiWhitespace(*(end)))) { 1.449 + continue; 1.450 + } 1.451 + modifiers |= kPairs[i].modifier; 1.452 + } 1.453 + 1.454 + return modifiers; 1.455 +} 1.456 + 1.457 +bool 1.458 +UIEvent::GetModifierStateInternal(const nsAString& aKey) 1.459 +{ 1.460 + WidgetInputEvent* inputEvent = mEvent->AsInputEvent(); 1.461 + MOZ_ASSERT(inputEvent, "mEvent must be WidgetInputEvent or derived class"); 1.462 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SHIFT)) { 1.463 + return inputEvent->IsShift(); 1.464 + } 1.465 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_CONTROL)) { 1.466 + return inputEvent->IsControl(); 1.467 + } 1.468 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_META)) { 1.469 + return inputEvent->IsMeta(); 1.470 + } 1.471 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_ALT)) { 1.472 + return inputEvent->IsAlt(); 1.473 + } 1.474 + 1.475 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_ALTGRAPH)) { 1.476 + return inputEvent->IsAltGraph(); 1.477 + } 1.478 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_OS)) { 1.479 + return inputEvent->IsOS(); 1.480 + } 1.481 + 1.482 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_CAPSLOCK)) { 1.483 + return inputEvent->IsCapsLocked(); 1.484 + } 1.485 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_NUMLOCK)) { 1.486 + return inputEvent->IsNumLocked(); 1.487 + } 1.488 + 1.489 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_FN)) { 1.490 + return inputEvent->IsFn(); 1.491 + } 1.492 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SCROLLLOCK)) { 1.493 + return inputEvent->IsScrollLocked(); 1.494 + } 1.495 + if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SYMBOLLOCK)) { 1.496 + return inputEvent->IsSymbolLocked(); 1.497 + } 1.498 + return false; 1.499 +} 1.500 + 1.501 +} // namespace dom 1.502 +} // namespace mozilla 1.503 + 1.504 +using namespace mozilla; 1.505 +using namespace mozilla::dom; 1.506 + 1.507 +nsresult 1.508 +NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult, 1.509 + EventTarget* aOwner, 1.510 + nsPresContext* aPresContext, 1.511 + WidgetGUIEvent* aEvent) 1.512 +{ 1.513 + UIEvent* it = new UIEvent(aOwner, aPresContext, aEvent); 1.514 + NS_ADDREF(it); 1.515 + *aInstancePtrResult = static_cast<Event*>(it); 1.516 + return NS_OK; 1.517 +}