1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/EventStateManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,5523 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozilla/Attributes.h" 1.11 +#include "mozilla/EventDispatcher.h" 1.12 +#include "mozilla/EventStateManager.h" 1.13 +#include "mozilla/EventStates.h" 1.14 +#include "mozilla/IMEStateManager.h" 1.15 +#include "mozilla/MiscEvents.h" 1.16 +#include "mozilla/MathAlgorithms.h" 1.17 +#include "mozilla/MouseEvents.h" 1.18 +#include "mozilla/TextComposition.h" 1.19 +#include "mozilla/TextEvents.h" 1.20 +#include "mozilla/TouchEvents.h" 1.21 +#include "mozilla/dom/Event.h" 1.22 +#include "mozilla/dom/TabParent.h" 1.23 +#include "mozilla/dom/UIEvent.h" 1.24 + 1.25 +#include "ContentEventHandler.h" 1.26 +#include "IMEContentObserver.h" 1.27 +#include "WheelHandlingHelper.h" 1.28 + 1.29 +#include "nsCOMPtr.h" 1.30 +#include "nsFocusManager.h" 1.31 +#include "nsIContent.h" 1.32 +#include "nsINodeInfo.h" 1.33 +#include "nsIDocument.h" 1.34 +#include "nsIFrame.h" 1.35 +#include "nsIWidget.h" 1.36 +#include "nsPresContext.h" 1.37 +#include "nsIPresShell.h" 1.38 +#include "nsGkAtoms.h" 1.39 +#include "nsIFormControl.h" 1.40 +#include "nsIComboboxControlFrame.h" 1.41 +#include "nsIScrollableFrame.h" 1.42 +#include "nsIDOMHTMLElement.h" 1.43 +#include "nsIDOMXULControlElement.h" 1.44 +#include "nsNameSpaceManager.h" 1.45 +#include "nsIBaseWindow.h" 1.46 +#include "nsISelection.h" 1.47 +#include "nsITextControlElement.h" 1.48 +#include "nsFrameSelection.h" 1.49 +#include "nsPIDOMWindow.h" 1.50 +#include "nsPIWindowRoot.h" 1.51 +#include "nsIWebNavigation.h" 1.52 +#include "nsIContentViewer.h" 1.53 +#include "nsFrameManager.h" 1.54 + 1.55 +#include "nsIDOMXULElement.h" 1.56 +#include "nsIDOMKeyEvent.h" 1.57 +#include "nsIObserverService.h" 1.58 +#include "nsIDocShell.h" 1.59 +#include "nsIMarkupDocumentViewer.h" 1.60 +#include "nsIDOMWheelEvent.h" 1.61 +#include "nsIDOMDragEvent.h" 1.62 +#include "nsIDOMUIEvent.h" 1.63 +#include "nsIMozBrowserFrame.h" 1.64 + 1.65 +#include "nsSubDocumentFrame.h" 1.66 +#include "nsLayoutUtils.h" 1.67 +#include "nsIInterfaceRequestorUtils.h" 1.68 +#include "nsUnicharUtils.h" 1.69 +#include "nsContentUtils.h" 1.70 + 1.71 +#include "imgIContainer.h" 1.72 +#include "nsIProperties.h" 1.73 +#include "nsISupportsPrimitives.h" 1.74 + 1.75 +#include "nsServiceManagerUtils.h" 1.76 +#include "nsITimer.h" 1.77 +#include "nsFontMetrics.h" 1.78 +#include "nsIDOMXULDocument.h" 1.79 +#include "nsIDragService.h" 1.80 +#include "nsIDragSession.h" 1.81 +#include "mozilla/dom/DataTransfer.h" 1.82 +#include "nsContentAreaDragDrop.h" 1.83 +#ifdef MOZ_XUL 1.84 +#include "nsTreeBodyFrame.h" 1.85 +#endif 1.86 +#include "nsIController.h" 1.87 +#include "nsICommandParams.h" 1.88 +#include "mozilla/Services.h" 1.89 +#include "mozilla/dom/HTMLLabelElement.h" 1.90 + 1.91 +#include "mozilla/Preferences.h" 1.92 +#include "mozilla/LookAndFeel.h" 1.93 +#include "GeckoProfiler.h" 1.94 +#include "Units.h" 1.95 + 1.96 +#ifdef XP_MACOSX 1.97 +#import <ApplicationServices/ApplicationServices.h> 1.98 +#endif 1.99 + 1.100 +namespace mozilla { 1.101 + 1.102 +using namespace dom; 1.103 + 1.104 +//#define DEBUG_DOCSHELL_FOCUS 1.105 + 1.106 +#define NS_USER_INTERACTION_INTERVAL 5000 // ms 1.107 + 1.108 +static const LayoutDeviceIntPoint kInvalidRefPoint = LayoutDeviceIntPoint(-1,-1); 1.109 + 1.110 +static uint32_t gMouseOrKeyboardEventCounter = 0; 1.111 +static nsITimer* gUserInteractionTimer = nullptr; 1.112 +static nsITimerCallback* gUserInteractionTimerCallback = nullptr; 1.113 + 1.114 +static inline int32_t 1.115 +RoundDown(double aDouble) 1.116 +{ 1.117 + return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble)) : 1.118 + static_cast<int32_t>(ceil(aDouble)); 1.119 +} 1.120 + 1.121 +#ifdef DEBUG_DOCSHELL_FOCUS 1.122 +static void 1.123 +PrintDocTree(nsIDocShellTreeItem* aParentItem, int aLevel) 1.124 +{ 1.125 + for (int32_t i=0;i<aLevel;i++) printf(" "); 1.126 + 1.127 + int32_t childWebshellCount; 1.128 + aParentItem->GetChildCount(&childWebshellCount); 1.129 + nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentItem)); 1.130 + int32_t type = aParentItem->ItemType(); 1.131 + nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell(); 1.132 + nsRefPtr<nsPresContext> presContext; 1.133 + parentAsDocShell->GetPresContext(getter_AddRefs(presContext)); 1.134 + nsCOMPtr<nsIContentViewer> cv; 1.135 + parentAsDocShell->GetContentViewer(getter_AddRefs(cv)); 1.136 + nsCOMPtr<nsIDOMDocument> domDoc; 1.137 + if (cv) 1.138 + cv->GetDOMDocument(getter_AddRefs(domDoc)); 1.139 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); 1.140 + nsCOMPtr<nsIDOMWindow> domwin = doc ? doc->GetWindow() : nullptr; 1.141 + nsIURI* uri = doc ? doc->GetDocumentURI() : nullptr; 1.142 + 1.143 + printf("DS %p Type %s Cnt %d Doc %p DW %p EM %p%c", 1.144 + static_cast<void*>(parentAsDocShell.get()), 1.145 + type==nsIDocShellTreeItem::typeChrome?"Chrome":"Content", 1.146 + childWebshellCount, static_cast<void*>(doc.get()), 1.147 + static_cast<void*>(domwin.get()), 1.148 + static_cast<void*>(presContext ? presContext->EventStateManager() : nullptr), 1.149 + uri ? ' ' : '\n'); 1.150 + if (uri) { 1.151 + nsAutoCString spec; 1.152 + uri->GetSpec(spec); 1.153 + printf("\"%s\"\n", spec.get()); 1.154 + } 1.155 + 1.156 + if (childWebshellCount > 0) { 1.157 + for (int32_t i = 0; i < childWebshellCount; i++) { 1.158 + nsCOMPtr<nsIDocShellTreeItem> child; 1.159 + aParentItem->GetChildAt(i, getter_AddRefs(child)); 1.160 + PrintDocTree(child, aLevel + 1); 1.161 + } 1.162 + } 1.163 +} 1.164 + 1.165 +static void 1.166 +PrintDocTreeAll(nsIDocShellTreeItem* aItem) 1.167 +{ 1.168 + nsCOMPtr<nsIDocShellTreeItem> item = aItem; 1.169 + for(;;) { 1.170 + nsCOMPtr<nsIDocShellTreeItem> parent; 1.171 + item->GetParent(getter_AddRefs(parent)); 1.172 + if (!parent) 1.173 + break; 1.174 + item = parent; 1.175 + } 1.176 + 1.177 + PrintDocTree(item, 0); 1.178 +} 1.179 +#endif 1.180 + 1.181 +// mask values for ui.key.chromeAccess and ui.key.contentAccess 1.182 +#define NS_MODIFIER_SHIFT 1 1.183 +#define NS_MODIFIER_CONTROL 2 1.184 +#define NS_MODIFIER_ALT 4 1.185 +#define NS_MODIFIER_META 8 1.186 +#define NS_MODIFIER_OS 16 1.187 + 1.188 +static nsIDocument * 1.189 +GetDocumentFromWindow(nsIDOMWindow *aWindow) 1.190 +{ 1.191 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aWindow); 1.192 + return win ? win->GetExtantDoc() : nullptr; 1.193 +} 1.194 + 1.195 +/******************************************************************/ 1.196 +/* mozilla::UITimerCallback */ 1.197 +/******************************************************************/ 1.198 + 1.199 +class UITimerCallback MOZ_FINAL : public nsITimerCallback 1.200 +{ 1.201 +public: 1.202 + UITimerCallback() : mPreviousCount(0) {} 1.203 + NS_DECL_ISUPPORTS 1.204 + NS_DECL_NSITIMERCALLBACK 1.205 +private: 1.206 + uint32_t mPreviousCount; 1.207 +}; 1.208 + 1.209 +NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback) 1.210 + 1.211 +// If aTimer is nullptr, this method always sends "user-interaction-inactive" 1.212 +// notification. 1.213 +NS_IMETHODIMP 1.214 +UITimerCallback::Notify(nsITimer* aTimer) 1.215 +{ 1.216 + nsCOMPtr<nsIObserverService> obs = 1.217 + mozilla::services::GetObserverService(); 1.218 + if (!obs) 1.219 + return NS_ERROR_FAILURE; 1.220 + if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) { 1.221 + gMouseOrKeyboardEventCounter = 0; 1.222 + obs->NotifyObservers(nullptr, "user-interaction-inactive", nullptr); 1.223 + if (gUserInteractionTimer) { 1.224 + gUserInteractionTimer->Cancel(); 1.225 + NS_RELEASE(gUserInteractionTimer); 1.226 + } 1.227 + } else { 1.228 + obs->NotifyObservers(nullptr, "user-interaction-active", nullptr); 1.229 + EventStateManager::UpdateUserActivityTimer(); 1.230 + } 1.231 + mPreviousCount = gMouseOrKeyboardEventCounter; 1.232 + return NS_OK; 1.233 +} 1.234 + 1.235 +/******************************************************************/ 1.236 +/* mozilla::OverOutElementsWrapper */ 1.237 +/******************************************************************/ 1.238 + 1.239 +OverOutElementsWrapper::OverOutElementsWrapper() 1.240 + : mLastOverFrame(nullptr) 1.241 +{ 1.242 +} 1.243 + 1.244 +OverOutElementsWrapper::~OverOutElementsWrapper() 1.245 +{ 1.246 +} 1.247 + 1.248 +NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper, 1.249 + mLastOverElement, 1.250 + mFirstOverEventElement, 1.251 + mFirstOutEventElement) 1.252 +NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper) 1.253 +NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper) 1.254 + 1.255 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper) 1.256 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.257 +NS_INTERFACE_MAP_END 1.258 + 1.259 +/******************************************************************/ 1.260 +/* mozilla::EventStateManager */ 1.261 +/******************************************************************/ 1.262 + 1.263 +static uint32_t sESMInstanceCount = 0; 1.264 + 1.265 +int32_t EventStateManager::sUserInputEventDepth = 0; 1.266 +bool EventStateManager::sNormalLMouseEventInProcess = false; 1.267 +EventStateManager* EventStateManager::sActiveESM = nullptr; 1.268 +nsIDocument* EventStateManager::sMouseOverDocument = nullptr; 1.269 +nsWeakFrame EventStateManager::sLastDragOverFrame = nullptr; 1.270 +LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint; 1.271 +nsIntPoint EventStateManager::sLastScreenPoint = nsIntPoint(0, 0); 1.272 +LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint; 1.273 +CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0); 1.274 +bool EventStateManager::sIsPointerLocked = false; 1.275 +// Reference to the pointer locked element. 1.276 +nsWeakPtr EventStateManager::sPointerLockedElement; 1.277 +// Reference to the document which requested pointer lock. 1.278 +nsWeakPtr EventStateManager::sPointerLockedDoc; 1.279 +nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr; 1.280 +TimeStamp EventStateManager::sHandlingInputStart; 1.281 + 1.282 +EventStateManager::WheelPrefs* 1.283 + EventStateManager::WheelPrefs::sInstance = nullptr; 1.284 +EventStateManager::DeltaAccumulator* 1.285 + EventStateManager::DeltaAccumulator::sInstance = nullptr; 1.286 + 1.287 +EventStateManager::EventStateManager() 1.288 + : mLockCursor(0) 1.289 + , mPreLockPoint(0,0) 1.290 + , mCurrentTarget(nullptr) 1.291 + // init d&d gesture state machine variables 1.292 + , mGestureDownPoint(0,0) 1.293 + , mPresContext(nullptr) 1.294 + , mLClickCount(0) 1.295 + , mMClickCount(0) 1.296 + , mRClickCount(0) 1.297 + , m_haveShutdown(false) 1.298 +{ 1.299 + if (sESMInstanceCount == 0) { 1.300 + gUserInteractionTimerCallback = new UITimerCallback(); 1.301 + if (gUserInteractionTimerCallback) 1.302 + NS_ADDREF(gUserInteractionTimerCallback); 1.303 + UpdateUserActivityTimer(); 1.304 + } 1.305 + ++sESMInstanceCount; 1.306 +} 1.307 + 1.308 +nsresult 1.309 +EventStateManager::UpdateUserActivityTimer() 1.310 +{ 1.311 + if (!gUserInteractionTimerCallback) 1.312 + return NS_OK; 1.313 + 1.314 + if (!gUserInteractionTimer) 1.315 + CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer); 1.316 + 1.317 + if (gUserInteractionTimer) { 1.318 + gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback, 1.319 + NS_USER_INTERACTION_INTERVAL, 1.320 + nsITimer::TYPE_ONE_SHOT); 1.321 + } 1.322 + return NS_OK; 1.323 +} 1.324 + 1.325 +nsresult 1.326 +EventStateManager::Init() 1.327 +{ 1.328 + nsCOMPtr<nsIObserverService> observerService = 1.329 + mozilla::services::GetObserverService(); 1.330 + if (!observerService) 1.331 + return NS_ERROR_FAILURE; 1.332 + 1.333 + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true); 1.334 + 1.335 + if (sESMInstanceCount == 1) { 1.336 + Prefs::Init(); 1.337 + } 1.338 + 1.339 + return NS_OK; 1.340 +} 1.341 + 1.342 +EventStateManager::~EventStateManager() 1.343 +{ 1.344 + ReleaseCurrentIMEContentObserver(); 1.345 + 1.346 + if (sActiveESM == this) { 1.347 + sActiveESM = nullptr; 1.348 + } 1.349 + if (Prefs::ClickHoldContextMenu()) 1.350 + KillClickHoldTimer(); 1.351 + 1.352 + if (mDocument == sMouseOverDocument) 1.353 + sMouseOverDocument = nullptr; 1.354 + 1.355 + --sESMInstanceCount; 1.356 + if(sESMInstanceCount == 0) { 1.357 + WheelTransaction::Shutdown(); 1.358 + if (gUserInteractionTimerCallback) { 1.359 + gUserInteractionTimerCallback->Notify(nullptr); 1.360 + NS_RELEASE(gUserInteractionTimerCallback); 1.361 + } 1.362 + if (gUserInteractionTimer) { 1.363 + gUserInteractionTimer->Cancel(); 1.364 + NS_RELEASE(gUserInteractionTimer); 1.365 + } 1.366 + Prefs::Shutdown(); 1.367 + WheelPrefs::Shutdown(); 1.368 + DeltaAccumulator::Shutdown(); 1.369 + } 1.370 + 1.371 + if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) { 1.372 + sDragOverContent = nullptr; 1.373 + } 1.374 + 1.375 + if (!m_haveShutdown) { 1.376 + Shutdown(); 1.377 + 1.378 + // Don't remove from Observer service in Shutdown because Shutdown also 1.379 + // gets called from xpcom shutdown observer. And we don't want to remove 1.380 + // from the service in that case. 1.381 + 1.382 + nsCOMPtr<nsIObserverService> observerService = 1.383 + mozilla::services::GetObserverService(); 1.384 + if (observerService) { 1.385 + observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); 1.386 + } 1.387 + } 1.388 + 1.389 +} 1.390 + 1.391 +nsresult 1.392 +EventStateManager::Shutdown() 1.393 +{ 1.394 + m_haveShutdown = true; 1.395 + return NS_OK; 1.396 +} 1.397 + 1.398 +NS_IMETHODIMP 1.399 +EventStateManager::Observe(nsISupports* aSubject, 1.400 + const char* aTopic, 1.401 + const char16_t *someData) 1.402 +{ 1.403 + if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { 1.404 + Shutdown(); 1.405 + } 1.406 + 1.407 + return NS_OK; 1.408 +} 1.409 + 1.410 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventStateManager) 1.411 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) 1.412 + NS_INTERFACE_MAP_ENTRY(nsIObserver) 1.413 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.414 +NS_INTERFACE_MAP_END 1.415 + 1.416 +NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager) 1.417 +NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager) 1.418 + 1.419 +NS_IMPL_CYCLE_COLLECTION(EventStateManager, 1.420 + mCurrentTargetContent, 1.421 + mGestureDownContent, 1.422 + mGestureDownFrameOwner, 1.423 + mLastLeftMouseDownContent, 1.424 + mLastLeftMouseDownContentParent, 1.425 + mLastMiddleMouseDownContent, 1.426 + mLastMiddleMouseDownContentParent, 1.427 + mLastRightMouseDownContent, 1.428 + mLastRightMouseDownContentParent, 1.429 + mActiveContent, 1.430 + mHoverContent, 1.431 + mURLTargetContent, 1.432 + mMouseEnterLeaveHelper, 1.433 + mPointersEnterLeaveHelper, 1.434 + mDocument, 1.435 + mIMEContentObserver, 1.436 + mAccessKeys) 1.437 + 1.438 +void 1.439 +EventStateManager::ReleaseCurrentIMEContentObserver() 1.440 +{ 1.441 + if (mIMEContentObserver) { 1.442 + mIMEContentObserver->DisconnectFromEventStateManager(); 1.443 + } 1.444 + mIMEContentObserver = nullptr; 1.445 +} 1.446 + 1.447 +void 1.448 +EventStateManager::OnStartToObserveContent( 1.449 + IMEContentObserver* aIMEContentObserver) 1.450 +{ 1.451 + ReleaseCurrentIMEContentObserver(); 1.452 + mIMEContentObserver = aIMEContentObserver; 1.453 +} 1.454 + 1.455 +void 1.456 +EventStateManager::OnStopObservingContent( 1.457 + IMEContentObserver* aIMEContentObserver) 1.458 +{ 1.459 + aIMEContentObserver->DisconnectFromEventStateManager(); 1.460 + NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver); 1.461 + mIMEContentObserver = nullptr; 1.462 +} 1.463 + 1.464 +nsresult 1.465 +EventStateManager::PreHandleEvent(nsPresContext* aPresContext, 1.466 + WidgetEvent* aEvent, 1.467 + nsIFrame* aTargetFrame, 1.468 + nsEventStatus* aStatus) 1.469 +{ 1.470 + NS_ENSURE_ARG_POINTER(aStatus); 1.471 + NS_ENSURE_ARG(aPresContext); 1.472 + if (!aEvent) { 1.473 + NS_ERROR("aEvent is null. This should never happen."); 1.474 + return NS_ERROR_NULL_POINTER; 1.475 + } 1.476 + 1.477 + mCurrentTarget = aTargetFrame; 1.478 + mCurrentTargetContent = nullptr; 1.479 + 1.480 + // Focus events don't necessarily need a frame. 1.481 + if (NS_EVENT_NEEDS_FRAME(aEvent)) { 1.482 + NS_ASSERTION(mCurrentTarget, "mCurrentTarget is null. this should not happen. see bug #13007"); 1.483 + if (!mCurrentTarget) return NS_ERROR_NULL_POINTER; 1.484 + } 1.485 +#ifdef DEBUG 1.486 + if (aEvent->HasDragEventMessage() && sIsPointerLocked) { 1.487 + NS_ASSERTION(sIsPointerLocked, 1.488 + "sIsPointerLocked is true. Drag events should be suppressed when the pointer is locked."); 1.489 + } 1.490 +#endif 1.491 + // Store last known screenPoint and clientPoint so pointer lock 1.492 + // can use these values as constants. 1.493 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.494 + if (aEvent->mFlags.mIsTrusted && 1.495 + ((mouseEvent && mouseEvent->IsReal()) || 1.496 + aEvent->eventStructType == NS_WHEEL_EVENT) && 1.497 + !sIsPointerLocked) { 1.498 + sLastScreenPoint = 1.499 + UIEvent::CalculateScreenPoint(aPresContext, aEvent); 1.500 + sLastClientPoint = 1.501 + UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr); 1.502 + } 1.503 + 1.504 + // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page 1.505 + // when user is not active doesn't change the state to active. 1.506 + if (aEvent->mFlags.mIsTrusted && 1.507 + ((mouseEvent && mouseEvent->IsReal() && 1.508 + mouseEvent->message != NS_MOUSE_ENTER && 1.509 + mouseEvent->message != NS_MOUSE_EXIT) || 1.510 + aEvent->eventStructType == NS_WHEEL_EVENT || 1.511 + aEvent->eventStructType == NS_KEY_EVENT)) { 1.512 + if (gMouseOrKeyboardEventCounter == 0) { 1.513 + nsCOMPtr<nsIObserverService> obs = 1.514 + mozilla::services::GetObserverService(); 1.515 + if (obs) { 1.516 + obs->NotifyObservers(nullptr, "user-interaction-active", nullptr); 1.517 + UpdateUserActivityTimer(); 1.518 + } 1.519 + } 1.520 + ++gMouseOrKeyboardEventCounter; 1.521 + } 1.522 + 1.523 + *aStatus = nsEventStatus_eIgnore; 1.524 + 1.525 + WheelTransaction::OnEvent(aEvent); 1.526 + 1.527 + switch (aEvent->message) { 1.528 + case NS_MOUSE_BUTTON_DOWN: { 1.529 + switch (mouseEvent->button) { 1.530 + case WidgetMouseEvent::eLeftButton: 1.531 + BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame); 1.532 + mLClickCount = mouseEvent->clickCount; 1.533 + SetClickCount(aPresContext, mouseEvent, aStatus); 1.534 + sNormalLMouseEventInProcess = true; 1.535 + break; 1.536 + case WidgetMouseEvent::eMiddleButton: 1.537 + mMClickCount = mouseEvent->clickCount; 1.538 + SetClickCount(aPresContext, mouseEvent, aStatus); 1.539 + break; 1.540 + case WidgetMouseEvent::eRightButton: 1.541 + mRClickCount = mouseEvent->clickCount; 1.542 + SetClickCount(aPresContext, mouseEvent, aStatus); 1.543 + break; 1.544 + } 1.545 + break; 1.546 + } 1.547 + case NS_MOUSE_BUTTON_UP: { 1.548 + switch (mouseEvent->button) { 1.549 + case WidgetMouseEvent::eLeftButton: 1.550 + if (Prefs::ClickHoldContextMenu()) { 1.551 + KillClickHoldTimer(); 1.552 + } 1.553 + StopTrackingDragGesture(); 1.554 + sNormalLMouseEventInProcess = false; 1.555 + // then fall through... 1.556 + case WidgetMouseEvent::eRightButton: 1.557 + case WidgetMouseEvent::eMiddleButton: 1.558 + SetClickCount(aPresContext, mouseEvent, aStatus); 1.559 + break; 1.560 + } 1.561 + break; 1.562 + } 1.563 + case NS_POINTER_CANCEL: 1.564 + { 1.565 + GenerateMouseEnterExit(mouseEvent); 1.566 + break; 1.567 + } 1.568 + case NS_MOUSE_EXIT: 1.569 + // If the event is not a top-level window exit, then it's not 1.570 + // really an exit --- we may have traversed widget boundaries but 1.571 + // we're still in our toplevel window. 1.572 + if (mouseEvent->exit != WidgetMouseEvent::eTopLevel) { 1.573 + // Treat it as a synthetic move so we don't generate spurious 1.574 + // "exit" or "move" events. Any necessary "out" or "over" events 1.575 + // will be generated by GenerateMouseEnterExit 1.576 + mouseEvent->message = NS_MOUSE_MOVE; 1.577 + mouseEvent->reason = WidgetMouseEvent::eSynthesized; 1.578 + // then fall through... 1.579 + } else { 1.580 + GenerateMouseEnterExit(mouseEvent); 1.581 + //This is a window level mouse exit event and should stop here 1.582 + aEvent->message = 0; 1.583 + break; 1.584 + } 1.585 + case NS_MOUSE_MOVE: 1.586 + case NS_POINTER_DOWN: 1.587 + case NS_POINTER_MOVE: { 1.588 + // on the Mac, GenerateDragGesture() may not return until the drag 1.589 + // has completed and so |aTargetFrame| may have been deleted (moving 1.590 + // a bookmark, for example). If this is the case, however, we know 1.591 + // that ClearFrameRefs() has been called and it cleared out 1.592 + // |mCurrentTarget|. As a result, we should pass |mCurrentTarget| 1.593 + // into UpdateCursor(). 1.594 + GenerateDragGesture(aPresContext, mouseEvent); 1.595 + UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus); 1.596 + GenerateMouseEnterExit(mouseEvent); 1.597 + // Flush pending layout changes, so that later mouse move events 1.598 + // will go to the right nodes. 1.599 + FlushPendingEvents(aPresContext); 1.600 + break; 1.601 + } 1.602 + case NS_DRAGDROP_GESTURE: 1.603 + if (Prefs::ClickHoldContextMenu()) { 1.604 + // an external drag gesture event came in, not generated internally 1.605 + // by Gecko. Make sure we get rid of the click-hold timer. 1.606 + KillClickHoldTimer(); 1.607 + } 1.608 + break; 1.609 + case NS_DRAGDROP_OVER: 1.610 + // NS_DRAGDROP_DROP is fired before NS_DRAGDROP_DRAGDROP so send 1.611 + // the enter/exit events before NS_DRAGDROP_DROP. 1.612 + GenerateDragDropEnterExit(aPresContext, aEvent->AsDragEvent()); 1.613 + break; 1.614 + 1.615 + case NS_KEY_PRESS: 1.616 + { 1.617 + WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); 1.618 + 1.619 + int32_t modifierMask = 0; 1.620 + if (keyEvent->IsShift()) 1.621 + modifierMask |= NS_MODIFIER_SHIFT; 1.622 + if (keyEvent->IsControl()) 1.623 + modifierMask |= NS_MODIFIER_CONTROL; 1.624 + if (keyEvent->IsAlt()) 1.625 + modifierMask |= NS_MODIFIER_ALT; 1.626 + if (keyEvent->IsMeta()) 1.627 + modifierMask |= NS_MODIFIER_META; 1.628 + if (keyEvent->IsOS()) 1.629 + modifierMask |= NS_MODIFIER_OS; 1.630 + 1.631 + // Prevent keyboard scrolling while an accesskey modifier is in use. 1.632 + if (modifierMask && 1.633 + (modifierMask == Prefs::ChromeAccessModifierMask() || 1.634 + modifierMask == Prefs::ContentAccessModifierMask())) { 1.635 + HandleAccessKey(aPresContext, keyEvent, aStatus, nullptr, 1.636 + eAccessKeyProcessingNormal, modifierMask); 1.637 + } 1.638 + } 1.639 + // then fall through... 1.640 + case NS_KEY_DOWN: 1.641 + case NS_KEY_UP: 1.642 + { 1.643 + nsIContent* content = GetFocusedContent(); 1.644 + if (content) 1.645 + mCurrentTargetContent = content; 1.646 + 1.647 + // NOTE: Don't refer TextComposition::IsComposing() since DOM Level 3 1.648 + // Events defines that KeyboardEvent.isComposing is true when it's 1.649 + // dispatched after compositionstart and compositionend. 1.650 + // TextComposition::IsComposing() is false even before 1.651 + // compositionend if there is no composing string. 1.652 + WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); 1.653 + nsRefPtr<TextComposition> composition = 1.654 + IMEStateManager::GetTextCompositionFor(keyEvent); 1.655 + keyEvent->mIsComposing = !!composition; 1.656 + } 1.657 + break; 1.658 + case NS_WHEEL_WHEEL: 1.659 + case NS_WHEEL_START: 1.660 + case NS_WHEEL_STOP: 1.661 + { 1.662 + NS_ASSERTION(aEvent->mFlags.mIsTrusted, 1.663 + "Untrusted wheel event shouldn't be here"); 1.664 + 1.665 + nsIContent* content = GetFocusedContent(); 1.666 + if (content) { 1.667 + mCurrentTargetContent = content; 1.668 + } 1.669 + 1.670 + if (aEvent->message != NS_WHEEL_WHEEL) { 1.671 + break; 1.672 + } 1.673 + 1.674 + WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent(); 1.675 + WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent); 1.676 + 1.677 + // If we won't dispatch a DOM event for this event, nothing to do anymore. 1.678 + if (!wheelEvent->IsAllowedToDispatchDOMEvent()) { 1.679 + break; 1.680 + } 1.681 + 1.682 + // Init lineOrPageDelta values for line scroll events for some devices 1.683 + // on some platforms which might dispatch wheel events which don't have 1.684 + // lineOrPageDelta values. And also, if delta values are customized by 1.685 + // prefs, this recomputes them. 1.686 + DeltaAccumulator::GetInstance()-> 1.687 + InitLineOrPageDelta(aTargetFrame, this, wheelEvent); 1.688 + } 1.689 + break; 1.690 + case NS_QUERY_SELECTED_TEXT: 1.691 + DoQuerySelectedText(aEvent->AsQueryContentEvent()); 1.692 + break; 1.693 + case NS_QUERY_TEXT_CONTENT: 1.694 + { 1.695 + if (RemoteQueryContentEvent(aEvent)) { 1.696 + break; 1.697 + } 1.698 + ContentEventHandler handler(mPresContext); 1.699 + handler.OnQueryTextContent(aEvent->AsQueryContentEvent()); 1.700 + } 1.701 + break; 1.702 + case NS_QUERY_CARET_RECT: 1.703 + { 1.704 + if (RemoteQueryContentEvent(aEvent)) { 1.705 + break; 1.706 + } 1.707 + ContentEventHandler handler(mPresContext); 1.708 + handler.OnQueryCaretRect(aEvent->AsQueryContentEvent()); 1.709 + } 1.710 + break; 1.711 + case NS_QUERY_TEXT_RECT: 1.712 + { 1.713 + if (RemoteQueryContentEvent(aEvent)) { 1.714 + break; 1.715 + } 1.716 + ContentEventHandler handler(mPresContext); 1.717 + handler.OnQueryTextRect(aEvent->AsQueryContentEvent()); 1.718 + } 1.719 + break; 1.720 + case NS_QUERY_EDITOR_RECT: 1.721 + { 1.722 + // XXX remote event 1.723 + ContentEventHandler handler(mPresContext); 1.724 + handler.OnQueryEditorRect(aEvent->AsQueryContentEvent()); 1.725 + } 1.726 + break; 1.727 + case NS_QUERY_CONTENT_STATE: 1.728 + { 1.729 + // XXX remote event 1.730 + ContentEventHandler handler(mPresContext); 1.731 + handler.OnQueryContentState(aEvent->AsQueryContentEvent()); 1.732 + } 1.733 + break; 1.734 + case NS_QUERY_SELECTION_AS_TRANSFERABLE: 1.735 + { 1.736 + // XXX remote event 1.737 + ContentEventHandler handler(mPresContext); 1.738 + handler.OnQuerySelectionAsTransferable(aEvent->AsQueryContentEvent()); 1.739 + } 1.740 + break; 1.741 + case NS_QUERY_CHARACTER_AT_POINT: 1.742 + { 1.743 + // XXX remote event 1.744 + ContentEventHandler handler(mPresContext); 1.745 + handler.OnQueryCharacterAtPoint(aEvent->AsQueryContentEvent()); 1.746 + } 1.747 + break; 1.748 + case NS_QUERY_DOM_WIDGET_HITTEST: 1.749 + { 1.750 + // XXX remote event 1.751 + ContentEventHandler handler(mPresContext); 1.752 + handler.OnQueryDOMWidgetHittest(aEvent->AsQueryContentEvent()); 1.753 + } 1.754 + break; 1.755 + case NS_SELECTION_SET: 1.756 + { 1.757 + WidgetSelectionEvent* selectionEvent = aEvent->AsSelectionEvent(); 1.758 + if (IsTargetCrossProcess(selectionEvent)) { 1.759 + // Will not be handled locally, remote the event 1.760 + if (GetCrossProcessTarget()->SendSelectionEvent(*selectionEvent)) { 1.761 + selectionEvent->mSucceeded = true; 1.762 + } 1.763 + break; 1.764 + } 1.765 + ContentEventHandler handler(mPresContext); 1.766 + handler.OnSelectionEvent(selectionEvent); 1.767 + } 1.768 + break; 1.769 + case NS_CONTENT_COMMAND_CUT: 1.770 + case NS_CONTENT_COMMAND_COPY: 1.771 + case NS_CONTENT_COMMAND_PASTE: 1.772 + case NS_CONTENT_COMMAND_DELETE: 1.773 + case NS_CONTENT_COMMAND_UNDO: 1.774 + case NS_CONTENT_COMMAND_REDO: 1.775 + case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE: 1.776 + { 1.777 + DoContentCommandEvent(aEvent->AsContentCommandEvent()); 1.778 + } 1.779 + break; 1.780 + case NS_CONTENT_COMMAND_SCROLL: 1.781 + { 1.782 + DoContentCommandScrollEvent(aEvent->AsContentCommandEvent()); 1.783 + } 1.784 + break; 1.785 + case NS_TEXT_TEXT: 1.786 + { 1.787 + WidgetTextEvent *textEvent = aEvent->AsTextEvent(); 1.788 + if (IsTargetCrossProcess(textEvent)) { 1.789 + // Will not be handled locally, remote the event 1.790 + if (GetCrossProcessTarget()->SendTextEvent(*textEvent)) { 1.791 + // Cancel local dispatching 1.792 + aEvent->mFlags.mPropagationStopped = true; 1.793 + } 1.794 + } 1.795 + } 1.796 + break; 1.797 + case NS_COMPOSITION_START: 1.798 + if (aEvent->mFlags.mIsTrusted) { 1.799 + // If the event is trusted event, set the selected text to data of 1.800 + // composition event. 1.801 + WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent(); 1.802 + WidgetQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT, 1.803 + compositionEvent->widget); 1.804 + DoQuerySelectedText(&selectedText); 1.805 + NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text"); 1.806 + compositionEvent->data = selectedText.mReply.mString; 1.807 + } 1.808 + // through to compositionend handling 1.809 + case NS_COMPOSITION_UPDATE: 1.810 + case NS_COMPOSITION_END: 1.811 + { 1.812 + WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent(); 1.813 + if (IsTargetCrossProcess(compositionEvent)) { 1.814 + // Will not be handled locally, remote the event 1.815 + if (GetCrossProcessTarget()->SendCompositionEvent(*compositionEvent)) { 1.816 + // Cancel local dispatching 1.817 + aEvent->mFlags.mPropagationStopped = true; 1.818 + } 1.819 + } 1.820 + } 1.821 + break; 1.822 + } 1.823 + return NS_OK; 1.824 +} 1.825 + 1.826 +// static 1.827 +int32_t 1.828 +EventStateManager::GetAccessModifierMaskFor(nsISupports* aDocShell) 1.829 +{ 1.830 + nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell)); 1.831 + if (!treeItem) 1.832 + return -1; // invalid modifier 1.833 + 1.834 + switch (treeItem->ItemType()) { 1.835 + case nsIDocShellTreeItem::typeChrome: 1.836 + return Prefs::ChromeAccessModifierMask(); 1.837 + 1.838 + case nsIDocShellTreeItem::typeContent: 1.839 + return Prefs::ContentAccessModifierMask(); 1.840 + 1.841 + default: 1.842 + return -1; // invalid modifier 1.843 + } 1.844 +} 1.845 + 1.846 +static bool 1.847 +IsAccessKeyTarget(nsIContent* aContent, nsIFrame* aFrame, nsAString& aKey) 1.848 +{ 1.849 + // Use GetAttr because we want Unicode case=insensitive matching 1.850 + // XXXbz shouldn't this be case-sensitive, per spec? 1.851 + nsString contentKey; 1.852 + if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, contentKey) || 1.853 + !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator())) 1.854 + return false; 1.855 + 1.856 + nsCOMPtr<nsIDOMXULDocument> xulDoc = 1.857 + do_QueryInterface(aContent->OwnerDoc()); 1.858 + if (!xulDoc && !aContent->IsXUL()) 1.859 + return true; 1.860 + 1.861 + // For XUL we do visibility checks. 1.862 + if (!aFrame) 1.863 + return false; 1.864 + 1.865 + if (aFrame->IsFocusable()) 1.866 + return true; 1.867 + 1.868 + if (!aFrame->IsVisibleConsideringAncestors()) 1.869 + return false; 1.870 + 1.871 + // XUL controls can be activated. 1.872 + nsCOMPtr<nsIDOMXULControlElement> control(do_QueryInterface(aContent)); 1.873 + if (control) 1.874 + return true; 1.875 + 1.876 + if (aContent->IsHTML()) { 1.877 + nsIAtom* tag = aContent->Tag(); 1.878 + 1.879 + // HTML area, label and legend elements are never focusable, so 1.880 + // we need to check for them explicitly before giving up. 1.881 + if (tag == nsGkAtoms::area || 1.882 + tag == nsGkAtoms::label || 1.883 + tag == nsGkAtoms::legend) 1.884 + return true; 1.885 + 1.886 + } else if (aContent->IsXUL()) { 1.887 + // XUL label elements are never focusable, so we need to check for them 1.888 + // explicitly before giving up. 1.889 + if (aContent->Tag() == nsGkAtoms::label) 1.890 + return true; 1.891 + } 1.892 + 1.893 + return false; 1.894 +} 1.895 + 1.896 +bool 1.897 +EventStateManager::ExecuteAccessKey(nsTArray<uint32_t>& aAccessCharCodes, 1.898 + bool aIsTrustedEvent) 1.899 +{ 1.900 + int32_t count, start = -1; 1.901 + nsIContent* focusedContent = GetFocusedContent(); 1.902 + if (focusedContent) { 1.903 + start = mAccessKeys.IndexOf(focusedContent); 1.904 + if (start == -1 && focusedContent->GetBindingParent()) 1.905 + start = mAccessKeys.IndexOf(focusedContent->GetBindingParent()); 1.906 + } 1.907 + nsIContent *content; 1.908 + nsIFrame *frame; 1.909 + int32_t length = mAccessKeys.Count(); 1.910 + for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) { 1.911 + uint32_t ch = aAccessCharCodes[i]; 1.912 + nsAutoString accessKey; 1.913 + AppendUCS4ToUTF16(ch, accessKey); 1.914 + for (count = 1; count <= length; ++count) { 1.915 + content = mAccessKeys[(start + count) % length]; 1.916 + frame = content->GetPrimaryFrame(); 1.917 + if (IsAccessKeyTarget(content, frame, accessKey)) { 1.918 + bool shouldActivate = Prefs::KeyCausesActivation(); 1.919 + while (shouldActivate && ++count <= length) { 1.920 + nsIContent *oc = mAccessKeys[(start + count) % length]; 1.921 + nsIFrame *of = oc->GetPrimaryFrame(); 1.922 + if (IsAccessKeyTarget(oc, of, accessKey)) 1.923 + shouldActivate = false; 1.924 + } 1.925 + if (shouldActivate) 1.926 + content->PerformAccesskey(shouldActivate, aIsTrustedEvent); 1.927 + else { 1.928 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.929 + if (fm) { 1.930 + nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content); 1.931 + fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY); 1.932 + } 1.933 + } 1.934 + return true; 1.935 + } 1.936 + } 1.937 + } 1.938 + return false; 1.939 +} 1.940 + 1.941 +bool 1.942 +EventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix) 1.943 +{ 1.944 + aPrefix.Truncate(); 1.945 + nsAutoString separator, modifierText; 1.946 + nsContentUtils::GetModifierSeparatorText(separator); 1.947 + 1.948 + nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak(); 1.949 + int32_t modifierMask = GetAccessModifierMaskFor(container); 1.950 + 1.951 + if (modifierMask & NS_MODIFIER_CONTROL) { 1.952 + nsContentUtils::GetControlText(modifierText); 1.953 + aPrefix.Append(modifierText + separator); 1.954 + } 1.955 + if (modifierMask & NS_MODIFIER_META) { 1.956 + nsContentUtils::GetMetaText(modifierText); 1.957 + aPrefix.Append(modifierText + separator); 1.958 + } 1.959 + if (modifierMask & NS_MODIFIER_OS) { 1.960 + nsContentUtils::GetOSText(modifierText); 1.961 + aPrefix.Append(modifierText + separator); 1.962 + } 1.963 + if (modifierMask & NS_MODIFIER_ALT) { 1.964 + nsContentUtils::GetAltText(modifierText); 1.965 + aPrefix.Append(modifierText + separator); 1.966 + } 1.967 + if (modifierMask & NS_MODIFIER_SHIFT) { 1.968 + nsContentUtils::GetShiftText(modifierText); 1.969 + aPrefix.Append(modifierText + separator); 1.970 + } 1.971 + return !aPrefix.IsEmpty(); 1.972 +} 1.973 + 1.974 +void 1.975 +EventStateManager::HandleAccessKey(nsPresContext* aPresContext, 1.976 + WidgetKeyboardEvent* aEvent, 1.977 + nsEventStatus* aStatus, 1.978 + nsIDocShellTreeItem* aBubbledFrom, 1.979 + ProcessingAccessKeyState aAccessKeyState, 1.980 + int32_t aModifierMask) 1.981 +{ 1.982 + nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell(); 1.983 + 1.984 + // Alt or other accesskey modifier is down, we may need to do an accesskey 1.985 + if (mAccessKeys.Count() > 0 && 1.986 + aModifierMask == GetAccessModifierMaskFor(docShell)) { 1.987 + // Someone registered an accesskey. Find and activate it. 1.988 + nsAutoTArray<uint32_t, 10> accessCharCodes; 1.989 + nsContentUtils::GetAccessKeyCandidates(aEvent, accessCharCodes); 1.990 + if (ExecuteAccessKey(accessCharCodes, aEvent->mFlags.mIsTrusted)) { 1.991 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.992 + return; 1.993 + } 1.994 + } 1.995 + 1.996 + // after the local accesskey handling 1.997 + if (nsEventStatus_eConsumeNoDefault != *aStatus) { 1.998 + // checking all sub docshells 1.999 + 1.1000 + if (!docShell) { 1.1001 + NS_WARNING("no docShellTreeNode for presContext"); 1.1002 + return; 1.1003 + } 1.1004 + 1.1005 + int32_t childCount; 1.1006 + docShell->GetChildCount(&childCount); 1.1007 + for (int32_t counter = 0; counter < childCount; counter++) { 1.1008 + // Not processing the child which bubbles up the handling 1.1009 + nsCOMPtr<nsIDocShellTreeItem> subShellItem; 1.1010 + docShell->GetChildAt(counter, getter_AddRefs(subShellItem)); 1.1011 + if (aAccessKeyState == eAccessKeyProcessingUp && 1.1012 + subShellItem == aBubbledFrom) 1.1013 + continue; 1.1014 + 1.1015 + nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem); 1.1016 + if (subDS && IsShellVisible(subDS)) { 1.1017 + nsCOMPtr<nsIPresShell> subPS = subDS->GetPresShell(); 1.1018 + 1.1019 + // Docshells need not have a presshell (eg. display:none 1.1020 + // iframes, docshells in transition between documents, etc). 1.1021 + if (!subPS) { 1.1022 + // Oh, well. Just move on to the next child 1.1023 + continue; 1.1024 + } 1.1025 + 1.1026 + nsPresContext *subPC = subPS->GetPresContext(); 1.1027 + 1.1028 + EventStateManager* esm = 1.1029 + static_cast<EventStateManager*>(subPC->EventStateManager()); 1.1030 + 1.1031 + if (esm) 1.1032 + esm->HandleAccessKey(subPC, aEvent, aStatus, nullptr, 1.1033 + eAccessKeyProcessingDown, aModifierMask); 1.1034 + 1.1035 + if (nsEventStatus_eConsumeNoDefault == *aStatus) 1.1036 + break; 1.1037 + } 1.1038 + } 1.1039 + }// if end . checking all sub docshell ends here. 1.1040 + 1.1041 + // bubble up the process to the parent docshell if necessary 1.1042 + if (eAccessKeyProcessingDown != aAccessKeyState && nsEventStatus_eConsumeNoDefault != *aStatus) { 1.1043 + if (!docShell) { 1.1044 + NS_WARNING("no docShellTreeItem for presContext"); 1.1045 + return; 1.1046 + } 1.1047 + 1.1048 + nsCOMPtr<nsIDocShellTreeItem> parentShellItem; 1.1049 + docShell->GetParent(getter_AddRefs(parentShellItem)); 1.1050 + nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem); 1.1051 + if (parentDS) { 1.1052 + nsCOMPtr<nsIPresShell> parentPS = parentDS->GetPresShell(); 1.1053 + NS_ASSERTION(parentPS, "Our PresShell exists but the parent's does not?"); 1.1054 + 1.1055 + nsPresContext *parentPC = parentPS->GetPresContext(); 1.1056 + NS_ASSERTION(parentPC, "PresShell without PresContext"); 1.1057 + 1.1058 + EventStateManager* esm = 1.1059 + static_cast<EventStateManager*>(parentPC->EventStateManager()); 1.1060 + 1.1061 + if (esm) 1.1062 + esm->HandleAccessKey(parentPC, aEvent, aStatus, docShell, 1.1063 + eAccessKeyProcessingUp, aModifierMask); 1.1064 + } 1.1065 + }// if end. bubble up process 1.1066 +}// end of HandleAccessKey 1.1067 + 1.1068 +bool 1.1069 +EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent, 1.1070 + nsFrameLoader* aFrameLoader, 1.1071 + nsEventStatus *aStatus) { 1.1072 + PBrowserParent* remoteBrowser = aFrameLoader->GetRemoteBrowser(); 1.1073 + TabParent* remote = static_cast<TabParent*>(remoteBrowser); 1.1074 + if (!remote) { 1.1075 + return false; 1.1076 + } 1.1077 + 1.1078 + switch (aEvent->eventStructType) { 1.1079 + case NS_MOUSE_EVENT: { 1.1080 + return remote->SendRealMouseEvent(*aEvent->AsMouseEvent()); 1.1081 + } 1.1082 + case NS_KEY_EVENT: { 1.1083 + return remote->SendRealKeyEvent(*aEvent->AsKeyboardEvent()); 1.1084 + } 1.1085 + case NS_WHEEL_EVENT: { 1.1086 + return remote->SendMouseWheelEvent(*aEvent->AsWheelEvent()); 1.1087 + } 1.1088 + case NS_TOUCH_EVENT: { 1.1089 + // Let the child process synthesize a mouse event if needed, and 1.1090 + // ensure we don't synthesize one in this process. 1.1091 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.1092 + return remote->SendRealTouchEvent(*aEvent->AsTouchEvent()); 1.1093 + } 1.1094 + default: { 1.1095 + MOZ_CRASH("Attempt to send non-whitelisted event?"); 1.1096 + } 1.1097 + } 1.1098 +} 1.1099 + 1.1100 +bool 1.1101 +EventStateManager::IsRemoteTarget(nsIContent* target) { 1.1102 + if (!target) { 1.1103 + return false; 1.1104 + } 1.1105 + 1.1106 + // <browser/iframe remote=true> from XUL 1.1107 + if ((target->Tag() == nsGkAtoms::browser || 1.1108 + target->Tag() == nsGkAtoms::iframe) && 1.1109 + target->IsXUL() && 1.1110 + target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote, 1.1111 + nsGkAtoms::_true, eIgnoreCase)) { 1.1112 + return true; 1.1113 + } 1.1114 + 1.1115 + // <frame/iframe mozbrowser/mozapp> 1.1116 + nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(target); 1.1117 + if (browserFrame && browserFrame->GetReallyIsBrowserOrApp()) { 1.1118 + return !!TabParent::GetFrom(target); 1.1119 + } 1.1120 + 1.1121 + return false; 1.1122 +} 1.1123 + 1.1124 +/*static*/ LayoutDeviceIntPoint 1.1125 +EventStateManager::GetChildProcessOffset(nsFrameLoader* aFrameLoader, 1.1126 + const WidgetEvent& aEvent) 1.1127 +{ 1.1128 + // The "toplevel widget" in child processes is always at position 1.1129 + // 0,0. Map the event coordinates to match that. 1.1130 + nsIFrame* targetFrame = aFrameLoader->GetPrimaryFrameOfOwningContent(); 1.1131 + if (!targetFrame) { 1.1132 + return LayoutDeviceIntPoint(); 1.1133 + } 1.1134 + nsPresContext* presContext = targetFrame->PresContext(); 1.1135 + 1.1136 + // Find out how far we're offset from the nearest widget. 1.1137 + nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(&aEvent, 1.1138 + targetFrame); 1.1139 + return LayoutDeviceIntPoint::FromAppUnitsToNearest(pt, presContext->AppUnitsPerDevPixel()); 1.1140 +} 1.1141 + 1.1142 +bool 1.1143 +CrossProcessSafeEvent(const WidgetEvent& aEvent) 1.1144 +{ 1.1145 + switch (aEvent.eventStructType) { 1.1146 + case NS_KEY_EVENT: 1.1147 + case NS_WHEEL_EVENT: 1.1148 + return true; 1.1149 + case NS_MOUSE_EVENT: 1.1150 + switch (aEvent.message) { 1.1151 + case NS_MOUSE_BUTTON_DOWN: 1.1152 + case NS_MOUSE_BUTTON_UP: 1.1153 + case NS_MOUSE_MOVE: 1.1154 + case NS_CONTEXTMENU: 1.1155 + return true; 1.1156 + default: 1.1157 + return false; 1.1158 + } 1.1159 + case NS_TOUCH_EVENT: 1.1160 + switch (aEvent.message) { 1.1161 + case NS_TOUCH_START: 1.1162 + case NS_TOUCH_MOVE: 1.1163 + case NS_TOUCH_END: 1.1164 + case NS_TOUCH_CANCEL: 1.1165 + return true; 1.1166 + default: 1.1167 + return false; 1.1168 + } 1.1169 + default: 1.1170 + return false; 1.1171 + } 1.1172 +} 1.1173 + 1.1174 +bool 1.1175 +EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent, 1.1176 + nsIFrame* aTargetFrame, 1.1177 + nsEventStatus *aStatus) { 1.1178 + if (*aStatus == nsEventStatus_eConsumeNoDefault || 1.1179 + aEvent->mFlags.mNoCrossProcessBoundaryForwarding || 1.1180 + !CrossProcessSafeEvent(*aEvent)) { 1.1181 + return false; 1.1182 + } 1.1183 + 1.1184 + // Collect the remote event targets we're going to forward this 1.1185 + // event to. 1.1186 + // 1.1187 + // NB: the elements of |targets| must be unique, for correctness. 1.1188 + nsAutoTArray<nsCOMPtr<nsIContent>, 1> targets; 1.1189 + if (aEvent->eventStructType != NS_TOUCH_EVENT || 1.1190 + aEvent->message == NS_TOUCH_START) { 1.1191 + // If this event only has one target, and it's remote, add it to 1.1192 + // the array. 1.1193 + nsIFrame* frame = GetEventTarget(); 1.1194 + nsIContent* target = frame ? frame->GetContent() : nullptr; 1.1195 + if (IsRemoteTarget(target)) { 1.1196 + targets.AppendElement(target); 1.1197 + } 1.1198 + } else { 1.1199 + // This is a touch event with possibly multiple touch points. 1.1200 + // Each touch point may have its own target. So iterate through 1.1201 + // all of them and collect the unique set of targets for event 1.1202 + // forwarding. 1.1203 + // 1.1204 + // This loop is similar to the one used in 1.1205 + // PresShell::DispatchTouchEvent(). 1.1206 + const nsTArray< nsRefPtr<Touch> >& touches = 1.1207 + aEvent->AsTouchEvent()->touches; 1.1208 + for (uint32_t i = 0; i < touches.Length(); ++i) { 1.1209 + Touch* touch = touches[i]; 1.1210 + // NB: the |mChanged| check is an optimization, subprocesses can 1.1211 + // compute this for themselves. If the touch hasn't changed, we 1.1212 + // may be able to avoid forwarding the event entirely (which is 1.1213 + // not free). 1.1214 + if (!touch || !touch->mChanged) { 1.1215 + continue; 1.1216 + } 1.1217 + nsCOMPtr<EventTarget> targetPtr = touch->mTarget; 1.1218 + if (!targetPtr) { 1.1219 + continue; 1.1220 + } 1.1221 + nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr); 1.1222 + if (IsRemoteTarget(target) && !targets.Contains(target)) { 1.1223 + targets.AppendElement(target); 1.1224 + } 1.1225 + } 1.1226 + } 1.1227 + 1.1228 + if (targets.Length() == 0) { 1.1229 + return false; 1.1230 + } 1.1231 + 1.1232 + // Look up the frame loader for all the remote targets we found, and 1.1233 + // then dispatch the event to the remote content they represent. 1.1234 + bool dispatched = false; 1.1235 + for (uint32_t i = 0; i < targets.Length(); ++i) { 1.1236 + nsIContent* target = targets[i]; 1.1237 + nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(target); 1.1238 + if (!loaderOwner) { 1.1239 + continue; 1.1240 + } 1.1241 + 1.1242 + nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader(); 1.1243 + if (!frameLoader) { 1.1244 + continue; 1.1245 + } 1.1246 + 1.1247 + uint32_t eventMode; 1.1248 + frameLoader->GetEventMode(&eventMode); 1.1249 + if (eventMode == nsIFrameLoader::EVENT_MODE_DONT_FORWARD_TO_CHILD) { 1.1250 + continue; 1.1251 + } 1.1252 + 1.1253 + dispatched |= DispatchCrossProcessEvent(aEvent, frameLoader, aStatus); 1.1254 + } 1.1255 + return dispatched; 1.1256 +} 1.1257 + 1.1258 +// 1.1259 +// CreateClickHoldTimer 1.1260 +// 1.1261 +// Fire off a timer for determining if the user wants click-hold. This timer 1.1262 +// is a one-shot that will be cancelled when the user moves enough to fire 1.1263 +// a drag. 1.1264 +// 1.1265 +void 1.1266 +EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext, 1.1267 + nsIFrame* inDownFrame, 1.1268 + WidgetGUIEvent* inMouseDownEvent) 1.1269 +{ 1.1270 + if (!inMouseDownEvent->mFlags.mIsTrusted || IsRemoteTarget(mGestureDownContent)) 1.1271 + return; 1.1272 + 1.1273 + // just to be anal (er, safe) 1.1274 + if (mClickHoldTimer) { 1.1275 + mClickHoldTimer->Cancel(); 1.1276 + mClickHoldTimer = nullptr; 1.1277 + } 1.1278 + 1.1279 + // if content clicked on has a popup, don't even start the timer 1.1280 + // since we'll end up conflicting and both will show. 1.1281 + if (mGestureDownContent) { 1.1282 + // check for the |popup| attribute 1.1283 + if (nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None, 1.1284 + nsGkAtoms::popup)) 1.1285 + return; 1.1286 + 1.1287 + // check for a <menubutton> like bookmarks 1.1288 + if (mGestureDownContent->Tag() == nsGkAtoms::menubutton) 1.1289 + return; 1.1290 + } 1.1291 + 1.1292 + mClickHoldTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.1293 + if (mClickHoldTimer) { 1.1294 + int32_t clickHoldDelay = 1.1295 + Preferences::GetInt("ui.click_hold_context_menus.delay", 500); 1.1296 + mClickHoldTimer->InitWithFuncCallback(sClickHoldCallback, this, 1.1297 + clickHoldDelay, 1.1298 + nsITimer::TYPE_ONE_SHOT); 1.1299 + } 1.1300 +} // CreateClickHoldTimer 1.1301 + 1.1302 + 1.1303 +// 1.1304 +// KillClickHoldTimer 1.1305 +// 1.1306 +// Stop the timer that would show the context menu dead in its tracks 1.1307 +// 1.1308 +void 1.1309 +EventStateManager::KillClickHoldTimer() 1.1310 +{ 1.1311 + if (mClickHoldTimer) { 1.1312 + mClickHoldTimer->Cancel(); 1.1313 + mClickHoldTimer = nullptr; 1.1314 + } 1.1315 +} 1.1316 + 1.1317 + 1.1318 +// 1.1319 +// sClickHoldCallback 1.1320 +// 1.1321 +// This fires after the mouse has been down for a certain length of time. 1.1322 +// 1.1323 +void 1.1324 +EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM) 1.1325 +{ 1.1326 + nsRefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM); 1.1327 + if (self) { 1.1328 + self->FireContextClick(); 1.1329 + } 1.1330 + 1.1331 + // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup(); 1.1332 + 1.1333 +} // sAutoHideCallback 1.1334 + 1.1335 + 1.1336 +// 1.1337 +// FireContextClick 1.1338 +// 1.1339 +// If we're this far, our timer has fired, which means the mouse has been down 1.1340 +// for a certain period of time and has not moved enough to generate a dragGesture. 1.1341 +// We can be certain the user wants a context-click at this stage, so generate 1.1342 +// a dom event and fire it in. 1.1343 +// 1.1344 +// After the event fires, check if PreventDefault() has been set on the event which 1.1345 +// means that someone either ate the event or put up a context menu. This is our cue 1.1346 +// to stop tracking the drag gesture. If we always did this, draggable items w/out 1.1347 +// a context menu wouldn't be draggable after a certain length of time, which is 1.1348 +// _not_ what we want. 1.1349 +// 1.1350 +void 1.1351 +EventStateManager::FireContextClick() 1.1352 +{ 1.1353 + if (!mGestureDownContent || !mPresContext) { 1.1354 + return; 1.1355 + } 1.1356 + 1.1357 +#ifdef XP_MACOSX 1.1358 + // Hack to ensure that we don't show a context menu when the user 1.1359 + // let go of the mouse after a long cpu-hogging operation prevented 1.1360 + // us from handling any OS events. See bug 117589. 1.1361 + if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft)) 1.1362 + return; 1.1363 +#endif 1.1364 + 1.1365 + nsEventStatus status = nsEventStatus_eIgnore; 1.1366 + 1.1367 + // Dispatch to the DOM. We have to fake out the ESM and tell it that the 1.1368 + // current target frame is actually where the mouseDown occurred, otherwise it 1.1369 + // will use the frame the mouse is currently over which may or may not be 1.1370 + // the same. (Note: saari and I have decided that we don't have to reset |mCurrentTarget| 1.1371 + // when we're through because no one else is doing anything more with this 1.1372 + // event and it will get reset on the very next event to the correct frame). 1.1373 + mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent); 1.1374 + // make sure the widget sticks around 1.1375 + nsCOMPtr<nsIWidget> targetWidget; 1.1376 + if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) { 1.1377 + NS_ASSERTION(mPresContext == mCurrentTarget->PresContext(), 1.1378 + "a prescontext returned a primary frame that didn't belong to it?"); 1.1379 + 1.1380 + // before dispatching, check that we're not on something that 1.1381 + // doesn't get a context menu 1.1382 + nsIAtom *tag = mGestureDownContent->Tag(); 1.1383 + bool allowedToDispatch = true; 1.1384 + 1.1385 + if (mGestureDownContent->IsXUL()) { 1.1386 + if (tag == nsGkAtoms::scrollbar || 1.1387 + tag == nsGkAtoms::scrollbarbutton || 1.1388 + tag == nsGkAtoms::button) 1.1389 + allowedToDispatch = false; 1.1390 + else if (tag == nsGkAtoms::toolbarbutton) { 1.1391 + // a <toolbarbutton> that has the container attribute set 1.1392 + // will already have its own dropdown. 1.1393 + if (nsContentUtils::HasNonEmptyAttr(mGestureDownContent, 1.1394 + kNameSpaceID_None, nsGkAtoms::container)) { 1.1395 + allowedToDispatch = false; 1.1396 + } else { 1.1397 + // If the toolbar button has an open menu, don't attempt to open 1.1398 + // a second menu 1.1399 + if (mGestureDownContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open, 1.1400 + nsGkAtoms::_true, eCaseMatters)) { 1.1401 + allowedToDispatch = false; 1.1402 + } 1.1403 + } 1.1404 + } 1.1405 + } 1.1406 + else if (mGestureDownContent->IsHTML()) { 1.1407 + nsCOMPtr<nsIFormControl> formCtrl(do_QueryInterface(mGestureDownContent)); 1.1408 + 1.1409 + if (formCtrl) { 1.1410 + allowedToDispatch = formCtrl->IsTextControl(false) || 1.1411 + formCtrl->GetType() == NS_FORM_INPUT_FILE; 1.1412 + } 1.1413 + else if (tag == nsGkAtoms::applet || 1.1414 + tag == nsGkAtoms::embed || 1.1415 + tag == nsGkAtoms::object) { 1.1416 + allowedToDispatch = false; 1.1417 + } 1.1418 + } 1.1419 + 1.1420 + if (allowedToDispatch) { 1.1421 + // init the event while mCurrentTarget is still good 1.1422 + WidgetMouseEvent event(true, NS_CONTEXTMENU, targetWidget, 1.1423 + WidgetMouseEvent::eReal); 1.1424 + event.clickCount = 1; 1.1425 + FillInEventFromGestureDown(&event); 1.1426 + 1.1427 + // stop selection tracking, we're in control now 1.1428 + if (mCurrentTarget) 1.1429 + { 1.1430 + nsRefPtr<nsFrameSelection> frameSel = 1.1431 + mCurrentTarget->GetFrameSelection(); 1.1432 + 1.1433 + if (frameSel && frameSel->GetMouseDownState()) { 1.1434 + // note that this can cause selection changed events to fire if we're in 1.1435 + // a text field, which will null out mCurrentTarget 1.1436 + frameSel->SetMouseDownState(false); 1.1437 + } 1.1438 + } 1.1439 + 1.1440 + nsIDocument* doc = mGestureDownContent->GetCurrentDoc(); 1.1441 + AutoHandlingUserInputStatePusher userInpStatePusher(true, &event, doc); 1.1442 + 1.1443 + // dispatch to DOM 1.1444 + EventDispatcher::Dispatch(mGestureDownContent, mPresContext, &event, 1.1445 + nullptr, &status); 1.1446 + 1.1447 + // We don't need to dispatch to frame handling because no frames 1.1448 + // watch NS_CONTEXTMENU except for nsMenuFrame and that's only for 1.1449 + // dismissal. That's just as well since we don't really know 1.1450 + // which frame to send it to. 1.1451 + } 1.1452 + } 1.1453 + 1.1454 + // now check if the event has been handled. If so, stop tracking a drag 1.1455 + if (status == nsEventStatus_eConsumeNoDefault) { 1.1456 + StopTrackingDragGesture(); 1.1457 + } 1.1458 + 1.1459 + KillClickHoldTimer(); 1.1460 + 1.1461 +} // FireContextClick 1.1462 + 1.1463 + 1.1464 +// 1.1465 +// BeginTrackingDragGesture 1.1466 +// 1.1467 +// Record that the mouse has gone down and that we should move to TRACKING state 1.1468 +// of d&d gesture tracker. 1.1469 +// 1.1470 +// We also use this to track click-hold context menus. When the mouse goes down, 1.1471 +// fire off a short timer. If the timer goes off and we have yet to fire the 1.1472 +// drag gesture (ie, the mouse hasn't moved a certain distance), then we can 1.1473 +// assume the user wants a click-hold, so fire a context-click event. We only 1.1474 +// want to cancel the drag gesture if the context-click event is handled. 1.1475 +// 1.1476 +void 1.1477 +EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext, 1.1478 + WidgetMouseEvent* inDownEvent, 1.1479 + nsIFrame* inDownFrame) 1.1480 +{ 1.1481 + if (!inDownEvent->widget) 1.1482 + return; 1.1483 + 1.1484 + // Note that |inDownEvent| could be either a mouse down event or a 1.1485 + // synthesized mouse move event. 1.1486 + mGestureDownPoint = inDownEvent->refPoint + 1.1487 + LayoutDeviceIntPoint::FromUntyped(inDownEvent->widget->WidgetToScreenOffset()); 1.1488 + 1.1489 + inDownFrame->GetContentForEvent(inDownEvent, 1.1490 + getter_AddRefs(mGestureDownContent)); 1.1491 + 1.1492 + mGestureDownFrameOwner = inDownFrame->GetContent(); 1.1493 + mGestureModifiers = inDownEvent->modifiers; 1.1494 + mGestureDownButtons = inDownEvent->buttons; 1.1495 + 1.1496 + if (Prefs::ClickHoldContextMenu()) { 1.1497 + // fire off a timer to track click-hold 1.1498 + CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent); 1.1499 + } 1.1500 +} 1.1501 + 1.1502 + 1.1503 +// 1.1504 +// StopTrackingDragGesture 1.1505 +// 1.1506 +// Record that the mouse has gone back up so that we should leave the TRACKING 1.1507 +// state of d&d gesture tracker and return to the START state. 1.1508 +// 1.1509 +void 1.1510 +EventStateManager::StopTrackingDragGesture() 1.1511 +{ 1.1512 + mGestureDownContent = nullptr; 1.1513 + mGestureDownFrameOwner = nullptr; 1.1514 +} 1.1515 + 1.1516 +void 1.1517 +EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent) 1.1518 +{ 1.1519 + NS_ASSERTION(aEvent->widget == mCurrentTarget->GetNearestWidget(), 1.1520 + "Incorrect widget in event"); 1.1521 + 1.1522 + // Set the coordinates in the new event to the coordinates of 1.1523 + // the old event, adjusted for the fact that the widget might be 1.1524 + // different 1.1525 + aEvent->refPoint = mGestureDownPoint - 1.1526 + LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset()); 1.1527 + aEvent->modifiers = mGestureModifiers; 1.1528 + aEvent->buttons = mGestureDownButtons; 1.1529 +} 1.1530 + 1.1531 +// 1.1532 +// GenerateDragGesture 1.1533 +// 1.1534 +// If we're in the TRACKING state of the d&d gesture tracker, check the current position 1.1535 +// of the mouse in relation to the old one. If we've moved a sufficient amount from 1.1536 +// the mouse down, then fire off a drag gesture event. 1.1537 +void 1.1538 +EventStateManager::GenerateDragGesture(nsPresContext* aPresContext, 1.1539 + WidgetMouseEvent* aEvent) 1.1540 +{ 1.1541 + NS_ASSERTION(aPresContext, "This shouldn't happen."); 1.1542 + if (IsTrackingDragGesture()) { 1.1543 + mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame(); 1.1544 + 1.1545 + if (!mCurrentTarget) { 1.1546 + StopTrackingDragGesture(); 1.1547 + return; 1.1548 + } 1.1549 + 1.1550 + // Check if selection is tracking drag gestures, if so 1.1551 + // don't interfere! 1.1552 + if (mCurrentTarget) 1.1553 + { 1.1554 + nsRefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection(); 1.1555 + if (frameSel && frameSel->GetMouseDownState()) { 1.1556 + StopTrackingDragGesture(); 1.1557 + return; 1.1558 + } 1.1559 + } 1.1560 + 1.1561 + // If non-native code is capturing the mouse don't start a drag. 1.1562 + if (nsIPresShell::IsMouseCapturePreventingDrag()) { 1.1563 + StopTrackingDragGesture(); 1.1564 + return; 1.1565 + } 1.1566 + 1.1567 + static int32_t pixelThresholdX = 0; 1.1568 + static int32_t pixelThresholdY = 0; 1.1569 + 1.1570 + if (!pixelThresholdX) { 1.1571 + pixelThresholdX = 1.1572 + LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdX, 0); 1.1573 + pixelThresholdY = 1.1574 + LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 0); 1.1575 + if (!pixelThresholdX) 1.1576 + pixelThresholdX = 5; 1.1577 + if (!pixelThresholdY) 1.1578 + pixelThresholdY = 5; 1.1579 + } 1.1580 + 1.1581 + // fire drag gesture if mouse has moved enough 1.1582 + LayoutDeviceIntPoint pt = aEvent->refPoint + 1.1583 + LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset()); 1.1584 + if (DeprecatedAbs(pt.x - mGestureDownPoint.x) > pixelThresholdX || 1.1585 + DeprecatedAbs(pt.y - mGestureDownPoint.y) > pixelThresholdY) { 1.1586 + if (Prefs::ClickHoldContextMenu()) { 1.1587 + // stop the click-hold before we fire off the drag gesture, in case 1.1588 + // it takes a long time 1.1589 + KillClickHoldTimer(); 1.1590 + } 1.1591 + 1.1592 + nsCOMPtr<nsISupports> container = aPresContext->GetContainerWeak(); 1.1593 + nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container); 1.1594 + if (!window) 1.1595 + return; 1.1596 + 1.1597 + nsRefPtr<DataTransfer> dataTransfer = 1.1598 + new DataTransfer(window, NS_DRAGDROP_START, false, -1); 1.1599 + 1.1600 + nsCOMPtr<nsISelection> selection; 1.1601 + nsCOMPtr<nsIContent> eventContent, targetContent; 1.1602 + mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent)); 1.1603 + if (eventContent) 1.1604 + DetermineDragTarget(window, eventContent, dataTransfer, 1.1605 + getter_AddRefs(selection), getter_AddRefs(targetContent)); 1.1606 + 1.1607 + // Stop tracking the drag gesture now. This should stop us from 1.1608 + // reentering GenerateDragGesture inside DOM event processing. 1.1609 + StopTrackingDragGesture(); 1.1610 + 1.1611 + if (!targetContent) 1.1612 + return; 1.1613 + 1.1614 + // Use our targetContent, now that we've determined it, as the 1.1615 + // parent object of the DataTransfer. 1.1616 + dataTransfer->SetParentObject(targetContent); 1.1617 + 1.1618 + sLastDragOverFrame = nullptr; 1.1619 + nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget(); 1.1620 + 1.1621 + // get the widget from the target frame 1.1622 + WidgetDragEvent startEvent(aEvent->mFlags.mIsTrusted, 1.1623 + NS_DRAGDROP_START, widget); 1.1624 + FillInEventFromGestureDown(&startEvent); 1.1625 + 1.1626 + WidgetDragEvent gestureEvent(aEvent->mFlags.mIsTrusted, 1.1627 + NS_DRAGDROP_GESTURE, widget); 1.1628 + FillInEventFromGestureDown(&gestureEvent); 1.1629 + 1.1630 + startEvent.dataTransfer = gestureEvent.dataTransfer = dataTransfer; 1.1631 + startEvent.inputSource = gestureEvent.inputSource = aEvent->inputSource; 1.1632 + 1.1633 + // Dispatch to the DOM. By setting mCurrentTarget we are faking 1.1634 + // out the ESM and telling it that the current target frame is 1.1635 + // actually where the mouseDown occurred, otherwise it will use 1.1636 + // the frame the mouse is currently over which may or may not be 1.1637 + // the same. (Note: saari and I have decided that we don't have 1.1638 + // to reset |mCurrentTarget| when we're through because no one 1.1639 + // else is doing anything more with this event and it will get 1.1640 + // reset on the very next event to the correct frame). 1.1641 + 1.1642 + // Hold onto old target content through the event and reset after. 1.1643 + nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent; 1.1644 + 1.1645 + // Set the current target to the content for the mouse down 1.1646 + mCurrentTargetContent = targetContent; 1.1647 + 1.1648 + // Dispatch both the dragstart and draggesture events to the DOM. For 1.1649 + // elements in an editor, only fire the draggesture event so that the 1.1650 + // editor code can handle it but content doesn't see a dragstart. 1.1651 + nsEventStatus status = nsEventStatus_eIgnore; 1.1652 + EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, 1.1653 + nullptr, &status); 1.1654 + 1.1655 + WidgetDragEvent* event = &startEvent; 1.1656 + if (status != nsEventStatus_eConsumeNoDefault) { 1.1657 + status = nsEventStatus_eIgnore; 1.1658 + EventDispatcher::Dispatch(targetContent, aPresContext, &gestureEvent, 1.1659 + nullptr, &status); 1.1660 + event = &gestureEvent; 1.1661 + } 1.1662 + 1.1663 + nsCOMPtr<nsIObserverService> observerService = 1.1664 + mozilla::services::GetObserverService(); 1.1665 + // Emit observer event to allow addons to modify the DataTransfer object. 1.1666 + if (observerService) { 1.1667 + observerService->NotifyObservers(dataTransfer, 1.1668 + "on-datatransfer-available", 1.1669 + nullptr); 1.1670 + } 1.1671 + 1.1672 + // now that the dataTransfer has been updated in the dragstart and 1.1673 + // draggesture events, make it read only so that the data doesn't 1.1674 + // change during the drag. 1.1675 + dataTransfer->SetReadOnly(); 1.1676 + 1.1677 + if (status != nsEventStatus_eConsumeNoDefault) { 1.1678 + bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer, 1.1679 + targetContent, selection); 1.1680 + if (dragStarted) { 1.1681 + sActiveESM = nullptr; 1.1682 + aEvent->mFlags.mPropagationStopped = true; 1.1683 + } 1.1684 + } 1.1685 + 1.1686 + // Note that frame event handling doesn't care about NS_DRAGDROP_GESTURE, 1.1687 + // which is just as well since we don't really know which frame to 1.1688 + // send it to 1.1689 + 1.1690 + // Reset mCurretTargetContent to what it was 1.1691 + mCurrentTargetContent = targetBeforeEvent; 1.1692 + } 1.1693 + 1.1694 + // Now flush all pending notifications, for better responsiveness 1.1695 + // while dragging. 1.1696 + FlushPendingEvents(aPresContext); 1.1697 + } 1.1698 +} // GenerateDragGesture 1.1699 + 1.1700 +void 1.1701 +EventStateManager::DetermineDragTarget(nsPIDOMWindow* aWindow, 1.1702 + nsIContent* aSelectionTarget, 1.1703 + DataTransfer* aDataTransfer, 1.1704 + nsISelection** aSelection, 1.1705 + nsIContent** aTargetNode) 1.1706 +{ 1.1707 + *aTargetNode = nullptr; 1.1708 + 1.1709 + // GetDragData determines if a selection, link or image in the content 1.1710 + // should be dragged, and places the data associated with the drag in the 1.1711 + // data transfer. 1.1712 + // mGestureDownContent is the node where the mousedown event for the drag 1.1713 + // occurred, and aSelectionTarget is the node to use when a selection is used 1.1714 + bool canDrag; 1.1715 + nsCOMPtr<nsIContent> dragDataNode; 1.1716 + bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0; 1.1717 + nsresult rv = nsContentAreaDragDrop::GetDragData(aWindow, mGestureDownContent, 1.1718 + aSelectionTarget, wasAlt, 1.1719 + aDataTransfer, &canDrag, aSelection, 1.1720 + getter_AddRefs(dragDataNode)); 1.1721 + if (NS_FAILED(rv) || !canDrag) 1.1722 + return; 1.1723 + 1.1724 + // if GetDragData returned a node, use that as the node being dragged. 1.1725 + // Otherwise, if a selection is being dragged, use the node within the 1.1726 + // selection that was dragged. Otherwise, just use the mousedown target. 1.1727 + nsIContent* dragContent = mGestureDownContent; 1.1728 + if (dragDataNode) 1.1729 + dragContent = dragDataNode; 1.1730 + else if (*aSelection) 1.1731 + dragContent = aSelectionTarget; 1.1732 + 1.1733 + nsIContent* originalDragContent = dragContent; 1.1734 + 1.1735 + // If a selection isn't being dragged, look for an ancestor with the 1.1736 + // draggable property set. If one is found, use that as the target of the 1.1737 + // drag instead of the node that was clicked on. If a draggable node wasn't 1.1738 + // found, just use the clicked node. 1.1739 + if (!*aSelection) { 1.1740 + while (dragContent) { 1.1741 + nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(dragContent); 1.1742 + if (htmlElement) { 1.1743 + bool draggable = false; 1.1744 + htmlElement->GetDraggable(&draggable); 1.1745 + if (draggable) 1.1746 + break; 1.1747 + } 1.1748 + else { 1.1749 + nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(dragContent); 1.1750 + if (xulElement) { 1.1751 + // All XUL elements are draggable, so if a XUL element is 1.1752 + // encountered, stop looking for draggable nodes and just use the 1.1753 + // original clicked node instead. 1.1754 + // XXXndeakin 1.1755 + // In the future, we will want to improve this so that XUL has a 1.1756 + // better way to specify whether something is draggable than just 1.1757 + // on/off. 1.1758 + dragContent = mGestureDownContent; 1.1759 + break; 1.1760 + } 1.1761 + // otherwise, it's not an HTML or XUL element, so just keep looking 1.1762 + } 1.1763 + dragContent = dragContent->GetParent(); 1.1764 + } 1.1765 + } 1.1766 + 1.1767 + // if no node in the hierarchy was found to drag, but the GetDragData method 1.1768 + // returned a node, use that returned node. Otherwise, nothing is draggable. 1.1769 + if (!dragContent && dragDataNode) 1.1770 + dragContent = dragDataNode; 1.1771 + 1.1772 + if (dragContent) { 1.1773 + // if an ancestor node was used instead, clear the drag data 1.1774 + // XXXndeakin rework this a bit. Find a way to just not call GetDragData if we don't need to. 1.1775 + if (dragContent != originalDragContent) 1.1776 + aDataTransfer->ClearAll(); 1.1777 + *aTargetNode = dragContent; 1.1778 + NS_ADDREF(*aTargetNode); 1.1779 + } 1.1780 +} 1.1781 + 1.1782 +bool 1.1783 +EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext, 1.1784 + WidgetDragEvent* aDragEvent, 1.1785 + DataTransfer* aDataTransfer, 1.1786 + nsIContent* aDragTarget, 1.1787 + nsISelection* aSelection) 1.1788 +{ 1.1789 + nsCOMPtr<nsIDragService> dragService = 1.1790 + do_GetService("@mozilla.org/widget/dragservice;1"); 1.1791 + if (!dragService) 1.1792 + return false; 1.1793 + 1.1794 + // Default handling for the draggesture/dragstart event. 1.1795 + // 1.1796 + // First, check if a drag session already exists. This means that the drag 1.1797 + // service was called directly within a draggesture handler. In this case, 1.1798 + // don't do anything more, as it is assumed that the handler is managing 1.1799 + // drag and drop manually. Make sure to return true to indicate that a drag 1.1800 + // began. 1.1801 + nsCOMPtr<nsIDragSession> dragSession; 1.1802 + dragService->GetCurrentSession(getter_AddRefs(dragSession)); 1.1803 + if (dragSession) 1.1804 + return true; 1.1805 + 1.1806 + // No drag session is currently active, so check if a handler added 1.1807 + // any items to be dragged. If not, there isn't anything to drag. 1.1808 + uint32_t count = 0; 1.1809 + if (aDataTransfer) 1.1810 + aDataTransfer->GetMozItemCount(&count); 1.1811 + if (!count) 1.1812 + return false; 1.1813 + 1.1814 + // Get the target being dragged, which may not be the same as the 1.1815 + // target of the mouse event. If one wasn't set in the 1.1816 + // aDataTransfer during the event handler, just use the original 1.1817 + // target instead. 1.1818 + nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget(); 1.1819 + if (!dragTarget) { 1.1820 + dragTarget = aDragTarget; 1.1821 + if (!dragTarget) 1.1822 + return false; 1.1823 + } 1.1824 + 1.1825 + // check which drag effect should initially be used. If the effect was not 1.1826 + // set, just use all actions, otherwise Windows won't allow a drop. 1.1827 + uint32_t action; 1.1828 + aDataTransfer->GetEffectAllowedInt(&action); 1.1829 + if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) 1.1830 + action = nsIDragService::DRAGDROP_ACTION_COPY | 1.1831 + nsIDragService::DRAGDROP_ACTION_MOVE | 1.1832 + nsIDragService::DRAGDROP_ACTION_LINK; 1.1833 + 1.1834 + // get any custom drag image that was set 1.1835 + int32_t imageX, imageY; 1.1836 + Element* dragImage = aDataTransfer->GetDragImage(&imageX, &imageY); 1.1837 + 1.1838 + nsCOMPtr<nsISupportsArray> transArray = 1.1839 + aDataTransfer->GetTransferables(dragTarget->AsDOMNode()); 1.1840 + if (!transArray) 1.1841 + return false; 1.1842 + 1.1843 + // XXXndeakin don't really want to create a new drag DOM event 1.1844 + // here, but we need something to pass to the InvokeDragSession 1.1845 + // methods. 1.1846 + nsCOMPtr<nsIDOMEvent> domEvent; 1.1847 + NS_NewDOMDragEvent(getter_AddRefs(domEvent), dragTarget, 1.1848 + aPresContext, aDragEvent); 1.1849 + 1.1850 + nsCOMPtr<nsIDOMDragEvent> domDragEvent = do_QueryInterface(domEvent); 1.1851 + // if creating a drag event failed, starting a drag session will 1.1852 + // just fail. 1.1853 + 1.1854 + // Use InvokeDragSessionWithSelection if a selection is being dragged, 1.1855 + // such that the image can be generated from the selected text. However, 1.1856 + // use InvokeDragSessionWithImage if a custom image was set or something 1.1857 + // other than a selection is being dragged. 1.1858 + if (!dragImage && aSelection) { 1.1859 + dragService->InvokeDragSessionWithSelection(aSelection, transArray, 1.1860 + action, domDragEvent, 1.1861 + aDataTransfer); 1.1862 + } 1.1863 + else { 1.1864 + // if dragging within a XUL tree and no custom drag image was 1.1865 + // set, the region argument to InvokeDragSessionWithImage needs 1.1866 + // to be set to the area encompassing the selected rows of the 1.1867 + // tree to ensure that the drag feedback gets clipped to those 1.1868 + // rows. For other content, region should be null. 1.1869 + nsCOMPtr<nsIScriptableRegion> region; 1.1870 +#ifdef MOZ_XUL 1.1871 + if (dragTarget && !dragImage) { 1.1872 + if (dragTarget->NodeInfo()->Equals(nsGkAtoms::treechildren, 1.1873 + kNameSpaceID_XUL)) { 1.1874 + nsTreeBodyFrame* treeBody = 1.1875 + do_QueryFrame(dragTarget->GetPrimaryFrame()); 1.1876 + if (treeBody) { 1.1877 + treeBody->GetSelectionRegion(getter_AddRefs(region)); 1.1878 + } 1.1879 + } 1.1880 + } 1.1881 +#endif 1.1882 + 1.1883 + dragService->InvokeDragSessionWithImage(dragTarget->AsDOMNode(), transArray, 1.1884 + region, action, 1.1885 + dragImage ? dragImage->AsDOMNode() : 1.1886 + nullptr, 1.1887 + imageX, 1.1888 + imageY, domDragEvent, 1.1889 + aDataTransfer); 1.1890 + } 1.1891 + 1.1892 + return true; 1.1893 +} 1.1894 + 1.1895 +nsresult 1.1896 +EventStateManager::GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv) 1.1897 +{ 1.1898 + *aMv = nullptr; 1.1899 + 1.1900 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.1901 + if(!fm) return NS_ERROR_FAILURE; 1.1902 + 1.1903 + nsCOMPtr<nsIDOMWindow> focusedWindow; 1.1904 + fm->GetFocusedWindow(getter_AddRefs(focusedWindow)); 1.1905 + 1.1906 + nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(focusedWindow); 1.1907 + if(!ourWindow) return NS_ERROR_FAILURE; 1.1908 + 1.1909 + nsIDOMWindow *rootWindow = ourWindow->GetPrivateRoot(); 1.1910 + if(!rootWindow) return NS_ERROR_FAILURE; 1.1911 + 1.1912 + nsCOMPtr<nsIDOMWindow> contentWindow; 1.1913 + rootWindow->GetContent(getter_AddRefs(contentWindow)); 1.1914 + if(!contentWindow) return NS_ERROR_FAILURE; 1.1915 + 1.1916 + nsIDocument *doc = GetDocumentFromWindow(contentWindow); 1.1917 + if(!doc) return NS_ERROR_FAILURE; 1.1918 + 1.1919 + nsIPresShell *presShell = doc->GetShell(); 1.1920 + if(!presShell) return NS_ERROR_FAILURE; 1.1921 + nsPresContext *presContext = presShell->GetPresContext(); 1.1922 + if(!presContext) return NS_ERROR_FAILURE; 1.1923 + 1.1924 + nsCOMPtr<nsIDocShell> docshell(presContext->GetDocShell()); 1.1925 + if(!docshell) return NS_ERROR_FAILURE; 1.1926 + 1.1927 + nsCOMPtr<nsIContentViewer> cv; 1.1928 + docshell->GetContentViewer(getter_AddRefs(cv)); 1.1929 + if(!cv) return NS_ERROR_FAILURE; 1.1930 + 1.1931 + nsCOMPtr<nsIMarkupDocumentViewer> mv(do_QueryInterface(cv)); 1.1932 + if(!mv) return NS_ERROR_FAILURE; 1.1933 + 1.1934 + *aMv = mv; 1.1935 + NS_IF_ADDREF(*aMv); 1.1936 + 1.1937 + return NS_OK; 1.1938 +} 1.1939 + 1.1940 +nsresult 1.1941 +EventStateManager::ChangeTextSize(int32_t change) 1.1942 +{ 1.1943 + nsCOMPtr<nsIMarkupDocumentViewer> mv; 1.1944 + nsresult rv = GetMarkupDocumentViewer(getter_AddRefs(mv)); 1.1945 + NS_ENSURE_SUCCESS(rv, rv); 1.1946 + 1.1947 + float textzoom; 1.1948 + float zoomMin = ((float)Preferences::GetInt("zoom.minPercent", 50)) / 100; 1.1949 + float zoomMax = ((float)Preferences::GetInt("zoom.maxPercent", 300)) / 100; 1.1950 + mv->GetTextZoom(&textzoom); 1.1951 + textzoom += ((float)change) / 10; 1.1952 + if (textzoom < zoomMin) 1.1953 + textzoom = zoomMin; 1.1954 + else if (textzoom > zoomMax) 1.1955 + textzoom = zoomMax; 1.1956 + mv->SetTextZoom(textzoom); 1.1957 + 1.1958 + return NS_OK; 1.1959 +} 1.1960 + 1.1961 +nsresult 1.1962 +EventStateManager::ChangeFullZoom(int32_t change) 1.1963 +{ 1.1964 + nsCOMPtr<nsIMarkupDocumentViewer> mv; 1.1965 + nsresult rv = GetMarkupDocumentViewer(getter_AddRefs(mv)); 1.1966 + NS_ENSURE_SUCCESS(rv, rv); 1.1967 + 1.1968 + float fullzoom; 1.1969 + float zoomMin = ((float)Preferences::GetInt("zoom.minPercent", 50)) / 100; 1.1970 + float zoomMax = ((float)Preferences::GetInt("zoom.maxPercent", 300)) / 100; 1.1971 + mv->GetFullZoom(&fullzoom); 1.1972 + fullzoom += ((float)change) / 10; 1.1973 + if (fullzoom < zoomMin) 1.1974 + fullzoom = zoomMin; 1.1975 + else if (fullzoom > zoomMax) 1.1976 + fullzoom = zoomMax; 1.1977 + mv->SetFullZoom(fullzoom); 1.1978 + 1.1979 + return NS_OK; 1.1980 +} 1.1981 + 1.1982 +void 1.1983 +EventStateManager::DoScrollHistory(int32_t direction) 1.1984 +{ 1.1985 + nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak()); 1.1986 + if (pcContainer) { 1.1987 + nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer)); 1.1988 + if (webNav) { 1.1989 + // positive direction to go back one step, nonpositive to go forward 1.1990 + if (direction > 0) 1.1991 + webNav->GoBack(); 1.1992 + else 1.1993 + webNav->GoForward(); 1.1994 + } 1.1995 + } 1.1996 +} 1.1997 + 1.1998 +void 1.1999 +EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame, 1.2000 + int32_t adjustment) 1.2001 +{ 1.2002 + // Exclude form controls and content in chrome docshells. 1.2003 + nsIContent *content = aTargetFrame->GetContent(); 1.2004 + if (content && 1.2005 + !content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) && 1.2006 + !nsContentUtils::IsInChromeDocshell(content->OwnerDoc())) 1.2007 + { 1.2008 + // positive adjustment to decrease zoom, negative to increase 1.2009 + int32_t change = (adjustment > 0) ? -1 : 1; 1.2010 + 1.2011 + if (Preferences::GetBool("browser.zoom.full") || content->GetCurrentDoc()->IsSyntheticDocument()) { 1.2012 + ChangeFullZoom(change); 1.2013 + } else { 1.2014 + ChangeTextSize(change); 1.2015 + } 1.2016 + } 1.2017 +} 1.2018 + 1.2019 +static nsIFrame* 1.2020 +GetParentFrameToScroll(nsIFrame* aFrame) 1.2021 +{ 1.2022 + if (!aFrame) 1.2023 + return nullptr; 1.2024 + 1.2025 + if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED && 1.2026 + nsLayoutUtils::IsReallyFixedPos(aFrame)) 1.2027 + return aFrame->PresContext()->GetPresShell()->GetRootScrollFrame(); 1.2028 + 1.2029 + return aFrame->GetParent(); 1.2030 +} 1.2031 + 1.2032 +void 1.2033 +EventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame, 1.2034 + WidgetWheelEvent* aEvent, 1.2035 + nsEventStatus* aStatus) 1.2036 +{ 1.2037 + MOZ_ASSERT(aEvent); 1.2038 + MOZ_ASSERT(aStatus); 1.2039 + 1.2040 + if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) { 1.2041 + return; 1.2042 + } 1.2043 + 1.2044 + // Ignore mouse wheel transaction for computing legacy mouse wheel 1.2045 + // events' delta value. 1.2046 + nsIScrollableFrame* scrollTarget = 1.2047 + ComputeScrollTarget(aTargetFrame, aEvent, 1.2048 + COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET); 1.2049 + 1.2050 + nsIFrame* scrollFrame = do_QueryFrame(scrollTarget); 1.2051 + nsPresContext* pc = 1.2052 + scrollFrame ? scrollFrame->PresContext() : aTargetFrame->PresContext(); 1.2053 + 1.2054 + // DOM event's delta vales are computed from CSS pixels. 1.2055 + nsSize scrollAmount = GetScrollAmount(pc, aEvent, scrollTarget); 1.2056 + nsIntSize scrollAmountInCSSPixels( 1.2057 + nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width), 1.2058 + nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.height)); 1.2059 + 1.2060 + // XXX We don't deal with fractional amount in legacy event, though the 1.2061 + // default action handler (DoScrollText()) deals with it. 1.2062 + // If we implemented such strict computation, we would need additional 1.2063 + // accumulated delta values. It would made the code more complicated. 1.2064 + // And also it would computes different delta values from older version. 1.2065 + // It doesn't make sense to implement such code for legacy events and 1.2066 + // rare cases. 1.2067 + int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY; 1.2068 + switch (aEvent->deltaMode) { 1.2069 + case nsIDOMWheelEvent::DOM_DELTA_PAGE: 1.2070 + scrollDeltaX = 1.2071 + !aEvent->lineOrPageDeltaX ? 0 : 1.2072 + (aEvent->lineOrPageDeltaX > 0 ? nsIDOMUIEvent::SCROLL_PAGE_DOWN : 1.2073 + nsIDOMUIEvent::SCROLL_PAGE_UP); 1.2074 + scrollDeltaY = 1.2075 + !aEvent->lineOrPageDeltaY ? 0 : 1.2076 + (aEvent->lineOrPageDeltaY > 0 ? nsIDOMUIEvent::SCROLL_PAGE_DOWN : 1.2077 + nsIDOMUIEvent::SCROLL_PAGE_UP); 1.2078 + pixelDeltaX = RoundDown(aEvent->deltaX * scrollAmountInCSSPixels.width); 1.2079 + pixelDeltaY = RoundDown(aEvent->deltaY * scrollAmountInCSSPixels.height); 1.2080 + break; 1.2081 + 1.2082 + case nsIDOMWheelEvent::DOM_DELTA_LINE: 1.2083 + scrollDeltaX = aEvent->lineOrPageDeltaX; 1.2084 + scrollDeltaY = aEvent->lineOrPageDeltaY; 1.2085 + pixelDeltaX = RoundDown(aEvent->deltaX * scrollAmountInCSSPixels.width); 1.2086 + pixelDeltaY = RoundDown(aEvent->deltaY * scrollAmountInCSSPixels.height); 1.2087 + break; 1.2088 + 1.2089 + case nsIDOMWheelEvent::DOM_DELTA_PIXEL: 1.2090 + scrollDeltaX = aEvent->lineOrPageDeltaX; 1.2091 + scrollDeltaY = aEvent->lineOrPageDeltaY; 1.2092 + pixelDeltaX = RoundDown(aEvent->deltaX); 1.2093 + pixelDeltaY = RoundDown(aEvent->deltaY); 1.2094 + break; 1.2095 + 1.2096 + default: 1.2097 + MOZ_CRASH("Invalid deltaMode value comes"); 1.2098 + } 1.2099 + 1.2100 + // Send the legacy events in following order: 1.2101 + // 1. Vertical scroll 1.2102 + // 2. Vertical pixel scroll (even if #1 isn't consumed) 1.2103 + // 3. Horizontal scroll (even if #1 and/or #2 are consumed) 1.2104 + // 4. Horizontal pixel scroll (even if #3 isn't consumed) 1.2105 + 1.2106 + nsWeakFrame targetFrame(aTargetFrame); 1.2107 + 1.2108 + MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault && 1.2109 + !aEvent->mFlags.mDefaultPrevented, 1.2110 + "If you make legacy events dispatched for default prevented wheel " 1.2111 + "event, you need to initialize stateX and stateY"); 1.2112 + EventState stateX, stateY; 1.2113 + if (scrollDeltaY) { 1.2114 + SendLineScrollEvent(aTargetFrame, aEvent, stateY, 1.2115 + scrollDeltaY, DELTA_DIRECTION_Y); 1.2116 + if (!targetFrame.IsAlive()) { 1.2117 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.2118 + return; 1.2119 + } 1.2120 + } 1.2121 + 1.2122 + if (pixelDeltaY) { 1.2123 + SendPixelScrollEvent(aTargetFrame, aEvent, stateY, 1.2124 + pixelDeltaY, DELTA_DIRECTION_Y); 1.2125 + if (!targetFrame.IsAlive()) { 1.2126 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.2127 + return; 1.2128 + } 1.2129 + } 1.2130 + 1.2131 + if (scrollDeltaX) { 1.2132 + SendLineScrollEvent(aTargetFrame, aEvent, stateX, 1.2133 + scrollDeltaX, DELTA_DIRECTION_X); 1.2134 + if (!targetFrame.IsAlive()) { 1.2135 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.2136 + return; 1.2137 + } 1.2138 + } 1.2139 + 1.2140 + if (pixelDeltaX) { 1.2141 + SendPixelScrollEvent(aTargetFrame, aEvent, stateX, 1.2142 + pixelDeltaX, DELTA_DIRECTION_X); 1.2143 + if (!targetFrame.IsAlive()) { 1.2144 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.2145 + return; 1.2146 + } 1.2147 + } 1.2148 + 1.2149 + if (stateY.mDefaultPrevented || stateX.mDefaultPrevented) { 1.2150 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.2151 + aEvent->mFlags.mDefaultPrevented = true; 1.2152 + aEvent->mFlags.mDefaultPreventedByContent |= 1.2153 + stateY.mDefaultPreventedByContent || stateX.mDefaultPreventedByContent; 1.2154 + } 1.2155 +} 1.2156 + 1.2157 +void 1.2158 +EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame, 1.2159 + WidgetWheelEvent* aEvent, 1.2160 + EventState& aState, 1.2161 + int32_t aDelta, 1.2162 + DeltaDirection aDeltaDirection) 1.2163 +{ 1.2164 + nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent(); 1.2165 + if (!targetContent) 1.2166 + targetContent = GetFocusedContent(); 1.2167 + if (!targetContent) 1.2168 + return; 1.2169 + 1.2170 + while (targetContent->IsNodeOfType(nsINode::eTEXT)) { 1.2171 + targetContent = targetContent->GetParent(); 1.2172 + } 1.2173 + 1.2174 + WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_SCROLL, 1.2175 + aEvent->widget); 1.2176 + event.mFlags.mDefaultPrevented = aState.mDefaultPrevented; 1.2177 + event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent; 1.2178 + event.refPoint = aEvent->refPoint; 1.2179 + event.widget = aEvent->widget; 1.2180 + event.time = aEvent->time; 1.2181 + event.modifiers = aEvent->modifiers; 1.2182 + event.buttons = aEvent->buttons; 1.2183 + event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X); 1.2184 + event.delta = aDelta; 1.2185 + event.inputSource = aEvent->inputSource; 1.2186 + 1.2187 + nsEventStatus status = nsEventStatus_eIgnore; 1.2188 + EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(), 1.2189 + &event, nullptr, &status); 1.2190 + aState.mDefaultPrevented = 1.2191 + event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault; 1.2192 + aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent; 1.2193 +} 1.2194 + 1.2195 +void 1.2196 +EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame, 1.2197 + WidgetWheelEvent* aEvent, 1.2198 + EventState& aState, 1.2199 + int32_t aPixelDelta, 1.2200 + DeltaDirection aDeltaDirection) 1.2201 +{ 1.2202 + nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent(); 1.2203 + if (!targetContent) { 1.2204 + targetContent = GetFocusedContent(); 1.2205 + if (!targetContent) 1.2206 + return; 1.2207 + } 1.2208 + 1.2209 + while (targetContent->IsNodeOfType(nsINode::eTEXT)) { 1.2210 + targetContent = targetContent->GetParent(); 1.2211 + } 1.2212 + 1.2213 + WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_PIXEL_SCROLL, 1.2214 + aEvent->widget); 1.2215 + event.mFlags.mDefaultPrevented = aState.mDefaultPrevented; 1.2216 + event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent; 1.2217 + event.refPoint = aEvent->refPoint; 1.2218 + event.widget = aEvent->widget; 1.2219 + event.time = aEvent->time; 1.2220 + event.modifiers = aEvent->modifiers; 1.2221 + event.buttons = aEvent->buttons; 1.2222 + event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X); 1.2223 + event.delta = aPixelDelta; 1.2224 + event.inputSource = aEvent->inputSource; 1.2225 + 1.2226 + nsEventStatus status = nsEventStatus_eIgnore; 1.2227 + EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(), 1.2228 + &event, nullptr, &status); 1.2229 + aState.mDefaultPrevented = 1.2230 + event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault; 1.2231 + aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent; 1.2232 +} 1.2233 + 1.2234 +nsIScrollableFrame* 1.2235 +EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame, 1.2236 + WidgetWheelEvent* aEvent, 1.2237 + ComputeScrollTargetOptions aOptions) 1.2238 +{ 1.2239 + return ComputeScrollTarget(aTargetFrame, aEvent->deltaX, aEvent->deltaY, 1.2240 + aEvent, aOptions); 1.2241 +} 1.2242 + 1.2243 +// Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking 1.2244 +// for which scrollbarowners to activate when two finger down on trackpad 1.2245 +// and before any actual motion 1.2246 +nsIScrollableFrame* 1.2247 +EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame, 1.2248 + double aDirectionX, 1.2249 + double aDirectionY, 1.2250 + WidgetWheelEvent* aEvent, 1.2251 + ComputeScrollTargetOptions aOptions) 1.2252 +{ 1.2253 + if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) { 1.2254 + // If the user recently scrolled with the mousewheel, then they probably 1.2255 + // want to scroll the same view as before instead of the view under the 1.2256 + // cursor. WheelTransaction tracks the frame currently being 1.2257 + // scrolled with the mousewheel. We consider the transaction ended when the 1.2258 + // mouse moves more than "mousewheel.transaction.ignoremovedelay" 1.2259 + // milliseconds after the last scroll operation, or any time the mouse moves 1.2260 + // out of the frame, or when more than "mousewheel.transaction.timeout" 1.2261 + // milliseconds have passed after the last operation, even if the mouse 1.2262 + // hasn't moved. 1.2263 + nsIFrame* lastScrollFrame = WheelTransaction::GetTargetFrame(); 1.2264 + if (lastScrollFrame) { 1.2265 + nsIScrollableFrame* frameToScroll = 1.2266 + lastScrollFrame->GetScrollTargetFrame(); 1.2267 + if (frameToScroll) { 1.2268 + return frameToScroll; 1.2269 + } 1.2270 + } 1.2271 + } 1.2272 + 1.2273 + // If the event doesn't cause scroll actually, we cannot find scroll target 1.2274 + // because we check if the event can cause scroll actually on each found 1.2275 + // scrollable frame. 1.2276 + if (!aDirectionX && !aDirectionY) { 1.2277 + return nullptr; 1.2278 + } 1.2279 + 1.2280 + bool checkIfScrollableX = 1.2281 + aDirectionX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS); 1.2282 + bool checkIfScrollableY = 1.2283 + aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS); 1.2284 + 1.2285 + nsIScrollableFrame* frameToScroll = nullptr; 1.2286 + nsIFrame* scrollFrame = 1.2287 + !(aOptions & START_FROM_PARENT) ? aTargetFrame : 1.2288 + GetParentFrameToScroll(aTargetFrame); 1.2289 + for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) { 1.2290 + // Check whether the frame wants to provide us with a scrollable view. 1.2291 + frameToScroll = scrollFrame->GetScrollTargetFrame(); 1.2292 + if (!frameToScroll) { 1.2293 + continue; 1.2294 + } 1.2295 + 1.2296 + // Don't scroll vertically by mouse-wheel on a single-line text control. 1.2297 + if (checkIfScrollableY) { 1.2298 + nsIContent* c = scrollFrame->GetContent(); 1.2299 + nsCOMPtr<nsITextControlElement> ctrl = 1.2300 + do_QueryInterface(c->IsInAnonymousSubtree() ? c->GetBindingParent() : c); 1.2301 + if (ctrl && ctrl->IsSingleLineTextControl()) { 1.2302 + continue; 1.2303 + } 1.2304 + } 1.2305 + 1.2306 + if (!checkIfScrollableX && !checkIfScrollableY) { 1.2307 + return frameToScroll; 1.2308 + } 1.2309 + 1.2310 + ScrollbarStyles ss = frameToScroll->GetScrollbarStyles(); 1.2311 + bool hiddenForV = (NS_STYLE_OVERFLOW_HIDDEN == ss.mVertical); 1.2312 + bool hiddenForH = (NS_STYLE_OVERFLOW_HIDDEN == ss.mHorizontal); 1.2313 + if ((hiddenForV && hiddenForH) || 1.2314 + (checkIfScrollableY && !checkIfScrollableX && hiddenForV) || 1.2315 + (checkIfScrollableX && !checkIfScrollableY && hiddenForH)) { 1.2316 + continue; 1.2317 + } 1.2318 + 1.2319 + // For default action, we should climb up the tree if cannot scroll it 1.2320 + // by the event actually. 1.2321 + bool canScroll = 1.2322 + WheelHandlingUtils::CanScrollOn(frameToScroll, aDirectionX, aDirectionY); 1.2323 + // Comboboxes need special care. 1.2324 + nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame); 1.2325 + if (comboBox) { 1.2326 + if (comboBox->IsDroppedDown()) { 1.2327 + // Don't propagate to parent when drop down menu is active. 1.2328 + return canScroll ? frameToScroll : nullptr; 1.2329 + } 1.2330 + // Always propagate when not dropped down (even if focused). 1.2331 + continue; 1.2332 + } 1.2333 + 1.2334 + if (canScroll) { 1.2335 + return frameToScroll; 1.2336 + } 1.2337 + } 1.2338 + 1.2339 + nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrame( 1.2340 + aTargetFrame->PresContext()->FrameManager()->GetRootFrame()); 1.2341 + aOptions = 1.2342 + static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT); 1.2343 + return newFrame ? ComputeScrollTarget(newFrame, aEvent, aOptions) : nullptr; 1.2344 +} 1.2345 + 1.2346 +nsSize 1.2347 +EventStateManager::GetScrollAmount(nsPresContext* aPresContext, 1.2348 + WidgetWheelEvent* aEvent, 1.2349 + nsIScrollableFrame* aScrollableFrame) 1.2350 +{ 1.2351 + MOZ_ASSERT(aPresContext); 1.2352 + MOZ_ASSERT(aEvent); 1.2353 + 1.2354 + bool isPage = (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE); 1.2355 + if (aScrollableFrame) { 1.2356 + return isPage ? aScrollableFrame->GetPageScrollAmount() : 1.2357 + aScrollableFrame->GetLineScrollAmount(); 1.2358 + } 1.2359 + 1.2360 + // If there is no scrollable frame and page scrolling, use view port size. 1.2361 + if (isPage) { 1.2362 + return aPresContext->GetVisibleArea().Size(); 1.2363 + } 1.2364 + 1.2365 + // If there is no scrollable frame, we should use root frame's information. 1.2366 + nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame(); 1.2367 + if (!rootFrame) { 1.2368 + return nsSize(0, 0); 1.2369 + } 1.2370 + nsRefPtr<nsFontMetrics> fm; 1.2371 + nsLayoutUtils::GetFontMetricsForFrame(rootFrame, getter_AddRefs(fm), 1.2372 + nsLayoutUtils::FontSizeInflationFor(rootFrame)); 1.2373 + NS_ENSURE_TRUE(fm, nsSize(0, 0)); 1.2374 + return nsSize(fm->AveCharWidth(), fm->MaxHeight()); 1.2375 +} 1.2376 + 1.2377 +void 1.2378 +EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame, 1.2379 + WidgetWheelEvent* aEvent) 1.2380 +{ 1.2381 + MOZ_ASSERT(aScrollableFrame); 1.2382 + MOZ_ASSERT(aEvent); 1.2383 + 1.2384 + nsIFrame* scrollFrame = do_QueryFrame(aScrollableFrame); 1.2385 + MOZ_ASSERT(scrollFrame); 1.2386 + nsWeakFrame scrollFrameWeak(scrollFrame); 1.2387 + 1.2388 + nsIFrame* lastScrollFrame = WheelTransaction::GetTargetFrame(); 1.2389 + if (!lastScrollFrame) { 1.2390 + WheelTransaction::BeginTransaction(scrollFrame, aEvent); 1.2391 + } else if (lastScrollFrame != scrollFrame) { 1.2392 + WheelTransaction::EndTransaction(); 1.2393 + WheelTransaction::BeginTransaction(scrollFrame, aEvent); 1.2394 + } else { 1.2395 + WheelTransaction::UpdateTransaction(aEvent); 1.2396 + } 1.2397 + 1.2398 + // When the scroll event will not scroll any views, UpdateTransaction 1.2399 + // fired MozMouseScrollFailed event which is for automated testing. 1.2400 + // In the event handler, the target frame might be destroyed. Then, 1.2401 + // we should not try scrolling anything. 1.2402 + if (!scrollFrameWeak.IsAlive()) { 1.2403 + WheelTransaction::EndTransaction(); 1.2404 + return; 1.2405 + } 1.2406 + 1.2407 + // Default action's actual scroll amount should be computed from device 1.2408 + // pixels. 1.2409 + nsPresContext* pc = scrollFrame->PresContext(); 1.2410 + nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollableFrame); 1.2411 + nsIntSize scrollAmountInDevPixels( 1.2412 + pc->AppUnitsToDevPixels(scrollAmount.width), 1.2413 + pc->AppUnitsToDevPixels(scrollAmount.height)); 1.2414 + nsIntPoint actualDevPixelScrollAmount = 1.2415 + DeltaAccumulator::GetInstance()-> 1.2416 + ComputeScrollAmountForDefaultAction(aEvent, scrollAmountInDevPixels); 1.2417 + 1.2418 + // Don't scroll around the axis whose overflow style is hidden. 1.2419 + ScrollbarStyles overflowStyle = aScrollableFrame->GetScrollbarStyles(); 1.2420 + if (overflowStyle.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) { 1.2421 + actualDevPixelScrollAmount.x = 0; 1.2422 + } 1.2423 + if (overflowStyle.mVertical == NS_STYLE_OVERFLOW_HIDDEN) { 1.2424 + actualDevPixelScrollAmount.y = 0; 1.2425 + } 1.2426 + 1.2427 + nsIAtom* origin = nullptr; 1.2428 + switch (aEvent->deltaMode) { 1.2429 + case nsIDOMWheelEvent::DOM_DELTA_LINE: 1.2430 + origin = nsGkAtoms::mouseWheel; 1.2431 + break; 1.2432 + case nsIDOMWheelEvent::DOM_DELTA_PAGE: 1.2433 + origin = nsGkAtoms::pages; 1.2434 + break; 1.2435 + case nsIDOMWheelEvent::DOM_DELTA_PIXEL: 1.2436 + origin = nsGkAtoms::pixels; 1.2437 + break; 1.2438 + default: 1.2439 + MOZ_CRASH("Invalid deltaMode value comes"); 1.2440 + } 1.2441 + 1.2442 + // We shouldn't scroll more one page at once except when over one page scroll 1.2443 + // is allowed for the event. 1.2444 + nsSize pageSize = aScrollableFrame->GetPageScrollAmount(); 1.2445 + nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width), 1.2446 + pc->AppUnitsToDevPixels(pageSize.height)); 1.2447 + if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) && 1.2448 + DeprecatedAbs(actualDevPixelScrollAmount.x) > devPixelPageSize.width) { 1.2449 + actualDevPixelScrollAmount.x = 1.2450 + (actualDevPixelScrollAmount.x >= 0) ? devPixelPageSize.width : 1.2451 + -devPixelPageSize.width; 1.2452 + } 1.2453 + 1.2454 + if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) && 1.2455 + DeprecatedAbs(actualDevPixelScrollAmount.y) > devPixelPageSize.height) { 1.2456 + actualDevPixelScrollAmount.y = 1.2457 + (actualDevPixelScrollAmount.y >= 0) ? devPixelPageSize.height : 1.2458 + -devPixelPageSize.height; 1.2459 + } 1.2460 + 1.2461 + bool isDeltaModePixel = 1.2462 + (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL); 1.2463 + 1.2464 + nsIScrollableFrame::ScrollMode mode; 1.2465 + switch (aEvent->scrollType) { 1.2466 + case WidgetWheelEvent::SCROLL_DEFAULT: 1.2467 + if (isDeltaModePixel) { 1.2468 + mode = nsIScrollableFrame::NORMAL; 1.2469 + } else { 1.2470 + mode = nsIScrollableFrame::SMOOTH; 1.2471 + } 1.2472 + break; 1.2473 + case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY: 1.2474 + mode = nsIScrollableFrame::INSTANT; 1.2475 + break; 1.2476 + case WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY: 1.2477 + mode = nsIScrollableFrame::NORMAL; 1.2478 + break; 1.2479 + case WidgetWheelEvent::SCROLL_SMOOTHLY: 1.2480 + mode = nsIScrollableFrame::SMOOTH; 1.2481 + break; 1.2482 + default: 1.2483 + MOZ_CRASH("Invalid scrollType value comes"); 1.2484 + } 1.2485 + 1.2486 + nsIntPoint overflow; 1.2487 + aScrollableFrame->ScrollBy(actualDevPixelScrollAmount, 1.2488 + nsIScrollableFrame::DEVICE_PIXELS, 1.2489 + mode, &overflow, origin); 1.2490 + 1.2491 + if (!scrollFrameWeak.IsAlive()) { 1.2492 + // If the scroll causes changing the layout, we can think that the event 1.2493 + // has been completely consumed by the content. Then, users probably don't 1.2494 + // want additional action. 1.2495 + aEvent->overflowDeltaX = aEvent->overflowDeltaY = 0; 1.2496 + } else if (isDeltaModePixel) { 1.2497 + aEvent->overflowDeltaX = overflow.x; 1.2498 + aEvent->overflowDeltaY = overflow.y; 1.2499 + } else { 1.2500 + aEvent->overflowDeltaX = 1.2501 + static_cast<double>(overflow.x) / scrollAmountInDevPixels.width; 1.2502 + aEvent->overflowDeltaY = 1.2503 + static_cast<double>(overflow.y) / scrollAmountInDevPixels.height; 1.2504 + } 1.2505 + 1.2506 + // If CSS overflow properties caused not to scroll, the overflowDelta* values 1.2507 + // should be same as delta* values since they may be used as gesture event by 1.2508 + // widget. However, if there is another scrollable element in the ancestor 1.2509 + // along the axis, probably users don't want the operation to cause 1.2510 + // additional action such as moving history. In such case, overflowDelta 1.2511 + // values should stay zero. 1.2512 + if (scrollFrameWeak.IsAlive()) { 1.2513 + if (aEvent->deltaX && 1.2514 + overflowStyle.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN && 1.2515 + !ComputeScrollTarget(scrollFrame, aEvent, 1.2516 + COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS)) { 1.2517 + aEvent->overflowDeltaX = aEvent->deltaX; 1.2518 + } 1.2519 + if (aEvent->deltaY && 1.2520 + overflowStyle.mVertical == NS_STYLE_OVERFLOW_HIDDEN && 1.2521 + !ComputeScrollTarget(scrollFrame, aEvent, 1.2522 + COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS)) { 1.2523 + aEvent->overflowDeltaY = aEvent->deltaY; 1.2524 + } 1.2525 + } 1.2526 + 1.2527 + NS_ASSERTION(aEvent->overflowDeltaX == 0 || 1.2528 + (aEvent->overflowDeltaX > 0) == (aEvent->deltaX > 0), 1.2529 + "The sign of overflowDeltaX is different from the scroll direction"); 1.2530 + NS_ASSERTION(aEvent->overflowDeltaY == 0 || 1.2531 + (aEvent->overflowDeltaY > 0) == (aEvent->deltaY > 0), 1.2532 + "The sign of overflowDeltaY is different from the scroll direction"); 1.2533 + 1.2534 + WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent); 1.2535 +} 1.2536 + 1.2537 +void 1.2538 +EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent, 1.2539 + nsIFrame* targetFrame) 1.2540 +{ 1.2541 + 1.2542 + NS_ASSERTION(aEvent->message == NS_GESTURENOTIFY_EVENT_START, 1.2543 + "DecideGestureEvent called with a non-gesture event"); 1.2544 + 1.2545 + /* Check the ancestor tree to decide if any frame is willing* to receive 1.2546 + * a MozPixelScroll event. If that's the case, the current touch gesture 1.2547 + * will be used as a pan gesture; otherwise it will be a regular 1.2548 + * mousedown/mousemove/click event. 1.2549 + * 1.2550 + * *willing: determine if it makes sense to pan the element using scroll events: 1.2551 + * - For web content: if there are any visible scrollbars on the touch point 1.2552 + * - For XUL: if it's an scrollable element that can currently scroll in some 1.2553 + * direction. 1.2554 + * 1.2555 + * Note: we'll have to one-off various cases to ensure a good usable behavior 1.2556 + */ 1.2557 + WidgetGestureNotifyEvent::ePanDirection panDirection = 1.2558 + WidgetGestureNotifyEvent::ePanNone; 1.2559 + bool displayPanFeedback = false; 1.2560 + for (nsIFrame* current = targetFrame; current; 1.2561 + current = nsLayoutUtils::GetCrossDocParentFrame(current)) { 1.2562 + 1.2563 + nsIAtom* currentFrameType = current->GetType(); 1.2564 + 1.2565 + // Scrollbars should always be draggable 1.2566 + if (currentFrameType == nsGkAtoms::scrollbarFrame) { 1.2567 + panDirection = WidgetGestureNotifyEvent::ePanNone; 1.2568 + break; 1.2569 + } 1.2570 + 1.2571 +#ifdef MOZ_XUL 1.2572 + // Special check for trees 1.2573 + nsTreeBodyFrame* treeFrame = do_QueryFrame(current); 1.2574 + if (treeFrame) { 1.2575 + if (treeFrame->GetHorizontalOverflow()) { 1.2576 + panDirection = WidgetGestureNotifyEvent::ePanHorizontal; 1.2577 + } 1.2578 + if (treeFrame->GetVerticalOverflow()) { 1.2579 + panDirection = WidgetGestureNotifyEvent::ePanVertical; 1.2580 + } 1.2581 + break; 1.2582 + } 1.2583 +#endif 1.2584 + 1.2585 + nsIScrollableFrame* scrollableFrame = do_QueryFrame(current); 1.2586 + if (scrollableFrame) { 1.2587 + if (current->IsFrameOfType(nsIFrame::eXULBox)) { 1.2588 + displayPanFeedback = true; 1.2589 + 1.2590 + nsRect scrollRange = scrollableFrame->GetScrollRange(); 1.2591 + bool canScrollHorizontally = scrollRange.width > 0; 1.2592 + 1.2593 + if (targetFrame->GetType() == nsGkAtoms::menuFrame) { 1.2594 + // menu frames report horizontal scroll when they have submenus 1.2595 + // and we don't want that 1.2596 + canScrollHorizontally = false; 1.2597 + displayPanFeedback = false; 1.2598 + } 1.2599 + 1.2600 + // Vertical panning has priority over horizontal panning, so 1.2601 + // when vertical movement is possible we can just finish the loop. 1.2602 + if (scrollRange.height > 0) { 1.2603 + panDirection = WidgetGestureNotifyEvent::ePanVertical; 1.2604 + break; 1.2605 + } 1.2606 + 1.2607 + if (canScrollHorizontally) { 1.2608 + panDirection = WidgetGestureNotifyEvent::ePanHorizontal; 1.2609 + displayPanFeedback = false; 1.2610 + } 1.2611 + } else { //Not a XUL box 1.2612 + uint32_t scrollbarVisibility = scrollableFrame->GetScrollbarVisibility(); 1.2613 + 1.2614 + //Check if we have visible scrollbars 1.2615 + if (scrollbarVisibility & nsIScrollableFrame::VERTICAL) { 1.2616 + panDirection = WidgetGestureNotifyEvent::ePanVertical; 1.2617 + displayPanFeedback = true; 1.2618 + break; 1.2619 + } 1.2620 + 1.2621 + if (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) { 1.2622 + panDirection = WidgetGestureNotifyEvent::ePanHorizontal; 1.2623 + displayPanFeedback = true; 1.2624 + } 1.2625 + } 1.2626 + } //scrollableFrame 1.2627 + } //ancestor chain 1.2628 + 1.2629 + aEvent->displayPanFeedback = displayPanFeedback; 1.2630 + aEvent->panDirection = panDirection; 1.2631 +} 1.2632 + 1.2633 +#ifdef XP_MACOSX 1.2634 +static bool 1.2635 +NodeAllowsClickThrough(nsINode* aNode) 1.2636 +{ 1.2637 + while (aNode) { 1.2638 + if (aNode->IsElement() && aNode->AsElement()->IsXUL()) { 1.2639 + mozilla::dom::Element* element = aNode->AsElement(); 1.2640 + static nsIContent::AttrValuesArray strings[] = 1.2641 + {&nsGkAtoms::always, &nsGkAtoms::never, nullptr}; 1.2642 + switch (element->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::clickthrough, 1.2643 + strings, eCaseMatters)) { 1.2644 + case 0: 1.2645 + return true; 1.2646 + case 1: 1.2647 + return false; 1.2648 + } 1.2649 + } 1.2650 + aNode = nsContentUtils::GetCrossDocParentNode(aNode); 1.2651 + } 1.2652 + return true; 1.2653 +} 1.2654 +#endif 1.2655 + 1.2656 +nsresult 1.2657 +EventStateManager::PostHandleEvent(nsPresContext* aPresContext, 1.2658 + WidgetEvent* aEvent, 1.2659 + nsIFrame* aTargetFrame, 1.2660 + nsEventStatus* aStatus) 1.2661 +{ 1.2662 + NS_ENSURE_ARG(aPresContext); 1.2663 + NS_ENSURE_ARG_POINTER(aStatus); 1.2664 + 1.2665 + bool dispatchedToContentProcess = HandleCrossProcessEvent(aEvent, 1.2666 + aTargetFrame, 1.2667 + aStatus); 1.2668 + 1.2669 + mCurrentTarget = aTargetFrame; 1.2670 + mCurrentTargetContent = nullptr; 1.2671 + 1.2672 + // Most of the events we handle below require a frame. 1.2673 + // Add special cases here. 1.2674 + if (!mCurrentTarget && aEvent->message != NS_MOUSE_BUTTON_UP && 1.2675 + aEvent->message != NS_MOUSE_BUTTON_DOWN) { 1.2676 + return NS_OK; 1.2677 + } 1.2678 + 1.2679 + //Keep the prescontext alive, we might need it after event dispatch 1.2680 + nsRefPtr<nsPresContext> presContext = aPresContext; 1.2681 + nsresult ret = NS_OK; 1.2682 + 1.2683 + switch (aEvent->message) { 1.2684 + case NS_MOUSE_BUTTON_DOWN: 1.2685 + { 1.2686 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.2687 + if (mouseEvent->button == WidgetMouseEvent::eLeftButton && 1.2688 + !sNormalLMouseEventInProcess) { 1.2689 + // We got a mouseup event while a mousedown event was being processed. 1.2690 + // Make sure that the capturing content is cleared. 1.2691 + nsIPresShell::SetCapturingContent(nullptr, 0); 1.2692 + break; 1.2693 + } 1.2694 + 1.2695 + nsCOMPtr<nsIContent> activeContent; 1.2696 + if (nsEventStatus_eConsumeNoDefault != *aStatus) { 1.2697 + nsCOMPtr<nsIContent> newFocus; 1.2698 + bool suppressBlur = false; 1.2699 + if (mCurrentTarget) { 1.2700 + mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus)); 1.2701 + const nsStyleUserInterface* ui = mCurrentTarget->StyleUserInterface(); 1.2702 + activeContent = mCurrentTarget->GetContent(); 1.2703 + 1.2704 + // In some cases, we do not want to even blur the current focused 1.2705 + // element. Those cases are: 1.2706 + // 1. -moz-user-focus CSS property is set to 'ignore'; 1.2707 + // 2. Element with NS_EVENT_STATE_DISABLED 1.2708 + // (aka :disabled pseudo-class for HTML element); 1.2709 + // 3. XUL control element has the disabled property set to 'true'. 1.2710 + // 1.2711 + // We can't use nsIFrame::IsFocusable() because we want to blur when 1.2712 + // we click on a visibility: none element. 1.2713 + // We can't use nsIContent::IsFocusable() because we want to blur when 1.2714 + // we click on a non-focusable element like a <div>. 1.2715 + // We have to use |aEvent->target| to not make sure we do not check an 1.2716 + // anonymous node of the targeted element. 1.2717 + suppressBlur = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE); 1.2718 + 1.2719 + if (!suppressBlur) { 1.2720 + nsCOMPtr<Element> element = do_QueryInterface(aEvent->target); 1.2721 + suppressBlur = element && 1.2722 + element->State().HasState(NS_EVENT_STATE_DISABLED); 1.2723 + } 1.2724 + 1.2725 + if (!suppressBlur) { 1.2726 + nsCOMPtr<nsIDOMXULControlElement> xulControl = 1.2727 + do_QueryInterface(aEvent->target); 1.2728 + if (xulControl) { 1.2729 + bool disabled; 1.2730 + xulControl->GetDisabled(&disabled); 1.2731 + suppressBlur = disabled; 1.2732 + } 1.2733 + } 1.2734 + } 1.2735 + 1.2736 + if (!suppressBlur) { 1.2737 + suppressBlur = nsContentUtils::IsUserFocusIgnored(activeContent); 1.2738 + } 1.2739 + 1.2740 + nsIFrame* currFrame = mCurrentTarget; 1.2741 + 1.2742 + // When a root content which isn't editable but has an editable HTML 1.2743 + // <body> element is clicked, we should redirect the focus to the 1.2744 + // the <body> element. E.g., when an user click bottom of the editor 1.2745 + // where is outside of the <body> element, the <body> should be focused 1.2746 + // and the user can edit immediately after that. 1.2747 + // 1.2748 + // NOTE: The newFocus isn't editable that also means it's not in 1.2749 + // designMode. In designMode, all contents are not focusable. 1.2750 + if (newFocus && !newFocus->IsEditable()) { 1.2751 + nsIDocument *doc = newFocus->GetCurrentDoc(); 1.2752 + if (doc && newFocus == doc->GetRootElement()) { 1.2753 + nsIContent *bodyContent = 1.2754 + nsLayoutUtils::GetEditableRootContentByContentEditable(doc); 1.2755 + if (bodyContent) { 1.2756 + nsIFrame* bodyFrame = bodyContent->GetPrimaryFrame(); 1.2757 + if (bodyFrame) { 1.2758 + currFrame = bodyFrame; 1.2759 + newFocus = bodyContent; 1.2760 + } 1.2761 + } 1.2762 + } 1.2763 + } 1.2764 + 1.2765 + // When the mouse is pressed, the default action is to focus the 1.2766 + // target. Look for the nearest enclosing focusable frame. 1.2767 + while (currFrame) { 1.2768 + // If the mousedown happened inside a popup, don't 1.2769 + // try to set focus on one of its containing elements 1.2770 + const nsStyleDisplay* display = currFrame->StyleDisplay(); 1.2771 + if (display->mDisplay == NS_STYLE_DISPLAY_POPUP) { 1.2772 + newFocus = nullptr; 1.2773 + break; 1.2774 + } 1.2775 + 1.2776 + int32_t tabIndexUnused; 1.2777 + if (currFrame->IsFocusable(&tabIndexUnused, true)) { 1.2778 + newFocus = currFrame->GetContent(); 1.2779 + nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus)); 1.2780 + if (domElement) 1.2781 + break; 1.2782 + } 1.2783 + currFrame = currFrame->GetParent(); 1.2784 + } 1.2785 + 1.2786 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.2787 + if (fm) { 1.2788 + // if something was found to focus, focus it. Otherwise, if the 1.2789 + // element that was clicked doesn't have -moz-user-focus: ignore, 1.2790 + // clear the existing focus. For -moz-user-focus: ignore, the focus 1.2791 + // is just left as is. 1.2792 + // Another effect of mouse clicking, handled in nsSelection, is that 1.2793 + // it should update the caret position to where the mouse was 1.2794 + // clicked. Because the focus is cleared when clicking on a 1.2795 + // non-focusable node, the next press of the tab key will cause 1.2796 + // focus to be shifted from the caret position instead of the root. 1.2797 + if (newFocus && currFrame) { 1.2798 + // use the mouse flag and the noscroll flag so that the content 1.2799 + // doesn't unexpectedly scroll when clicking an element that is 1.2800 + // only hald visible 1.2801 + nsCOMPtr<nsIDOMElement> newFocusElement = do_QueryInterface(newFocus); 1.2802 + fm->SetFocus(newFocusElement, nsIFocusManager::FLAG_BYMOUSE | 1.2803 + nsIFocusManager::FLAG_NOSCROLL); 1.2804 + } 1.2805 + else if (!suppressBlur) { 1.2806 + // clear the focus within the frame and then set it as the 1.2807 + // focused frame 1.2808 + EnsureDocument(mPresContext); 1.2809 + if (mDocument) { 1.2810 +#ifdef XP_MACOSX 1.2811 + if (!activeContent || !activeContent->IsXUL()) 1.2812 +#endif 1.2813 + fm->ClearFocus(mDocument->GetWindow()); 1.2814 + fm->SetFocusedWindow(mDocument->GetWindow()); 1.2815 + } 1.2816 + } 1.2817 + } 1.2818 + 1.2819 + // The rest is left button-specific. 1.2820 + if (mouseEvent->button != WidgetMouseEvent::eLeftButton) { 1.2821 + break; 1.2822 + } 1.2823 + 1.2824 + if (activeContent) { 1.2825 + // The nearest enclosing element goes into the 1.2826 + // :active state. If we fail the QI to DOMElement, 1.2827 + // then we know we're only a node, and that we need 1.2828 + // to obtain our parent element and put it into :active 1.2829 + // instead. 1.2830 + nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(activeContent)); 1.2831 + if (!elt) { 1.2832 + nsIContent* par = activeContent->GetParent(); 1.2833 + if (par) 1.2834 + activeContent = par; 1.2835 + } 1.2836 + } 1.2837 + } 1.2838 + else { 1.2839 + // if we're here, the event handler returned false, so stop 1.2840 + // any of our own processing of a drag. Workaround for bug 43258. 1.2841 + StopTrackingDragGesture(); 1.2842 + 1.2843 + // When the event was cancelled, there is currently a chrome document 1.2844 + // focused and a mousedown just occurred on a content document, ensure 1.2845 + // that the window that was clicked is focused. 1.2846 + EnsureDocument(mPresContext); 1.2847 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.2848 + if (mDocument && fm) { 1.2849 + nsCOMPtr<nsIDOMWindow> currentWindow; 1.2850 + fm->GetFocusedWindow(getter_AddRefs(currentWindow)); 1.2851 + if (currentWindow && mDocument->GetWindow() && 1.2852 + currentWindow != mDocument->GetWindow() && 1.2853 + !nsContentUtils::IsChromeDoc(mDocument)) { 1.2854 + nsCOMPtr<nsIDOMWindow> currentTop; 1.2855 + nsCOMPtr<nsIDOMWindow> newTop; 1.2856 + currentWindow->GetTop(getter_AddRefs(currentTop)); 1.2857 + mDocument->GetWindow()->GetTop(getter_AddRefs(newTop)); 1.2858 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(currentWindow); 1.2859 + nsCOMPtr<nsIDocument> currentDoc = win->GetExtantDoc(); 1.2860 + if (nsContentUtils::IsChromeDoc(currentDoc) || 1.2861 + (currentTop && newTop && currentTop != newTop)) { 1.2862 + fm->SetFocusedWindow(mDocument->GetWindow()); 1.2863 + } 1.2864 + } 1.2865 + } 1.2866 + } 1.2867 + SetActiveManager(this, activeContent); 1.2868 + } 1.2869 + break; 1.2870 + case NS_POINTER_CANCEL: 1.2871 + case NS_POINTER_UP: { 1.2872 + WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent(); 1.2873 + // After UP/Cancel Touch pointers become invalid so we can remove relevant helper from Table 1.2874 + // Mouse/Pen pointers are valid all the time (not only between down/up) 1.2875 + if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { 1.2876 + mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId); 1.2877 + } 1.2878 + if (pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_MOUSE) { 1.2879 + GenerateMouseEnterExit(pointerEvent); 1.2880 + } 1.2881 + break; 1.2882 + } 1.2883 + case NS_MOUSE_BUTTON_UP: 1.2884 + { 1.2885 + ClearGlobalActiveContent(this); 1.2886 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.2887 + if (mouseEvent && mouseEvent->IsReal()) { 1.2888 + if (!mCurrentTarget) { 1.2889 + GetEventTarget(); 1.2890 + } 1.2891 + // Make sure to dispatch the click even if there is no frame for 1.2892 + // the current target element. This is required for Web compatibility. 1.2893 + ret = CheckForAndDispatchClick(presContext, mouseEvent, aStatus); 1.2894 + } 1.2895 + 1.2896 + nsIPresShell *shell = presContext->GetPresShell(); 1.2897 + if (shell) { 1.2898 + nsRefPtr<nsFrameSelection> frameSelection = shell->FrameSelection(); 1.2899 + frameSelection->SetMouseDownState(false); 1.2900 + } 1.2901 + } 1.2902 + break; 1.2903 + case NS_WHEEL_STOP: 1.2904 + { 1.2905 + MOZ_ASSERT(aEvent->mFlags.mIsTrusted); 1.2906 + ScrollbarsForWheel::MayInactivate(); 1.2907 + } 1.2908 + break; 1.2909 + case NS_WHEEL_WHEEL: 1.2910 + case NS_WHEEL_START: 1.2911 + { 1.2912 + MOZ_ASSERT(aEvent->mFlags.mIsTrusted); 1.2913 + 1.2914 + if (*aStatus == nsEventStatus_eConsumeNoDefault) { 1.2915 + ScrollbarsForWheel::Inactivate(); 1.2916 + break; 1.2917 + } 1.2918 + 1.2919 + WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent(); 1.2920 + switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) { 1.2921 + case WheelPrefs::ACTION_SCROLL: { 1.2922 + // For scrolling of default action, we should honor the mouse wheel 1.2923 + // transaction. 1.2924 + 1.2925 + ScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent); 1.2926 + 1.2927 + if (aEvent->message != NS_WHEEL_WHEEL || 1.2928 + (!wheelEvent->deltaX && !wheelEvent->deltaY)) { 1.2929 + break; 1.2930 + } 1.2931 + 1.2932 + nsIScrollableFrame* scrollTarget = 1.2933 + ComputeScrollTarget(aTargetFrame, wheelEvent, 1.2934 + COMPUTE_DEFAULT_ACTION_TARGET); 1.2935 + 1.2936 + ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget); 1.2937 + 1.2938 + nsIFrame* rootScrollFrame = !aTargetFrame ? nullptr : 1.2939 + aTargetFrame->PresContext()->PresShell()->GetRootScrollFrame(); 1.2940 + nsIScrollableFrame* rootScrollableFrame = nullptr; 1.2941 + if (rootScrollFrame) { 1.2942 + rootScrollableFrame = do_QueryFrame(rootScrollFrame); 1.2943 + } 1.2944 + if (!scrollTarget || scrollTarget == rootScrollableFrame) { 1.2945 + wheelEvent->mViewPortIsOverscrolled = true; 1.2946 + } 1.2947 + wheelEvent->overflowDeltaX = wheelEvent->deltaX; 1.2948 + wheelEvent->overflowDeltaY = wheelEvent->deltaY; 1.2949 + WheelPrefs::GetInstance()-> 1.2950 + CancelApplyingUserPrefsFromOverflowDelta(wheelEvent); 1.2951 + if (scrollTarget) { 1.2952 + DoScrollText(scrollTarget, wheelEvent); 1.2953 + } else { 1.2954 + WheelTransaction::EndTransaction(); 1.2955 + ScrollbarsForWheel::Inactivate(); 1.2956 + } 1.2957 + break; 1.2958 + } 1.2959 + case WheelPrefs::ACTION_HISTORY: { 1.2960 + // If this event doesn't cause NS_MOUSE_SCROLL event or the direction 1.2961 + // is oblique, don't perform history back/forward. 1.2962 + int32_t intDelta = wheelEvent->GetPreferredIntDelta(); 1.2963 + if (!intDelta) { 1.2964 + break; 1.2965 + } 1.2966 + DoScrollHistory(intDelta); 1.2967 + break; 1.2968 + } 1.2969 + case WheelPrefs::ACTION_ZOOM: { 1.2970 + // If this event doesn't cause NS_MOUSE_SCROLL event or the direction 1.2971 + // is oblique, don't perform zoom in/out. 1.2972 + int32_t intDelta = wheelEvent->GetPreferredIntDelta(); 1.2973 + if (!intDelta) { 1.2974 + break; 1.2975 + } 1.2976 + DoScrollZoom(aTargetFrame, intDelta); 1.2977 + break; 1.2978 + } 1.2979 + case WheelPrefs::ACTION_NONE: 1.2980 + default: 1.2981 + // If we don't handle the wheel event, all of the delta values must 1.2982 + // be overflown delta values. 1.2983 + wheelEvent->overflowDeltaX = wheelEvent->deltaX; 1.2984 + wheelEvent->overflowDeltaY = wheelEvent->deltaY; 1.2985 + WheelPrefs::GetInstance()-> 1.2986 + CancelApplyingUserPrefsFromOverflowDelta(wheelEvent); 1.2987 + break; 1.2988 + } 1.2989 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.2990 + } 1.2991 + break; 1.2992 + 1.2993 + case NS_GESTURENOTIFY_EVENT_START: 1.2994 + { 1.2995 + if (nsEventStatus_eConsumeNoDefault != *aStatus) { 1.2996 + DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget); 1.2997 + } 1.2998 + } 1.2999 + break; 1.3000 + 1.3001 + case NS_DRAGDROP_ENTER: 1.3002 + case NS_DRAGDROP_OVER: 1.3003 + { 1.3004 + NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "Expected a drag event"); 1.3005 + 1.3006 + nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); 1.3007 + if (!dragSession) 1.3008 + break; 1.3009 + 1.3010 + // Reset the flag. 1.3011 + dragSession->SetOnlyChromeDrop(false); 1.3012 + if (mPresContext) { 1.3013 + EnsureDocument(mPresContext); 1.3014 + } 1.3015 + bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument); 1.3016 + 1.3017 + // the initial dataTransfer is the one from the dragstart event that 1.3018 + // was set on the dragSession when the drag began. 1.3019 + nsCOMPtr<nsIDOMDataTransfer> dataTransfer; 1.3020 + nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer; 1.3021 + dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer)); 1.3022 + 1.3023 + WidgetDragEvent *dragEvent = aEvent->AsDragEvent(); 1.3024 + 1.3025 + // collect any changes to moz cursor settings stored in the event's 1.3026 + // data transfer. 1.3027 + UpdateDragDataTransfer(dragEvent); 1.3028 + 1.3029 + // cancelling a dragenter or dragover event means that a drop should be 1.3030 + // allowed, so update the dropEffect and the canDrop state to indicate 1.3031 + // that a drag is allowed. If the event isn't cancelled, a drop won't be 1.3032 + // allowed. Essentially, to allow a drop somewhere, specify the effects 1.3033 + // using the effectAllowed and dropEffect properties in a dragenter or 1.3034 + // dragover event and cancel the event. To not allow a drop somewhere, 1.3035 + // don't cancel the event or set the effectAllowed or dropEffect to 1.3036 + // "none". This way, if the event is just ignored, no drop will be 1.3037 + // allowed. 1.3038 + uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE; 1.3039 + if (nsEventStatus_eConsumeNoDefault == *aStatus) { 1.3040 + // if the event has a dataTransfer set, use it. 1.3041 + if (dragEvent->dataTransfer) { 1.3042 + // get the dataTransfer and the dropEffect that was set on it 1.3043 + dataTransfer = do_QueryInterface(dragEvent->dataTransfer); 1.3044 + dataTransfer->GetDropEffectInt(&dropEffect); 1.3045 + } 1.3046 + else { 1.3047 + // if dragEvent->dataTransfer is null, it means that no attempt was 1.3048 + // made to access the dataTransfer during the event, yet the event 1.3049 + // was cancelled. Instead, use the initial data transfer available 1.3050 + // from the drag session. The drop effect would not have been 1.3051 + // initialized (which is done in DragEvent::GetDataTransfer), 1.3052 + // so set it from the drag action. We'll still want to filter it 1.3053 + // based on the effectAllowed below. 1.3054 + dataTransfer = initialDataTransfer; 1.3055 + 1.3056 + uint32_t action; 1.3057 + dragSession->GetDragAction(&action); 1.3058 + 1.3059 + // filter the drop effect based on the action. Use UNINITIALIZED as 1.3060 + // any effect is allowed. 1.3061 + dropEffect = nsContentUtils::FilterDropEffect(action, 1.3062 + nsIDragService::DRAGDROP_ACTION_UNINITIALIZED); 1.3063 + } 1.3064 + 1.3065 + // At this point, if the dataTransfer is null, it means that the 1.3066 + // drag was originally started by directly calling the drag service. 1.3067 + // Just assume that all effects are allowed. 1.3068 + uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED; 1.3069 + if (dataTransfer) 1.3070 + dataTransfer->GetEffectAllowedInt(&effectAllowed); 1.3071 + 1.3072 + // set the drag action based on the drop effect and effect allowed. 1.3073 + // The drop effect field on the drag transfer object specifies the 1.3074 + // desired current drop effect. However, it cannot be used if the 1.3075 + // effectAllowed state doesn't include that type of action. If the 1.3076 + // dropEffect is "none", then the action will be 'none' so a drop will 1.3077 + // not be allowed. 1.3078 + uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE; 1.3079 + if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED || 1.3080 + dropEffect & effectAllowed) 1.3081 + action = dropEffect; 1.3082 + 1.3083 + if (action == nsIDragService::DRAGDROP_ACTION_NONE) 1.3084 + dropEffect = nsIDragService::DRAGDROP_ACTION_NONE; 1.3085 + 1.3086 + // inform the drag session that a drop is allowed on this node. 1.3087 + dragSession->SetDragAction(action); 1.3088 + dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE); 1.3089 + 1.3090 + // For now, do this only for dragover. 1.3091 + //XXXsmaug dragenter needs some more work. 1.3092 + if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) { 1.3093 + // Someone has called preventDefault(), check whether is was on 1.3094 + // content or chrome. 1.3095 + dragSession->SetOnlyChromeDrop( 1.3096 + !dragEvent->mDefaultPreventedOnContent); 1.3097 + } 1.3098 + } else if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) { 1.3099 + // No one called preventDefault(), so handle drop only in chrome. 1.3100 + dragSession->SetOnlyChromeDrop(true); 1.3101 + } 1.3102 + 1.3103 + // now set the drop effect in the initial dataTransfer. This ensures 1.3104 + // that we can get the desired drop effect in the drop event. 1.3105 + if (initialDataTransfer) 1.3106 + initialDataTransfer->SetDropEffectInt(dropEffect); 1.3107 + } 1.3108 + break; 1.3109 + 1.3110 + case NS_DRAGDROP_DROP: 1.3111 + { 1.3112 + // now fire the dragdrop event, for compatibility with XUL 1.3113 + if (mCurrentTarget && nsEventStatus_eConsumeNoDefault != *aStatus) { 1.3114 + nsCOMPtr<nsIContent> targetContent; 1.3115 + mCurrentTarget->GetContentForEvent(aEvent, 1.3116 + getter_AddRefs(targetContent)); 1.3117 + 1.3118 + nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget(); 1.3119 + WidgetDragEvent event(aEvent->mFlags.mIsTrusted, 1.3120 + NS_DRAGDROP_DRAGDROP, widget); 1.3121 + 1.3122 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.3123 + event.refPoint = mouseEvent->refPoint; 1.3124 + if (mouseEvent->widget) { 1.3125 + event.refPoint += LayoutDeviceIntPoint::FromUntyped(mouseEvent->widget->WidgetToScreenOffset()); 1.3126 + } 1.3127 + event.refPoint -= LayoutDeviceIntPoint::FromUntyped(widget->WidgetToScreenOffset()); 1.3128 + event.modifiers = mouseEvent->modifiers; 1.3129 + event.buttons = mouseEvent->buttons; 1.3130 + event.inputSource = mouseEvent->inputSource; 1.3131 + 1.3132 + nsEventStatus status = nsEventStatus_eIgnore; 1.3133 + nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell(); 1.3134 + if (presShell) { 1.3135 + presShell->HandleEventWithTarget(&event, mCurrentTarget, 1.3136 + targetContent, &status); 1.3137 + } 1.3138 + } 1.3139 + sLastDragOverFrame = nullptr; 1.3140 + ClearGlobalActiveContent(this); 1.3141 + break; 1.3142 + } 1.3143 + case NS_DRAGDROP_EXIT: 1.3144 + // make sure to fire the enter and exit_synth events after the 1.3145 + // NS_DRAGDROP_EXIT event, otherwise we'll clean up too early 1.3146 + GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent()); 1.3147 + break; 1.3148 + 1.3149 + case NS_KEY_UP: 1.3150 + break; 1.3151 + 1.3152 + case NS_KEY_PRESS: 1.3153 + if (nsEventStatus_eConsumeNoDefault != *aStatus) { 1.3154 + WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); 1.3155 + //This is to prevent keyboard scrolling while alt modifier in use. 1.3156 + if (!keyEvent->IsAlt()) { 1.3157 + switch(keyEvent->keyCode) { 1.3158 + case NS_VK_TAB: 1.3159 + case NS_VK_F6: 1.3160 + // Handling the tab event after it was sent to content is bad, 1.3161 + // because to the FocusManager the remote-browser looks like one 1.3162 + // element, so we would just move the focus to the next element 1.3163 + // in chrome, instead of handling it in content. 1.3164 + if (dispatchedToContentProcess) 1.3165 + break; 1.3166 + 1.3167 + EnsureDocument(mPresContext); 1.3168 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.3169 + if (fm && mDocument) { 1.3170 + // Shift focus forward or back depending on shift key 1.3171 + bool isDocMove = 1.3172 + keyEvent->IsControl() || keyEvent->keyCode == NS_VK_F6; 1.3173 + uint32_t dir = keyEvent->IsShift() ? 1.3174 + (isDocMove ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARDDOC) : 1.3175 + static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARD)) : 1.3176 + (isDocMove ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARDDOC) : 1.3177 + static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD)); 1.3178 + nsCOMPtr<nsIDOMElement> result; 1.3179 + fm->MoveFocus(mDocument->GetWindow(), nullptr, dir, 1.3180 + nsIFocusManager::FLAG_BYKEY, 1.3181 + getter_AddRefs(result)); 1.3182 + } 1.3183 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.3184 + break; 1.3185 + } 1.3186 + } 1.3187 + } 1.3188 + break; 1.3189 + 1.3190 + case NS_MOUSE_ENTER: 1.3191 + if (mCurrentTarget) { 1.3192 + nsCOMPtr<nsIContent> targetContent; 1.3193 + mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent)); 1.3194 + SetContentState(targetContent, NS_EVENT_STATE_HOVER); 1.3195 + } 1.3196 + break; 1.3197 + 1.3198 +#ifdef XP_MACOSX 1.3199 + case NS_MOUSE_ACTIVATE: 1.3200 + if (mCurrentTarget) { 1.3201 + nsCOMPtr<nsIContent> targetContent; 1.3202 + mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent)); 1.3203 + if (!NodeAllowsClickThrough(targetContent)) { 1.3204 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.3205 + } 1.3206 + } 1.3207 + break; 1.3208 +#endif 1.3209 + } 1.3210 + 1.3211 + //Reset target frame to null to avoid mistargeting after reentrant event 1.3212 + mCurrentTarget = nullptr; 1.3213 + mCurrentTargetContent = nullptr; 1.3214 + 1.3215 + return ret; 1.3216 +} 1.3217 + 1.3218 +bool 1.3219 +EventStateManager::RemoteQueryContentEvent(WidgetEvent* aEvent) 1.3220 +{ 1.3221 + WidgetQueryContentEvent* queryEvent = aEvent->AsQueryContentEvent(); 1.3222 + if (!IsTargetCrossProcess(queryEvent)) { 1.3223 + return false; 1.3224 + } 1.3225 + // Will not be handled locally, remote the event 1.3226 + GetCrossProcessTarget()->HandleQueryContentEvent(*queryEvent); 1.3227 + return true; 1.3228 +} 1.3229 + 1.3230 +TabParent* 1.3231 +EventStateManager::GetCrossProcessTarget() 1.3232 +{ 1.3233 + return TabParent::GetIMETabParent(); 1.3234 +} 1.3235 + 1.3236 +bool 1.3237 +EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent) 1.3238 +{ 1.3239 + // Check to see if there is a focused, editable content in chrome, 1.3240 + // in that case, do not forward IME events to content 1.3241 + nsIContent *focusedContent = GetFocusedContent(); 1.3242 + if (focusedContent && focusedContent->IsEditable()) 1.3243 + return false; 1.3244 + return TabParent::GetIMETabParent() != nullptr; 1.3245 +} 1.3246 + 1.3247 +void 1.3248 +EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext) 1.3249 +{ 1.3250 + IMEStateManager::OnDestroyPresContext(aPresContext); 1.3251 + if (mHoverContent) { 1.3252 + // Bug 70855: Presentation is going away, possibly for a reframe. 1.3253 + // Reset the hover state so that if we're recreating the presentation, 1.3254 + // we won't have the old hover state still set in the new presentation, 1.3255 + // as if the new presentation is resized, a new element may be hovered. 1.3256 + SetContentState(nullptr, NS_EVENT_STATE_HOVER); 1.3257 + } 1.3258 + mPointersEnterLeaveHelper.Clear(); 1.3259 +} 1.3260 + 1.3261 +void 1.3262 +EventStateManager::SetPresContext(nsPresContext* aPresContext) 1.3263 +{ 1.3264 + mPresContext = aPresContext; 1.3265 +} 1.3266 + 1.3267 +void 1.3268 +EventStateManager::ClearFrameRefs(nsIFrame* aFrame) 1.3269 +{ 1.3270 + if (aFrame && aFrame == mCurrentTarget) { 1.3271 + mCurrentTargetContent = aFrame->GetContent(); 1.3272 + } 1.3273 +} 1.3274 + 1.3275 +void 1.3276 +EventStateManager::UpdateCursor(nsPresContext* aPresContext, 1.3277 + WidgetEvent* aEvent, 1.3278 + nsIFrame* aTargetFrame, 1.3279 + nsEventStatus* aStatus) 1.3280 +{ 1.3281 + if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) { 1.3282 + return; 1.3283 + } 1.3284 + 1.3285 + int32_t cursor = NS_STYLE_CURSOR_DEFAULT; 1.3286 + imgIContainer* container = nullptr; 1.3287 + bool haveHotspot = false; 1.3288 + float hotspotX = 0.0f, hotspotY = 0.0f; 1.3289 + 1.3290 + //If cursor is locked just use the locked one 1.3291 + if (mLockCursor) { 1.3292 + cursor = mLockCursor; 1.3293 + } 1.3294 + //If not locked, look for correct cursor 1.3295 + else if (aTargetFrame) { 1.3296 + nsIFrame::Cursor framecursor; 1.3297 + nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, 1.3298 + aTargetFrame); 1.3299 + if (NS_FAILED(aTargetFrame->GetCursor(pt, framecursor))) 1.3300 + return; // don't update the cursor if we failed to get it from the frame see bug 118877 1.3301 + cursor = framecursor.mCursor; 1.3302 + container = framecursor.mContainer; 1.3303 + haveHotspot = framecursor.mHaveHotspot; 1.3304 + hotspotX = framecursor.mHotspotX; 1.3305 + hotspotY = framecursor.mHotspotY; 1.3306 + } 1.3307 + 1.3308 + if (Preferences::GetBool("ui.use_activity_cursor", false)) { 1.3309 + // Check whether or not to show the busy cursor 1.3310 + nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell()); 1.3311 + if (!docShell) return; 1.3312 + uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE; 1.3313 + docShell->GetBusyFlags(&busyFlags); 1.3314 + 1.3315 + // Show busy cursor everywhere before page loads 1.3316 + // and just replace the arrow cursor after page starts loading 1.3317 + if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY && 1.3318 + (cursor == NS_STYLE_CURSOR_AUTO || cursor == NS_STYLE_CURSOR_DEFAULT)) 1.3319 + { 1.3320 + cursor = NS_STYLE_CURSOR_SPINNING; 1.3321 + container = nullptr; 1.3322 + } 1.3323 + } 1.3324 + 1.3325 + if (aTargetFrame) { 1.3326 + SetCursor(cursor, container, haveHotspot, hotspotX, hotspotY, 1.3327 + aTargetFrame->GetNearestWidget(), false); 1.3328 + } 1.3329 + 1.3330 + if (mLockCursor || NS_STYLE_CURSOR_AUTO != cursor) { 1.3331 + *aStatus = nsEventStatus_eConsumeDoDefault; 1.3332 + } 1.3333 +} 1.3334 + 1.3335 +nsresult 1.3336 +EventStateManager::SetCursor(int32_t aCursor, imgIContainer* aContainer, 1.3337 + bool aHaveHotspot, 1.3338 + float aHotspotX, float aHotspotY, 1.3339 + nsIWidget* aWidget, bool aLockCursor) 1.3340 +{ 1.3341 + EnsureDocument(mPresContext); 1.3342 + NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE); 1.3343 + sMouseOverDocument = mDocument.get(); 1.3344 + 1.3345 + nsCursor c; 1.3346 + 1.3347 + NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE); 1.3348 + if (aLockCursor) { 1.3349 + if (NS_STYLE_CURSOR_AUTO != aCursor) { 1.3350 + mLockCursor = aCursor; 1.3351 + } 1.3352 + else { 1.3353 + //If cursor style is set to auto we unlock the cursor again. 1.3354 + mLockCursor = 0; 1.3355 + } 1.3356 + } 1.3357 + switch (aCursor) { 1.3358 + default: 1.3359 + case NS_STYLE_CURSOR_AUTO: 1.3360 + case NS_STYLE_CURSOR_DEFAULT: 1.3361 + c = eCursor_standard; 1.3362 + break; 1.3363 + case NS_STYLE_CURSOR_POINTER: 1.3364 + c = eCursor_hyperlink; 1.3365 + break; 1.3366 + case NS_STYLE_CURSOR_CROSSHAIR: 1.3367 + c = eCursor_crosshair; 1.3368 + break; 1.3369 + case NS_STYLE_CURSOR_MOVE: 1.3370 + c = eCursor_move; 1.3371 + break; 1.3372 + case NS_STYLE_CURSOR_TEXT: 1.3373 + c = eCursor_select; 1.3374 + break; 1.3375 + case NS_STYLE_CURSOR_WAIT: 1.3376 + c = eCursor_wait; 1.3377 + break; 1.3378 + case NS_STYLE_CURSOR_HELP: 1.3379 + c = eCursor_help; 1.3380 + break; 1.3381 + case NS_STYLE_CURSOR_N_RESIZE: 1.3382 + c = eCursor_n_resize; 1.3383 + break; 1.3384 + case NS_STYLE_CURSOR_S_RESIZE: 1.3385 + c = eCursor_s_resize; 1.3386 + break; 1.3387 + case NS_STYLE_CURSOR_W_RESIZE: 1.3388 + c = eCursor_w_resize; 1.3389 + break; 1.3390 + case NS_STYLE_CURSOR_E_RESIZE: 1.3391 + c = eCursor_e_resize; 1.3392 + break; 1.3393 + case NS_STYLE_CURSOR_NW_RESIZE: 1.3394 + c = eCursor_nw_resize; 1.3395 + break; 1.3396 + case NS_STYLE_CURSOR_SE_RESIZE: 1.3397 + c = eCursor_se_resize; 1.3398 + break; 1.3399 + case NS_STYLE_CURSOR_NE_RESIZE: 1.3400 + c = eCursor_ne_resize; 1.3401 + break; 1.3402 + case NS_STYLE_CURSOR_SW_RESIZE: 1.3403 + c = eCursor_sw_resize; 1.3404 + break; 1.3405 + case NS_STYLE_CURSOR_COPY: // CSS3 1.3406 + c = eCursor_copy; 1.3407 + break; 1.3408 + case NS_STYLE_CURSOR_ALIAS: 1.3409 + c = eCursor_alias; 1.3410 + break; 1.3411 + case NS_STYLE_CURSOR_CONTEXT_MENU: 1.3412 + c = eCursor_context_menu; 1.3413 + break; 1.3414 + case NS_STYLE_CURSOR_CELL: 1.3415 + c = eCursor_cell; 1.3416 + break; 1.3417 + case NS_STYLE_CURSOR_GRAB: 1.3418 + c = eCursor_grab; 1.3419 + break; 1.3420 + case NS_STYLE_CURSOR_GRABBING: 1.3421 + c = eCursor_grabbing; 1.3422 + break; 1.3423 + case NS_STYLE_CURSOR_SPINNING: 1.3424 + c = eCursor_spinning; 1.3425 + break; 1.3426 + case NS_STYLE_CURSOR_ZOOM_IN: 1.3427 + c = eCursor_zoom_in; 1.3428 + break; 1.3429 + case NS_STYLE_CURSOR_ZOOM_OUT: 1.3430 + c = eCursor_zoom_out; 1.3431 + break; 1.3432 + case NS_STYLE_CURSOR_NOT_ALLOWED: 1.3433 + c = eCursor_not_allowed; 1.3434 + break; 1.3435 + case NS_STYLE_CURSOR_COL_RESIZE: 1.3436 + c = eCursor_col_resize; 1.3437 + break; 1.3438 + case NS_STYLE_CURSOR_ROW_RESIZE: 1.3439 + c = eCursor_row_resize; 1.3440 + break; 1.3441 + case NS_STYLE_CURSOR_NO_DROP: 1.3442 + c = eCursor_no_drop; 1.3443 + break; 1.3444 + case NS_STYLE_CURSOR_VERTICAL_TEXT: 1.3445 + c = eCursor_vertical_text; 1.3446 + break; 1.3447 + case NS_STYLE_CURSOR_ALL_SCROLL: 1.3448 + c = eCursor_all_scroll; 1.3449 + break; 1.3450 + case NS_STYLE_CURSOR_NESW_RESIZE: 1.3451 + c = eCursor_nesw_resize; 1.3452 + break; 1.3453 + case NS_STYLE_CURSOR_NWSE_RESIZE: 1.3454 + c = eCursor_nwse_resize; 1.3455 + break; 1.3456 + case NS_STYLE_CURSOR_NS_RESIZE: 1.3457 + c = eCursor_ns_resize; 1.3458 + break; 1.3459 + case NS_STYLE_CURSOR_EW_RESIZE: 1.3460 + c = eCursor_ew_resize; 1.3461 + break; 1.3462 + case NS_STYLE_CURSOR_NONE: 1.3463 + c = eCursor_none; 1.3464 + break; 1.3465 + } 1.3466 + 1.3467 + // First, try the imgIContainer, if non-null 1.3468 + nsresult rv = NS_ERROR_FAILURE; 1.3469 + if (aContainer) { 1.3470 + uint32_t hotspotX, hotspotY; 1.3471 + 1.3472 + // css3-ui says to use the CSS-specified hotspot if present, 1.3473 + // otherwise use the intrinsic hotspot, otherwise use the top left 1.3474 + // corner. 1.3475 + if (aHaveHotspot) { 1.3476 + int32_t imgWidth, imgHeight; 1.3477 + aContainer->GetWidth(&imgWidth); 1.3478 + aContainer->GetHeight(&imgHeight); 1.3479 + 1.3480 + // XXX std::max(NS_lround(x), 0)? 1.3481 + hotspotX = aHotspotX > 0.0f 1.3482 + ? uint32_t(aHotspotX + 0.5f) : uint32_t(0); 1.3483 + if (hotspotX >= uint32_t(imgWidth)) 1.3484 + hotspotX = imgWidth - 1; 1.3485 + hotspotY = aHotspotY > 0.0f 1.3486 + ? uint32_t(aHotspotY + 0.5f) : uint32_t(0); 1.3487 + if (hotspotY >= uint32_t(imgHeight)) 1.3488 + hotspotY = imgHeight - 1; 1.3489 + } else { 1.3490 + hotspotX = 0; 1.3491 + hotspotY = 0; 1.3492 + nsCOMPtr<nsIProperties> props(do_QueryInterface(aContainer)); 1.3493 + if (props) { 1.3494 + nsCOMPtr<nsISupportsPRUint32> hotspotXWrap, hotspotYWrap; 1.3495 + 1.3496 + props->Get("hotspotX", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotXWrap)); 1.3497 + props->Get("hotspotY", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotYWrap)); 1.3498 + 1.3499 + if (hotspotXWrap) 1.3500 + hotspotXWrap->GetData(&hotspotX); 1.3501 + if (hotspotYWrap) 1.3502 + hotspotYWrap->GetData(&hotspotY); 1.3503 + } 1.3504 + } 1.3505 + 1.3506 + rv = aWidget->SetCursor(aContainer, hotspotX, hotspotY); 1.3507 + } 1.3508 + 1.3509 + if (NS_FAILED(rv)) 1.3510 + aWidget->SetCursor(c); 1.3511 + 1.3512 + return NS_OK; 1.3513 +} 1.3514 + 1.3515 +class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback 1.3516 +{ 1.3517 +public: 1.3518 + ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {} 1.3519 + 1.3520 + virtual void HandleEvent(EventChainPostVisitor& aVisitor) 1.3521 + { 1.3522 + if (aVisitor.mPresContext) { 1.3523 + nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget); 1.3524 + if (frame) { 1.3525 + frame->HandleEvent(aVisitor.mPresContext, 1.3526 + aVisitor.mEvent->AsGUIEvent(), 1.3527 + &aVisitor.mEventStatus); 1.3528 + } 1.3529 + } 1.3530 + } 1.3531 + 1.3532 + nsCOMPtr<nsIContent> mTarget; 1.3533 +}; 1.3534 + 1.3535 +/*static*/ bool 1.3536 +EventStateManager::IsHandlingUserInput() 1.3537 +{ 1.3538 + if (sUserInputEventDepth <= 0) { 1.3539 + return false; 1.3540 + } 1.3541 + 1.3542 + TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout(); 1.3543 + return timeout <= TimeDuration(0) || 1.3544 + (TimeStamp::Now() - sHandlingInputStart) <= timeout; 1.3545 +} 1.3546 + 1.3547 +nsIFrame* 1.3548 +EventStateManager::DispatchMouseOrPointerEvent(WidgetMouseEvent* aMouseEvent, 1.3549 + uint32_t aMessage, 1.3550 + nsIContent* aTargetContent, 1.3551 + nsIContent* aRelatedContent) 1.3552 +{ 1.3553 + // http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods 1.3554 + // "[When the mouse is locked on an element...e]vents that require the concept 1.3555 + // of a mouse cursor must not be dispatched (for example: mouseover, mouseout). 1.3556 + if (sIsPointerLocked && 1.3557 + (aMessage == NS_MOUSELEAVE || 1.3558 + aMessage == NS_MOUSEENTER || 1.3559 + aMessage == NS_MOUSE_ENTER_SYNTH || 1.3560 + aMessage == NS_MOUSE_EXIT_SYNTH)) { 1.3561 + mCurrentTargetContent = nullptr; 1.3562 + nsCOMPtr<Element> pointerLockedElement = 1.3563 + do_QueryReferent(EventStateManager::sPointerLockedElement); 1.3564 + if (!pointerLockedElement) { 1.3565 + NS_WARNING("Should have pointer locked element, but didn't."); 1.3566 + return nullptr; 1.3567 + } 1.3568 + nsCOMPtr<nsIContent> content = do_QueryInterface(pointerLockedElement); 1.3569 + return mPresContext->GetPrimaryFrameFor(content); 1.3570 + } 1.3571 + 1.3572 + nsEventStatus status = nsEventStatus_eIgnore; 1.3573 + nsAutoPtr<WidgetMouseEvent> event; 1.3574 + WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent(); 1.3575 + if (sourcePointer) { 1.3576 + PROFILER_LABEL("Input", "DispatchPointerEvent"); 1.3577 + nsAutoPtr<WidgetPointerEvent> newPointerEvent; 1.3578 + newPointerEvent = 1.3579 + new WidgetPointerEvent(aMouseEvent->mFlags.mIsTrusted, aMessage, 1.3580 + aMouseEvent->widget); 1.3581 + newPointerEvent->isPrimary = sourcePointer->isPrimary; 1.3582 + newPointerEvent->pointerId = sourcePointer->pointerId; 1.3583 + newPointerEvent->width = sourcePointer->width; 1.3584 + newPointerEvent->height = sourcePointer->height; 1.3585 + newPointerEvent->inputSource = sourcePointer->inputSource; 1.3586 + newPointerEvent->relatedTarget = nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId) 1.3587 + ? nullptr 1.3588 + : aRelatedContent; 1.3589 + event = newPointerEvent.forget(); 1.3590 + } else { 1.3591 + PROFILER_LABEL("Input", "DispatchMouseEvent"); 1.3592 + event = 1.3593 + new WidgetMouseEvent(aMouseEvent->mFlags.mIsTrusted, aMessage, 1.3594 + aMouseEvent->widget, WidgetMouseEvent::eReal); 1.3595 + event->relatedTarget = aRelatedContent; 1.3596 + } 1.3597 + event->refPoint = aMouseEvent->refPoint; 1.3598 + event->modifiers = aMouseEvent->modifiers; 1.3599 + event->button = aMouseEvent->button; 1.3600 + event->buttons = aMouseEvent->buttons; 1.3601 + event->pressure = aMouseEvent->pressure; 1.3602 + event->pluginEvent = aMouseEvent->pluginEvent; 1.3603 + event->inputSource = aMouseEvent->inputSource; 1.3604 + 1.3605 + nsWeakFrame previousTarget = mCurrentTarget; 1.3606 + 1.3607 + mCurrentTargetContent = aTargetContent; 1.3608 + 1.3609 + nsIFrame* targetFrame = nullptr; 1.3610 + if (aTargetContent) { 1.3611 + ESMEventCB callback(aTargetContent); 1.3612 + EventDispatcher::Dispatch(aTargetContent, mPresContext, event, nullptr, 1.3613 + &status, &callback); 1.3614 + 1.3615 + // Although the primary frame was checked in event callback, 1.3616 + // it may not be the same object after event dispatching and handling. 1.3617 + // So we need to refetch it. 1.3618 + if (mPresContext) { 1.3619 + targetFrame = mPresContext->GetPrimaryFrameFor(aTargetContent); 1.3620 + } 1.3621 + } 1.3622 + 1.3623 + mCurrentTargetContent = nullptr; 1.3624 + mCurrentTarget = previousTarget; 1.3625 + 1.3626 + return targetFrame; 1.3627 +} 1.3628 + 1.3629 +class EnterLeaveDispatcher 1.3630 +{ 1.3631 +public: 1.3632 + EnterLeaveDispatcher(EventStateManager* aESM, 1.3633 + nsIContent* aTarget, nsIContent* aRelatedTarget, 1.3634 + WidgetMouseEvent* aMouseEvent, uint32_t aType) 1.3635 + : mESM(aESM) 1.3636 + , mMouseEvent(aMouseEvent) 1.3637 + , mType(aType) 1.3638 + { 1.3639 + nsPIDOMWindow* win = 1.3640 + aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr; 1.3641 + if (aMouseEvent->AsPointerEvent() ? win && win->HasPointerEnterLeaveEventListeners() : 1.3642 + win && win->HasMouseEnterLeaveEventListeners()) { 1.3643 + mRelatedTarget = aRelatedTarget ? 1.3644 + aRelatedTarget->FindFirstNonChromeOnlyAccessContent() : nullptr; 1.3645 + nsINode* commonParent = nullptr; 1.3646 + if (aTarget && aRelatedTarget) { 1.3647 + commonParent = 1.3648 + nsContentUtils::GetCommonAncestor(aTarget, aRelatedTarget); 1.3649 + } 1.3650 + nsIContent* current = aTarget; 1.3651 + // Note, it is ok if commonParent is null! 1.3652 + while (current && current != commonParent) { 1.3653 + if (!current->ChromeOnlyAccess()) { 1.3654 + mTargets.AppendObject(current); 1.3655 + } 1.3656 + // mouseenter/leave is fired only on elements. 1.3657 + current = current->GetParent(); 1.3658 + } 1.3659 + } 1.3660 + } 1.3661 + 1.3662 + ~EnterLeaveDispatcher() 1.3663 + { 1.3664 + if (mType == NS_MOUSEENTER || 1.3665 + mType == NS_POINTER_ENTER) { 1.3666 + for (int32_t i = mTargets.Count() - 1; i >= 0; --i) { 1.3667 + mESM->DispatchMouseOrPointerEvent(mMouseEvent, mType, mTargets[i], 1.3668 + mRelatedTarget); 1.3669 + } 1.3670 + } else { 1.3671 + for (int32_t i = 0; i < mTargets.Count(); ++i) { 1.3672 + mESM->DispatchMouseOrPointerEvent(mMouseEvent, mType, mTargets[i], 1.3673 + mRelatedTarget); 1.3674 + } 1.3675 + } 1.3676 + } 1.3677 + 1.3678 + EventStateManager* mESM; 1.3679 + nsCOMArray<nsIContent> mTargets; 1.3680 + nsCOMPtr<nsIContent> mRelatedTarget; 1.3681 + WidgetMouseEvent* mMouseEvent; 1.3682 + uint32_t mType; 1.3683 +}; 1.3684 + 1.3685 +void 1.3686 +EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent, 1.3687 + nsIContent* aMovingInto) 1.3688 +{ 1.3689 + OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent); 1.3690 + 1.3691 + if (!wrapper->mLastOverElement) 1.3692 + return; 1.3693 + // Before firing mouseout, check for recursion 1.3694 + if (wrapper->mLastOverElement == wrapper->mFirstOutEventElement) 1.3695 + return; 1.3696 + 1.3697 + if (wrapper->mLastOverFrame) { 1.3698 + // if the frame is associated with a subdocument, 1.3699 + // tell the subdocument that we're moving out of it 1.3700 + nsSubDocumentFrame* subdocFrame = do_QueryFrame(wrapper->mLastOverFrame.GetFrame()); 1.3701 + if (subdocFrame) { 1.3702 + nsCOMPtr<nsIDocShell> docshell; 1.3703 + subdocFrame->GetDocShell(getter_AddRefs(docshell)); 1.3704 + if (docshell) { 1.3705 + nsRefPtr<nsPresContext> presContext; 1.3706 + docshell->GetPresContext(getter_AddRefs(presContext)); 1.3707 + 1.3708 + if (presContext) { 1.3709 + EventStateManager* kidESM = presContext->EventStateManager(); 1.3710 + // Not moving into any element in this subdocument 1.3711 + kidESM->NotifyMouseOut(aMouseEvent, nullptr); 1.3712 + } 1.3713 + } 1.3714 + } 1.3715 + } 1.3716 + // That could have caused DOM events which could wreak havoc. Reverify 1.3717 + // things and be careful. 1.3718 + if (!wrapper->mLastOverElement) 1.3719 + return; 1.3720 + 1.3721 + // Store the first mouseOut event we fire and don't refire mouseOut 1.3722 + // to that element while the first mouseOut is still ongoing. 1.3723 + wrapper->mFirstOutEventElement = wrapper->mLastOverElement; 1.3724 + 1.3725 + // Don't touch hover state if aMovingInto is non-null. Caller will update 1.3726 + // hover state itself, and we have optimizations for hover switching between 1.3727 + // two nearby elements both deep in the DOM tree that would be defeated by 1.3728 + // switching the hover state to null here. 1.3729 + bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT; 1.3730 + if (!aMovingInto && !isPointer) { 1.3731 + // Unset :hover 1.3732 + SetContentState(nullptr, NS_EVENT_STATE_HOVER); 1.3733 + } 1.3734 + 1.3735 + EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement, 1.3736 + aMovingInto, aMouseEvent, 1.3737 + isPointer ? NS_POINTER_LEAVE : 1.3738 + NS_MOUSELEAVE); 1.3739 + 1.3740 + // Fire mouseout 1.3741 + DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? NS_POINTER_OUT : NS_MOUSE_EXIT_SYNTH, 1.3742 + wrapper->mLastOverElement, aMovingInto); 1.3743 + 1.3744 + wrapper->mLastOverFrame = nullptr; 1.3745 + wrapper->mLastOverElement = nullptr; 1.3746 + 1.3747 + // Turn recursion protection back off 1.3748 + wrapper->mFirstOutEventElement = nullptr; 1.3749 +} 1.3750 + 1.3751 +void 1.3752 +EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent, 1.3753 + nsIContent* aContent) 1.3754 +{ 1.3755 + NS_ASSERTION(aContent, "Mouse must be over something"); 1.3756 + 1.3757 + OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent); 1.3758 + 1.3759 + if (wrapper->mLastOverElement == aContent) 1.3760 + return; 1.3761 + 1.3762 + // Before firing mouseover, check for recursion 1.3763 + if (aContent == wrapper->mFirstOverEventElement) 1.3764 + return; 1.3765 + 1.3766 + // Check to see if we're a subdocument and if so update the parent 1.3767 + // document's ESM state to indicate that the mouse is over the 1.3768 + // content associated with our subdocument. 1.3769 + EnsureDocument(mPresContext); 1.3770 + nsIDocument *parentDoc = mDocument->GetParentDocument(); 1.3771 + if (parentDoc) { 1.3772 + nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument); 1.3773 + if (docContent) { 1.3774 + nsIPresShell *parentShell = parentDoc->GetShell(); 1.3775 + if (parentShell) { 1.3776 + EventStateManager* parentESM = 1.3777 + parentShell->GetPresContext()->EventStateManager(); 1.3778 + parentESM->NotifyMouseOver(aMouseEvent, docContent); 1.3779 + } 1.3780 + } 1.3781 + } 1.3782 + // Firing the DOM event in the parent document could cause all kinds 1.3783 + // of havoc. Reverify and take care. 1.3784 + if (wrapper->mLastOverElement == aContent) 1.3785 + return; 1.3786 + 1.3787 + // Remember mLastOverElement as the related content for the 1.3788 + // DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477. 1.3789 + nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement; 1.3790 + 1.3791 + bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT; 1.3792 + EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement, 1.3793 + aMouseEvent, 1.3794 + isPointer ? NS_POINTER_ENTER : 1.3795 + NS_MOUSEENTER); 1.3796 + 1.3797 + NotifyMouseOut(aMouseEvent, aContent); 1.3798 + 1.3799 + // Store the first mouseOver event we fire and don't refire mouseOver 1.3800 + // to that element while the first mouseOver is still ongoing. 1.3801 + wrapper->mFirstOverEventElement = aContent; 1.3802 + 1.3803 + if (!isPointer) { 1.3804 + SetContentState(aContent, NS_EVENT_STATE_HOVER); 1.3805 + } 1.3806 + 1.3807 + // Fire mouseover 1.3808 + wrapper->mLastOverFrame = 1.3809 + DispatchMouseOrPointerEvent(aMouseEvent, 1.3810 + isPointer ? NS_POINTER_OVER : 1.3811 + NS_MOUSE_ENTER_SYNTH, 1.3812 + aContent, lastOverElement); 1.3813 + wrapper->mLastOverElement = aContent; 1.3814 + 1.3815 + // Turn recursion protection back off 1.3816 + wrapper->mFirstOverEventElement = nullptr; 1.3817 +} 1.3818 + 1.3819 +// Returns the center point of the window's inner content area. 1.3820 +// This is in widget coordinates, i.e. relative to the widget's top 1.3821 +// left corner, not in screen coordinates, the same units that 1.3822 +// UIEvent::refPoint is in. 1.3823 +// 1.3824 +// XXX Hack alert: XXX 1.3825 +// However, we do the computation in integer CSS pixels, NOT device pix, 1.3826 +// in order to fudge around the one-pixel error in innerHeight in fullscreen 1.3827 +// mode (see bug 799523 comment 35, and bug 729011). Using integer CSS pix 1.3828 +// makes us throw away the fractional error that results, rather than having 1.3829 +// it manifest as a potential one-device-pix discrepancy. 1.3830 +static LayoutDeviceIntPoint 1.3831 +GetWindowInnerRectCenter(nsPIDOMWindow* aWindow, 1.3832 + nsIWidget* aWidget, 1.3833 + nsPresContext* aContext) 1.3834 +{ 1.3835 + NS_ENSURE_TRUE(aWindow && aWidget && aContext, LayoutDeviceIntPoint(0, 0)); 1.3836 + 1.3837 + float cssInnerX = 0.0; 1.3838 + aWindow->GetMozInnerScreenX(&cssInnerX); 1.3839 + int32_t innerX = int32_t(NS_round(cssInnerX)); 1.3840 + 1.3841 + float cssInnerY = 0.0; 1.3842 + aWindow->GetMozInnerScreenY(&cssInnerY); 1.3843 + int32_t innerY = int32_t(NS_round(cssInnerY)); 1.3844 + 1.3845 + int32_t innerWidth = 0; 1.3846 + aWindow->GetInnerWidth(&innerWidth); 1.3847 + 1.3848 + int32_t innerHeight = 0; 1.3849 + aWindow->GetInnerHeight(&innerHeight); 1.3850 + 1.3851 + nsIntRect screen; 1.3852 + aWidget->GetScreenBounds(screen); 1.3853 + 1.3854 + int32_t cssScreenX = aContext->DevPixelsToIntCSSPixels(screen.x); 1.3855 + int32_t cssScreenY = aContext->DevPixelsToIntCSSPixels(screen.y); 1.3856 + 1.3857 + return LayoutDeviceIntPoint( 1.3858 + aContext->CSSPixelsToDevPixels(innerX - cssScreenX + innerWidth / 2), 1.3859 + aContext->CSSPixelsToDevPixels(innerY - cssScreenY + innerHeight / 2)); 1.3860 +} 1.3861 + 1.3862 +void 1.3863 +EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) 1.3864 +{ 1.3865 + EnsureDocument(mPresContext); 1.3866 + if (!mDocument) 1.3867 + return; 1.3868 + 1.3869 + // Hold onto old target content through the event and reset after. 1.3870 + nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent; 1.3871 + 1.3872 + switch(aMouseEvent->message) { 1.3873 + case NS_MOUSE_MOVE: 1.3874 + { 1.3875 + // Mouse movement is reported on the MouseEvent.movement{X,Y} fields. 1.3876 + // Movement is calculated in UIEvent::GetMovementPoint() as: 1.3877 + // previous_mousemove_refPoint - current_mousemove_refPoint. 1.3878 + if (sIsPointerLocked && aMouseEvent->widget) { 1.3879 + // The pointer is locked. If the pointer is not located at the center of 1.3880 + // the window, dispatch a synthetic mousemove to return the pointer there. 1.3881 + // Doing this between "real" pointer moves gives the impression that the 1.3882 + // (locked) pointer can continue moving and won't stop at the screen 1.3883 + // boundary. We cancel the synthetic event so that we don't end up 1.3884 + // dispatching the centering move event to content. 1.3885 + LayoutDeviceIntPoint center = 1.3886 + GetWindowInnerRectCenter(mDocument->GetWindow(), aMouseEvent->widget, 1.3887 + mPresContext); 1.3888 + aMouseEvent->lastRefPoint = center; 1.3889 + if (aMouseEvent->refPoint != center) { 1.3890 + // Mouse move doesn't finish at the center of the window. Dispatch a 1.3891 + // synthetic native mouse event to move the pointer back to the center 1.3892 + // of the window, to faciliate more movement. But first, record that 1.3893 + // we've dispatched a synthetic mouse movement, so we can cancel it 1.3894 + // in the other branch here. 1.3895 + sSynthCenteringPoint = center; 1.3896 + aMouseEvent->widget->SynthesizeNativeMouseMove( 1.3897 + LayoutDeviceIntPoint::ToUntyped(center) + 1.3898 + aMouseEvent->widget->WidgetToScreenOffset()); 1.3899 + } else if (aMouseEvent->refPoint == sSynthCenteringPoint) { 1.3900 + // This is the "synthetic native" event we dispatched to re-center the 1.3901 + // pointer. Cancel it so we don't expose the centering move to content. 1.3902 + aMouseEvent->mFlags.mPropagationStopped = true; 1.3903 + // Clear sSynthCenteringPoint so we don't cancel other events 1.3904 + // targeted at the center. 1.3905 + sSynthCenteringPoint = kInvalidRefPoint; 1.3906 + } 1.3907 + } else if (sLastRefPoint == kInvalidRefPoint) { 1.3908 + // We don't have a valid previous mousemove refPoint. This is either 1.3909 + // the first move we've encountered, or the mouse has just re-entered 1.3910 + // the application window. We should report (0,0) movement for this 1.3911 + // case, so make the current and previous refPoints the same. 1.3912 + aMouseEvent->lastRefPoint = aMouseEvent->refPoint; 1.3913 + } else { 1.3914 + aMouseEvent->lastRefPoint = sLastRefPoint; 1.3915 + } 1.3916 + 1.3917 + // Update the last known refPoint with the current refPoint. 1.3918 + sLastRefPoint = aMouseEvent->refPoint; 1.3919 + 1.3920 + } 1.3921 + case NS_POINTER_MOVE: 1.3922 + case NS_POINTER_DOWN: 1.3923 + { 1.3924 + // Get the target content target (mousemove target == mouseover target) 1.3925 + nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent); 1.3926 + if (!targetElement) { 1.3927 + // We're always over the document root, even if we're only 1.3928 + // over dead space in a page (whose frame is not associated with 1.3929 + // any content) or in print preview dead space 1.3930 + targetElement = mDocument->GetRootElement(); 1.3931 + } 1.3932 + if (targetElement) { 1.3933 + NotifyMouseOver(aMouseEvent, targetElement); 1.3934 + } 1.3935 + } 1.3936 + break; 1.3937 + case NS_POINTER_UP: 1.3938 + { 1.3939 + // Get the target content target (mousemove target == mouseover target) 1.3940 + nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent); 1.3941 + if (!targetElement) { 1.3942 + // We're always over the document root, even if we're only 1.3943 + // over dead space in a page (whose frame is not associated with 1.3944 + // any content) or in print preview dead space 1.3945 + targetElement = mDocument->GetRootElement(); 1.3946 + } 1.3947 + if (targetElement) { 1.3948 + OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent); 1.3949 + if (helper) { 1.3950 + helper->mLastOverElement = targetElement; 1.3951 + } 1.3952 + NotifyMouseOut(aMouseEvent, nullptr); 1.3953 + } 1.3954 + } 1.3955 + break; 1.3956 + case NS_POINTER_LEAVE: 1.3957 + case NS_POINTER_CANCEL: 1.3958 + case NS_MOUSE_EXIT: 1.3959 + { 1.3960 + // This is actually the window mouse exit or pointer leave event. We're not moving 1.3961 + // into any new element. 1.3962 + 1.3963 + OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent); 1.3964 + if (helper->mLastOverFrame && 1.3965 + nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) != 1.3966 + nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) { 1.3967 + // the Mouse/PointerOut event widget doesn't have same top widget with 1.3968 + // mLastOverFrame, it's a spurious event for mLastOverFrame 1.3969 + break; 1.3970 + } 1.3971 + 1.3972 + // Reset sLastRefPoint, so that we'll know not to report any 1.3973 + // movement the next time we re-enter the window. 1.3974 + sLastRefPoint = kInvalidRefPoint; 1.3975 + 1.3976 + NotifyMouseOut(aMouseEvent, nullptr); 1.3977 + } 1.3978 + break; 1.3979 + } 1.3980 + 1.3981 + // reset mCurretTargetContent to what it was 1.3982 + mCurrentTargetContent = targetBeforeEvent; 1.3983 +} 1.3984 + 1.3985 +OverOutElementsWrapper* 1.3986 +EventStateManager::GetWrapperByEventID(WidgetMouseEvent* aEvent) 1.3987 +{ 1.3988 + WidgetPointerEvent* pointer = aEvent->AsPointerEvent(); 1.3989 + if (!pointer) { 1.3990 + MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr); 1.3991 + if (!mMouseEnterLeaveHelper) { 1.3992 + mMouseEnterLeaveHelper = new OverOutElementsWrapper(); 1.3993 + } 1.3994 + return mMouseEnterLeaveHelper; 1.3995 + } 1.3996 + nsRefPtr<OverOutElementsWrapper> helper; 1.3997 + if (!mPointersEnterLeaveHelper.Get(pointer->pointerId, getter_AddRefs(helper))) { 1.3998 + helper = new OverOutElementsWrapper(); 1.3999 + mPointersEnterLeaveHelper.Put(pointer->pointerId, helper); 1.4000 + } 1.4001 + 1.4002 + return helper; 1.4003 +} 1.4004 + 1.4005 +void 1.4006 +EventStateManager::SetPointerLock(nsIWidget* aWidget, 1.4007 + nsIContent* aElement) 1.4008 +{ 1.4009 + // NOTE: aElement will be nullptr when unlocking. 1.4010 + sIsPointerLocked = !!aElement; 1.4011 + 1.4012 + if (!aWidget) { 1.4013 + return; 1.4014 + } 1.4015 + 1.4016 + // Reset mouse wheel transaction 1.4017 + WheelTransaction::EndTransaction(); 1.4018 + 1.4019 + // Deal with DnD events 1.4020 + nsCOMPtr<nsIDragService> dragService = 1.4021 + do_GetService("@mozilla.org/widget/dragservice;1"); 1.4022 + 1.4023 + if (sIsPointerLocked) { 1.4024 + // Store the last known ref point so we can reposition the pointer after unlock. 1.4025 + mPreLockPoint = sLastRefPoint; 1.4026 + 1.4027 + // Fire a synthetic mouse move to ensure event state is updated. We first 1.4028 + // set the mouse to the center of the window, so that the mouse event 1.4029 + // doesn't report any movement. 1.4030 + sLastRefPoint = GetWindowInnerRectCenter(aElement->OwnerDoc()->GetWindow(), 1.4031 + aWidget, 1.4032 + mPresContext); 1.4033 + aWidget->SynthesizeNativeMouseMove( 1.4034 + LayoutDeviceIntPoint::ToUntyped(sLastRefPoint) + aWidget->WidgetToScreenOffset()); 1.4035 + 1.4036 + // Retarget all events to this element via capture. 1.4037 + nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK); 1.4038 + 1.4039 + // Suppress DnD 1.4040 + if (dragService) { 1.4041 + dragService->Suppress(); 1.4042 + } 1.4043 + } else { 1.4044 + // Unlocking, so return pointer to the original position by firing a 1.4045 + // synthetic mouse event. We first reset sLastRefPoint to its 1.4046 + // pre-pointerlock position, so that the synthetic mouse event reports 1.4047 + // no movement. 1.4048 + sLastRefPoint = mPreLockPoint; 1.4049 + aWidget->SynthesizeNativeMouseMove( 1.4050 + LayoutDeviceIntPoint::ToUntyped(mPreLockPoint) + aWidget->WidgetToScreenOffset()); 1.4051 + 1.4052 + // Don't retarget events to this element any more. 1.4053 + nsIPresShell::SetCapturingContent(nullptr, CAPTURE_POINTERLOCK); 1.4054 + 1.4055 + // Unsuppress DnD 1.4056 + if (dragService) { 1.4057 + dragService->Unsuppress(); 1.4058 + } 1.4059 + } 1.4060 +} 1.4061 + 1.4062 +void 1.4063 +EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext, 1.4064 + WidgetDragEvent* aDragEvent) 1.4065 +{ 1.4066 + //Hold onto old target content through the event and reset after. 1.4067 + nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent; 1.4068 + 1.4069 + switch(aDragEvent->message) { 1.4070 + case NS_DRAGDROP_OVER: 1.4071 + { 1.4072 + // when dragging from one frame to another, events are fired in the 1.4073 + // order: dragexit, dragenter, dragleave 1.4074 + if (sLastDragOverFrame != mCurrentTarget) { 1.4075 + //We'll need the content, too, to check if it changed separately from the frames. 1.4076 + nsCOMPtr<nsIContent> lastContent; 1.4077 + nsCOMPtr<nsIContent> targetContent; 1.4078 + mCurrentTarget->GetContentForEvent(aDragEvent, 1.4079 + getter_AddRefs(targetContent)); 1.4080 + 1.4081 + if (sLastDragOverFrame) { 1.4082 + //The frame has changed but the content may not have. Check before dispatching to content 1.4083 + sLastDragOverFrame->GetContentForEvent(aDragEvent, 1.4084 + getter_AddRefs(lastContent)); 1.4085 + 1.4086 + FireDragEnterOrExit(sLastDragOverFrame->PresContext(), 1.4087 + aDragEvent, NS_DRAGDROP_EXIT_SYNTH, 1.4088 + targetContent, lastContent, sLastDragOverFrame); 1.4089 + } 1.4090 + 1.4091 + FireDragEnterOrExit(aPresContext, aDragEvent, NS_DRAGDROP_ENTER, 1.4092 + lastContent, targetContent, mCurrentTarget); 1.4093 + 1.4094 + if (sLastDragOverFrame) { 1.4095 + FireDragEnterOrExit(sLastDragOverFrame->PresContext(), 1.4096 + aDragEvent, NS_DRAGDROP_LEAVE_SYNTH, 1.4097 + targetContent, lastContent, sLastDragOverFrame); 1.4098 + } 1.4099 + 1.4100 + sLastDragOverFrame = mCurrentTarget; 1.4101 + } 1.4102 + } 1.4103 + break; 1.4104 + 1.4105 + case NS_DRAGDROP_EXIT: 1.4106 + { 1.4107 + //This is actually the window mouse exit event. 1.4108 + if (sLastDragOverFrame) { 1.4109 + nsCOMPtr<nsIContent> lastContent; 1.4110 + sLastDragOverFrame->GetContentForEvent(aDragEvent, 1.4111 + getter_AddRefs(lastContent)); 1.4112 + 1.4113 + nsRefPtr<nsPresContext> lastDragOverFramePresContext = sLastDragOverFrame->PresContext(); 1.4114 + FireDragEnterOrExit(lastDragOverFramePresContext, 1.4115 + aDragEvent, NS_DRAGDROP_EXIT_SYNTH, 1.4116 + nullptr, lastContent, sLastDragOverFrame); 1.4117 + FireDragEnterOrExit(lastDragOverFramePresContext, 1.4118 + aDragEvent, NS_DRAGDROP_LEAVE_SYNTH, 1.4119 + nullptr, lastContent, sLastDragOverFrame); 1.4120 + 1.4121 + sLastDragOverFrame = nullptr; 1.4122 + } 1.4123 + } 1.4124 + break; 1.4125 + } 1.4126 + 1.4127 + //reset mCurretTargetContent to what it was 1.4128 + mCurrentTargetContent = targetBeforeEvent; 1.4129 + 1.4130 + // Now flush all pending notifications, for better responsiveness. 1.4131 + FlushPendingEvents(aPresContext); 1.4132 +} 1.4133 + 1.4134 +void 1.4135 +EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext, 1.4136 + WidgetDragEvent* aDragEvent, 1.4137 + uint32_t aMsg, 1.4138 + nsIContent* aRelatedTarget, 1.4139 + nsIContent* aTargetContent, 1.4140 + nsWeakFrame& aTargetFrame) 1.4141 +{ 1.4142 + nsEventStatus status = nsEventStatus_eIgnore; 1.4143 + WidgetDragEvent event(aDragEvent->mFlags.mIsTrusted, aMsg, 1.4144 + aDragEvent->widget); 1.4145 + event.refPoint = aDragEvent->refPoint; 1.4146 + event.modifiers = aDragEvent->modifiers; 1.4147 + event.buttons = aDragEvent->buttons; 1.4148 + event.relatedTarget = aRelatedTarget; 1.4149 + event.inputSource = aDragEvent->inputSource; 1.4150 + 1.4151 + mCurrentTargetContent = aTargetContent; 1.4152 + 1.4153 + if (aTargetContent != aRelatedTarget) { 1.4154 + //XXX This event should still go somewhere!! 1.4155 + if (aTargetContent) { 1.4156 + EventDispatcher::Dispatch(aTargetContent, aPresContext, &event, 1.4157 + nullptr, &status); 1.4158 + } 1.4159 + 1.4160 + // adjust the drag hover if the dragenter event was cancelled or this is a drag exit 1.4161 + if (status == nsEventStatus_eConsumeNoDefault || aMsg == NS_DRAGDROP_EXIT) 1.4162 + SetContentState((aMsg == NS_DRAGDROP_ENTER) ? aTargetContent : nullptr, 1.4163 + NS_EVENT_STATE_DRAGOVER); 1.4164 + 1.4165 + // collect any changes to moz cursor settings stored in the event's 1.4166 + // data transfer. 1.4167 + if (aMsg == NS_DRAGDROP_LEAVE_SYNTH || aMsg == NS_DRAGDROP_EXIT_SYNTH || 1.4168 + aMsg == NS_DRAGDROP_ENTER) 1.4169 + UpdateDragDataTransfer(&event); 1.4170 + } 1.4171 + 1.4172 + // Finally dispatch the event to the frame 1.4173 + if (aTargetFrame) 1.4174 + aTargetFrame->HandleEvent(aPresContext, &event, &status); 1.4175 +} 1.4176 + 1.4177 +void 1.4178 +EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent) 1.4179 +{ 1.4180 + NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!"); 1.4181 + if (!dragEvent->dataTransfer) 1.4182 + return; 1.4183 + 1.4184 + nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); 1.4185 + 1.4186 + if (dragSession) { 1.4187 + // the initial dataTransfer is the one from the dragstart event that 1.4188 + // was set on the dragSession when the drag began. 1.4189 + nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer; 1.4190 + dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer)); 1.4191 + if (initialDataTransfer) { 1.4192 + // retrieve the current moz cursor setting and save it. 1.4193 + nsAutoString mozCursor; 1.4194 + dragEvent->dataTransfer->GetMozCursor(mozCursor); 1.4195 + initialDataTransfer->SetMozCursor(mozCursor); 1.4196 + } 1.4197 + } 1.4198 +} 1.4199 + 1.4200 +nsresult 1.4201 +EventStateManager::SetClickCount(nsPresContext* aPresContext, 1.4202 + WidgetMouseEvent* aEvent, 1.4203 + nsEventStatus* aStatus) 1.4204 +{ 1.4205 + nsCOMPtr<nsIContent> mouseContent; 1.4206 + nsIContent* mouseContentParent = nullptr; 1.4207 + mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent)); 1.4208 + if (mouseContent) { 1.4209 + if (mouseContent->IsNodeOfType(nsINode::eTEXT)) { 1.4210 + mouseContent = mouseContent->GetParent(); 1.4211 + } 1.4212 + if (mouseContent && mouseContent->IsRootOfNativeAnonymousSubtree()) { 1.4213 + mouseContentParent = mouseContent->GetParent(); 1.4214 + } 1.4215 + } 1.4216 + 1.4217 + switch (aEvent->button) { 1.4218 + case WidgetMouseEvent::eLeftButton: 1.4219 + if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { 1.4220 + mLastLeftMouseDownContent = mouseContent; 1.4221 + mLastLeftMouseDownContentParent = mouseContentParent; 1.4222 + } else if (aEvent->message == NS_MOUSE_BUTTON_UP) { 1.4223 + if (mLastLeftMouseDownContent == mouseContent || 1.4224 + mLastLeftMouseDownContentParent == mouseContent || 1.4225 + mLastLeftMouseDownContent == mouseContentParent) { 1.4226 + aEvent->clickCount = mLClickCount; 1.4227 + mLClickCount = 0; 1.4228 + } else { 1.4229 + aEvent->clickCount = 0; 1.4230 + } 1.4231 + mLastLeftMouseDownContent = nullptr; 1.4232 + mLastLeftMouseDownContentParent = nullptr; 1.4233 + } 1.4234 + break; 1.4235 + 1.4236 + case WidgetMouseEvent::eMiddleButton: 1.4237 + if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { 1.4238 + mLastMiddleMouseDownContent = mouseContent; 1.4239 + mLastMiddleMouseDownContentParent = mouseContentParent; 1.4240 + } else if (aEvent->message == NS_MOUSE_BUTTON_UP) { 1.4241 + if (mLastMiddleMouseDownContent == mouseContent || 1.4242 + mLastMiddleMouseDownContentParent == mouseContent || 1.4243 + mLastMiddleMouseDownContent == mouseContentParent) { 1.4244 + aEvent->clickCount = mMClickCount; 1.4245 + mMClickCount = 0; 1.4246 + } else { 1.4247 + aEvent->clickCount = 0; 1.4248 + } 1.4249 + mLastMiddleMouseDownContent = nullptr; 1.4250 + mLastMiddleMouseDownContentParent = nullptr; 1.4251 + } 1.4252 + break; 1.4253 + 1.4254 + case WidgetMouseEvent::eRightButton: 1.4255 + if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { 1.4256 + mLastRightMouseDownContent = mouseContent; 1.4257 + mLastRightMouseDownContentParent = mouseContentParent; 1.4258 + } else if (aEvent->message == NS_MOUSE_BUTTON_UP) { 1.4259 + if (mLastRightMouseDownContent == mouseContent || 1.4260 + mLastRightMouseDownContentParent == mouseContent || 1.4261 + mLastRightMouseDownContent == mouseContentParent) { 1.4262 + aEvent->clickCount = mRClickCount; 1.4263 + mRClickCount = 0; 1.4264 + } else { 1.4265 + aEvent->clickCount = 0; 1.4266 + } 1.4267 + mLastRightMouseDownContent = nullptr; 1.4268 + mLastRightMouseDownContentParent = nullptr; 1.4269 + } 1.4270 + break; 1.4271 + } 1.4272 + 1.4273 + return NS_OK; 1.4274 +} 1.4275 + 1.4276 +nsresult 1.4277 +EventStateManager::CheckForAndDispatchClick(nsPresContext* aPresContext, 1.4278 + WidgetMouseEvent* aEvent, 1.4279 + nsEventStatus* aStatus) 1.4280 +{ 1.4281 + nsresult ret = NS_OK; 1.4282 + 1.4283 + //If mouse is still over same element, clickcount will be > 1. 1.4284 + //If it has moved it will be zero, so no click. 1.4285 + if (0 != aEvent->clickCount) { 1.4286 + //Check that the window isn't disabled before firing a click 1.4287 + //(see bug 366544). 1.4288 + if (aEvent->widget && !aEvent->widget->IsEnabled()) { 1.4289 + return ret; 1.4290 + } 1.4291 + //fire click 1.4292 + bool notDispatchToContents = 1.4293 + (aEvent->button == WidgetMouseEvent::eMiddleButton || 1.4294 + aEvent->button == WidgetMouseEvent::eRightButton); 1.4295 + 1.4296 + WidgetMouseEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK, 1.4297 + aEvent->widget, WidgetMouseEvent::eReal); 1.4298 + event.refPoint = aEvent->refPoint; 1.4299 + event.clickCount = aEvent->clickCount; 1.4300 + event.modifiers = aEvent->modifiers; 1.4301 + event.buttons = aEvent->buttons; 1.4302 + event.time = aEvent->time; 1.4303 + event.mFlags.mNoContentDispatch = notDispatchToContents; 1.4304 + event.button = aEvent->button; 1.4305 + event.inputSource = aEvent->inputSource; 1.4306 + 1.4307 + nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell(); 1.4308 + if (presShell) { 1.4309 + nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent); 1.4310 + if (!mouseContent && !mCurrentTarget) { 1.4311 + return NS_OK; 1.4312 + } 1.4313 + 1.4314 + // HandleEvent clears out mCurrentTarget which we might need again 1.4315 + nsWeakFrame currentTarget = mCurrentTarget; 1.4316 + ret = presShell->HandleEventWithTarget(&event, currentTarget, 1.4317 + mouseContent, aStatus); 1.4318 + if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2) { 1.4319 + //fire double click 1.4320 + WidgetMouseEvent event2(aEvent->mFlags.mIsTrusted, NS_MOUSE_DOUBLECLICK, 1.4321 + aEvent->widget, WidgetMouseEvent::eReal); 1.4322 + event2.refPoint = aEvent->refPoint; 1.4323 + event2.clickCount = aEvent->clickCount; 1.4324 + event2.modifiers = aEvent->modifiers; 1.4325 + event2.buttons = aEvent->buttons; 1.4326 + event2.mFlags.mNoContentDispatch = notDispatchToContents; 1.4327 + event2.button = aEvent->button; 1.4328 + event2.inputSource = aEvent->inputSource; 1.4329 + 1.4330 + ret = presShell->HandleEventWithTarget(&event2, currentTarget, 1.4331 + mouseContent, aStatus); 1.4332 + } 1.4333 + } 1.4334 + } 1.4335 + return ret; 1.4336 +} 1.4337 + 1.4338 +nsIFrame* 1.4339 +EventStateManager::GetEventTarget() 1.4340 +{ 1.4341 + nsIPresShell *shell; 1.4342 + if (mCurrentTarget || 1.4343 + !mPresContext || 1.4344 + !(shell = mPresContext->GetPresShell())) { 1.4345 + return mCurrentTarget; 1.4346 + } 1.4347 + 1.4348 + if (mCurrentTargetContent) { 1.4349 + mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent); 1.4350 + if (mCurrentTarget) { 1.4351 + return mCurrentTarget; 1.4352 + } 1.4353 + } 1.4354 + 1.4355 + nsIFrame* frame = shell->GetEventTargetFrame(); 1.4356 + return (mCurrentTarget = frame); 1.4357 +} 1.4358 + 1.4359 +already_AddRefed<nsIContent> 1.4360 +EventStateManager::GetEventTargetContent(WidgetEvent* aEvent) 1.4361 +{ 1.4362 + if (aEvent && 1.4363 + (aEvent->message == NS_FOCUS_CONTENT || 1.4364 + aEvent->message == NS_BLUR_CONTENT)) { 1.4365 + nsCOMPtr<nsIContent> content = GetFocusedContent(); 1.4366 + return content.forget(); 1.4367 + } 1.4368 + 1.4369 + if (mCurrentTargetContent) { 1.4370 + nsCOMPtr<nsIContent> content = mCurrentTargetContent; 1.4371 + return content.forget(); 1.4372 + } 1.4373 + 1.4374 + nsCOMPtr<nsIContent> content; 1.4375 + 1.4376 + nsIPresShell *presShell = mPresContext->GetPresShell(); 1.4377 + if (presShell) { 1.4378 + content = presShell->GetEventTargetContent(aEvent); 1.4379 + } 1.4380 + 1.4381 + // Some events here may set mCurrentTarget but not set the corresponding 1.4382 + // event target in the PresShell. 1.4383 + if (!content && mCurrentTarget) { 1.4384 + mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content)); 1.4385 + } 1.4386 + 1.4387 + return content.forget(); 1.4388 +} 1.4389 + 1.4390 +static Element* 1.4391 +GetLabelTarget(nsIContent* aPossibleLabel) 1.4392 +{ 1.4393 + mozilla::dom::HTMLLabelElement* label = 1.4394 + mozilla::dom::HTMLLabelElement::FromContent(aPossibleLabel); 1.4395 + if (!label) 1.4396 + return nullptr; 1.4397 + 1.4398 + return label->GetLabeledElement(); 1.4399 +} 1.4400 + 1.4401 +static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2) 1.4402 +{ 1.4403 + // Find closest common ancestor 1.4404 + if (aNode1 && aNode2) { 1.4405 + // Find the nearest common ancestor by counting the distance to the 1.4406 + // root and then walking up again, in pairs. 1.4407 + int32_t offset = 0; 1.4408 + nsIContent *anc1 = aNode1; 1.4409 + for (;;) { 1.4410 + ++offset; 1.4411 + nsIContent* parent = anc1->GetParent(); 1.4412 + if (!parent) 1.4413 + break; 1.4414 + anc1 = parent; 1.4415 + } 1.4416 + nsIContent *anc2 = aNode2; 1.4417 + for (;;) { 1.4418 + --offset; 1.4419 + nsIContent* parent = anc2->GetParent(); 1.4420 + if (!parent) 1.4421 + break; 1.4422 + anc2 = parent; 1.4423 + } 1.4424 + if (anc1 == anc2) { 1.4425 + anc1 = aNode1; 1.4426 + anc2 = aNode2; 1.4427 + while (offset > 0) { 1.4428 + anc1 = anc1->GetParent(); 1.4429 + --offset; 1.4430 + } 1.4431 + while (offset < 0) { 1.4432 + anc2 = anc2->GetParent(); 1.4433 + ++offset; 1.4434 + } 1.4435 + while (anc1 != anc2) { 1.4436 + anc1 = anc1->GetParent(); 1.4437 + anc2 = anc2->GetParent(); 1.4438 + } 1.4439 + return anc1; 1.4440 + } 1.4441 + } 1.4442 + return nullptr; 1.4443 +} 1.4444 + 1.4445 +static Element* 1.4446 +GetParentElement(Element* aElement) 1.4447 +{ 1.4448 + nsIContent* p = aElement->GetParent(); 1.4449 + return (p && p->IsElement()) ? p->AsElement() : nullptr; 1.4450 +} 1.4451 + 1.4452 +/* static */ 1.4453 +void 1.4454 +EventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen) 1.4455 +{ 1.4456 + DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen); 1.4457 + Element* ancestor = aElement; 1.4458 + while ((ancestor = GetParentElement(ancestor))) { 1.4459 + DoStateChange(ancestor, NS_EVENT_STATE_FULL_SCREEN_ANCESTOR, aIsFullScreen); 1.4460 + } 1.4461 +} 1.4462 + 1.4463 +/* static */ 1.4464 +inline void 1.4465 +EventStateManager::DoStateChange(Element* aElement, EventStates aState, 1.4466 + bool aAddState) 1.4467 +{ 1.4468 + if (aAddState) { 1.4469 + aElement->AddStates(aState); 1.4470 + } else { 1.4471 + aElement->RemoveStates(aState); 1.4472 + } 1.4473 +} 1.4474 + 1.4475 +/* static */ 1.4476 +inline void 1.4477 +EventStateManager::DoStateChange(nsIContent* aContent, EventStates aState, 1.4478 + bool aStateAdded) 1.4479 +{ 1.4480 + if (aContent->IsElement()) { 1.4481 + DoStateChange(aContent->AsElement(), aState, aStateAdded); 1.4482 + } 1.4483 +} 1.4484 + 1.4485 +/* static */ 1.4486 +void 1.4487 +EventStateManager::UpdateAncestorState(nsIContent* aStartNode, 1.4488 + nsIContent* aStopBefore, 1.4489 + EventStates aState, 1.4490 + bool aAddState) 1.4491 +{ 1.4492 + for (; aStartNode && aStartNode != aStopBefore; 1.4493 + aStartNode = aStartNode->GetParent()) { 1.4494 + // We might be starting with a non-element (e.g. a text node) and 1.4495 + // if someone is doing something weird might be ending with a 1.4496 + // non-element too (e.g. a document fragment) 1.4497 + if (!aStartNode->IsElement()) { 1.4498 + continue; 1.4499 + } 1.4500 + Element* element = aStartNode->AsElement(); 1.4501 + DoStateChange(element, aState, aAddState); 1.4502 + Element* labelTarget = GetLabelTarget(element); 1.4503 + if (labelTarget) { 1.4504 + DoStateChange(labelTarget, aState, aAddState); 1.4505 + } 1.4506 + } 1.4507 + 1.4508 + if (aAddState) { 1.4509 + // We might be in a situation where a node was in hover both 1.4510 + // because it was hovered and because the label for it was 1.4511 + // hovered, and while we stopped hovering the node the label is 1.4512 + // still hovered. Or we might have had two nested labels for the 1.4513 + // same node, and while one is no longer hovered the other still 1.4514 + // is. In that situation, the label that's still hovered will be 1.4515 + // aStopBefore or some ancestor of it, and the call we just made 1.4516 + // to UpdateAncestorState with aAddState = false would have 1.4517 + // removed the hover state from the node. But the node should 1.4518 + // still be in hover state. To handle this situation we need to 1.4519 + // keep walking up the tree and any time we find a label mark its 1.4520 + // corresponding node as still in our state. 1.4521 + for ( ; aStartNode; aStartNode = aStartNode->GetParent()) { 1.4522 + if (!aStartNode->IsElement()) { 1.4523 + continue; 1.4524 + } 1.4525 + 1.4526 + Element* labelTarget = GetLabelTarget(aStartNode->AsElement()); 1.4527 + if (labelTarget && !labelTarget->State().HasState(aState)) { 1.4528 + DoStateChange(labelTarget, aState, true); 1.4529 + } 1.4530 + } 1.4531 + } 1.4532 +} 1.4533 + 1.4534 +bool 1.4535 +EventStateManager::SetContentState(nsIContent* aContent, EventStates aState) 1.4536 +{ 1.4537 + // We manage 4 states here: ACTIVE, HOVER, DRAGOVER, URLTARGET 1.4538 + // The input must be exactly one of them. 1.4539 + NS_PRECONDITION(aState == NS_EVENT_STATE_ACTIVE || 1.4540 + aState == NS_EVENT_STATE_HOVER || 1.4541 + aState == NS_EVENT_STATE_DRAGOVER || 1.4542 + aState == NS_EVENT_STATE_URLTARGET, 1.4543 + "Unexpected state"); 1.4544 + 1.4545 + nsCOMPtr<nsIContent> notifyContent1; 1.4546 + nsCOMPtr<nsIContent> notifyContent2; 1.4547 + bool updateAncestors; 1.4548 + 1.4549 + if (aState == NS_EVENT_STATE_HOVER || aState == NS_EVENT_STATE_ACTIVE) { 1.4550 + // Hover and active are hierarchical 1.4551 + updateAncestors = true; 1.4552 + 1.4553 + // check to see that this state is allowed by style. Check dragover too? 1.4554 + // XXX Is this even what we want? 1.4555 + if (mCurrentTarget) 1.4556 + { 1.4557 + const nsStyleUserInterface* ui = mCurrentTarget->StyleUserInterface(); 1.4558 + if (ui->mUserInput == NS_STYLE_USER_INPUT_NONE) 1.4559 + return false; 1.4560 + } 1.4561 + 1.4562 + if (aState == NS_EVENT_STATE_ACTIVE) { 1.4563 + if (aContent != mActiveContent) { 1.4564 + notifyContent1 = aContent; 1.4565 + notifyContent2 = mActiveContent; 1.4566 + mActiveContent = aContent; 1.4567 + } 1.4568 + } else { 1.4569 + NS_ASSERTION(aState == NS_EVENT_STATE_HOVER, "How did that happen?"); 1.4570 + nsIContent* newHover; 1.4571 + 1.4572 + if (mPresContext->IsDynamic()) { 1.4573 + newHover = aContent; 1.4574 + } else { 1.4575 + NS_ASSERTION(!aContent || 1.4576 + aContent->GetCurrentDoc() == mPresContext->PresShell()->GetDocument(), 1.4577 + "Unexpected document"); 1.4578 + nsIFrame *frame = aContent ? aContent->GetPrimaryFrame() : nullptr; 1.4579 + if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) { 1.4580 + // The scrollbars of viewport should not ignore the hover state. 1.4581 + // Because they are *not* the content of the web page. 1.4582 + newHover = aContent; 1.4583 + } else { 1.4584 + // All contents of the web page should ignore the hover state. 1.4585 + newHover = nullptr; 1.4586 + } 1.4587 + } 1.4588 + 1.4589 + if (newHover != mHoverContent) { 1.4590 + notifyContent1 = newHover; 1.4591 + notifyContent2 = mHoverContent; 1.4592 + mHoverContent = newHover; 1.4593 + } 1.4594 + } 1.4595 + } else { 1.4596 + updateAncestors = false; 1.4597 + if (aState == NS_EVENT_STATE_DRAGOVER) { 1.4598 + if (aContent != sDragOverContent) { 1.4599 + notifyContent1 = aContent; 1.4600 + notifyContent2 = sDragOverContent; 1.4601 + sDragOverContent = aContent; 1.4602 + } 1.4603 + } else if (aState == NS_EVENT_STATE_URLTARGET) { 1.4604 + if (aContent != mURLTargetContent) { 1.4605 + notifyContent1 = aContent; 1.4606 + notifyContent2 = mURLTargetContent; 1.4607 + mURLTargetContent = aContent; 1.4608 + } 1.4609 + } 1.4610 + } 1.4611 + 1.4612 + // We need to keep track of which of notifyContent1 and notifyContent2 is 1.4613 + // getting the state set and which is getting it unset. If both are 1.4614 + // non-null, then notifyContent1 is having the state set and notifyContent2 1.4615 + // is having it unset. But if one of them is null, we need to keep track of 1.4616 + // the right thing for notifyContent1 explicitly. 1.4617 + bool content1StateSet = true; 1.4618 + if (!notifyContent1) { 1.4619 + // This is ok because FindCommonAncestor wouldn't find anything 1.4620 + // anyway if notifyContent1 is null. 1.4621 + notifyContent1 = notifyContent2; 1.4622 + notifyContent2 = nullptr; 1.4623 + content1StateSet = false; 1.4624 + } 1.4625 + 1.4626 + if (notifyContent1 && mPresContext) { 1.4627 + EnsureDocument(mPresContext); 1.4628 + if (mDocument) { 1.4629 + nsAutoScriptBlocker scriptBlocker; 1.4630 + 1.4631 + if (updateAncestors) { 1.4632 + nsCOMPtr<nsIContent> commonAncestor = 1.4633 + FindCommonAncestor(notifyContent1, notifyContent2); 1.4634 + if (notifyContent2) { 1.4635 + // It's very important to first notify the state removal and 1.4636 + // then the state addition, because due to labels it's 1.4637 + // possible that we're removing state from some element but 1.4638 + // then adding it again (say because mHoverContent changed 1.4639 + // from a control to its label). 1.4640 + UpdateAncestorState(notifyContent2, commonAncestor, aState, false); 1.4641 + } 1.4642 + UpdateAncestorState(notifyContent1, commonAncestor, aState, 1.4643 + content1StateSet); 1.4644 + } else { 1.4645 + if (notifyContent2) { 1.4646 + DoStateChange(notifyContent2, aState, false); 1.4647 + } 1.4648 + DoStateChange(notifyContent1, aState, content1StateSet); 1.4649 + } 1.4650 + } 1.4651 + } 1.4652 + 1.4653 + return true; 1.4654 +} 1.4655 + 1.4656 +PLDHashOperator 1.4657 +EventStateManager::ResetLastOverForContent( 1.4658 + const uint32_t& aIdx, 1.4659 + nsRefPtr<OverOutElementsWrapper>& aElemWrapper, 1.4660 + void* aClosure) 1.4661 +{ 1.4662 + nsIContent* content = static_cast<nsIContent*>(aClosure); 1.4663 + if (aElemWrapper && aElemWrapper->mLastOverElement && 1.4664 + nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement, content)) { 1.4665 + aElemWrapper->mLastOverElement = nullptr; 1.4666 + } 1.4667 + 1.4668 + return PL_DHASH_NEXT; 1.4669 +} 1.4670 + 1.4671 +void 1.4672 +EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent) 1.4673 +{ 1.4674 + /* 1.4675 + * Anchor and area elements when focused or hovered might make the UI to show 1.4676 + * the current link. We want to make sure that the UI gets informed when they 1.4677 + * are actually removed from the DOM. 1.4678 + */ 1.4679 + if (aContent->IsHTML() && 1.4680 + (aContent->Tag() == nsGkAtoms::a || aContent->Tag() == nsGkAtoms::area) && 1.4681 + (aContent->AsElement()->State().HasAtLeastOneOfStates(NS_EVENT_STATE_FOCUS | 1.4682 + NS_EVENT_STATE_HOVER))) { 1.4683 + nsGenericHTMLElement* element = static_cast<nsGenericHTMLElement*>(aContent); 1.4684 + element->LeaveLink(element->GetPresContext()); 1.4685 + } 1.4686 + 1.4687 + IMEStateManager::OnRemoveContent(mPresContext, aContent); 1.4688 + 1.4689 + // inform the focus manager that the content is being removed. If this 1.4690 + // content is focused, the focus will be removed without firing events. 1.4691 + nsFocusManager* fm = nsFocusManager::GetFocusManager(); 1.4692 + if (fm) 1.4693 + fm->ContentRemoved(aDocument, aContent); 1.4694 + 1.4695 + if (mHoverContent && 1.4696 + nsContentUtils::ContentIsDescendantOf(mHoverContent, aContent)) { 1.4697 + // Since hover is hierarchical, set the current hover to the 1.4698 + // content's parent node. 1.4699 + SetContentState(aContent->GetParent(), NS_EVENT_STATE_HOVER); 1.4700 + } 1.4701 + 1.4702 + if (mActiveContent && 1.4703 + nsContentUtils::ContentIsDescendantOf(mActiveContent, aContent)) { 1.4704 + // Active is hierarchical, so set the current active to the 1.4705 + // content's parent node. 1.4706 + SetContentState(aContent->GetParent(), NS_EVENT_STATE_ACTIVE); 1.4707 + } 1.4708 + 1.4709 + if (sDragOverContent && 1.4710 + sDragOverContent->OwnerDoc() == aContent->OwnerDoc() && 1.4711 + nsContentUtils::ContentIsDescendantOf(sDragOverContent, aContent)) { 1.4712 + sDragOverContent = nullptr; 1.4713 + } 1.4714 + 1.4715 + // See bug 292146 for why we want to null this out 1.4716 + ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent); 1.4717 + mPointersEnterLeaveHelper.Enumerate( 1.4718 + &EventStateManager::ResetLastOverForContent, aContent); 1.4719 +} 1.4720 + 1.4721 +bool 1.4722 +EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent) 1.4723 +{ 1.4724 + return !(aEvent->message == NS_MOUSE_BUTTON_DOWN && 1.4725 + aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton && 1.4726 + !sNormalLMouseEventInProcess); 1.4727 +} 1.4728 + 1.4729 +//------------------------------------------- 1.4730 +// Access Key Registration 1.4731 +//------------------------------------------- 1.4732 +void 1.4733 +EventStateManager::RegisterAccessKey(nsIContent* aContent, uint32_t aKey) 1.4734 +{ 1.4735 + if (aContent && mAccessKeys.IndexOf(aContent) == -1) 1.4736 + mAccessKeys.AppendObject(aContent); 1.4737 +} 1.4738 + 1.4739 +void 1.4740 +EventStateManager::UnregisterAccessKey(nsIContent* aContent, uint32_t aKey) 1.4741 +{ 1.4742 + if (aContent) 1.4743 + mAccessKeys.RemoveObject(aContent); 1.4744 +} 1.4745 + 1.4746 +uint32_t 1.4747 +EventStateManager::GetRegisteredAccessKey(nsIContent* aContent) 1.4748 +{ 1.4749 + MOZ_ASSERT(aContent); 1.4750 + 1.4751 + if (mAccessKeys.IndexOf(aContent) == -1) 1.4752 + return 0; 1.4753 + 1.4754 + nsAutoString accessKey; 1.4755 + aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey); 1.4756 + return accessKey.First(); 1.4757 +} 1.4758 + 1.4759 +void 1.4760 +EventStateManager::EnsureDocument(nsPresContext* aPresContext) 1.4761 +{ 1.4762 + if (!mDocument) 1.4763 + mDocument = aPresContext->Document(); 1.4764 +} 1.4765 + 1.4766 +void 1.4767 +EventStateManager::FlushPendingEvents(nsPresContext* aPresContext) 1.4768 +{ 1.4769 + NS_PRECONDITION(nullptr != aPresContext, "nullptr ptr"); 1.4770 + nsIPresShell *shell = aPresContext->GetPresShell(); 1.4771 + if (shell) { 1.4772 + shell->FlushPendingNotifications(Flush_InterruptibleLayout); 1.4773 + } 1.4774 +} 1.4775 + 1.4776 +nsIContent* 1.4777 +EventStateManager::GetFocusedContent() 1.4778 +{ 1.4779 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.4780 + if (!fm || !mDocument) 1.4781 + return nullptr; 1.4782 + 1.4783 + nsCOMPtr<nsPIDOMWindow> focusedWindow; 1.4784 + return nsFocusManager::GetFocusedDescendant(mDocument->GetWindow(), false, 1.4785 + getter_AddRefs(focusedWindow)); 1.4786 +} 1.4787 + 1.4788 +//------------------------------------------------------- 1.4789 +// Return true if the docshell is visible 1.4790 + 1.4791 +bool 1.4792 +EventStateManager::IsShellVisible(nsIDocShell* aShell) 1.4793 +{ 1.4794 + NS_ASSERTION(aShell, "docshell is null"); 1.4795 + 1.4796 + nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell); 1.4797 + if (!basewin) 1.4798 + return true; 1.4799 + 1.4800 + bool isVisible = true; 1.4801 + basewin->GetVisibility(&isVisible); 1.4802 + 1.4803 + // We should be doing some additional checks here so that 1.4804 + // we don't tab into hidden tabs of tabbrowser. -bryner 1.4805 + 1.4806 + return isVisible; 1.4807 +} 1.4808 + 1.4809 +nsresult 1.4810 +EventStateManager::DoContentCommandEvent(WidgetContentCommandEvent* aEvent) 1.4811 +{ 1.4812 + EnsureDocument(mPresContext); 1.4813 + NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE); 1.4814 + nsCOMPtr<nsPIDOMWindow> window(mDocument->GetWindow()); 1.4815 + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 1.4816 + 1.4817 + nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot(); 1.4818 + NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); 1.4819 + const char* cmd; 1.4820 + switch (aEvent->message) { 1.4821 + case NS_CONTENT_COMMAND_CUT: 1.4822 + cmd = "cmd_cut"; 1.4823 + break; 1.4824 + case NS_CONTENT_COMMAND_COPY: 1.4825 + cmd = "cmd_copy"; 1.4826 + break; 1.4827 + case NS_CONTENT_COMMAND_PASTE: 1.4828 + cmd = "cmd_paste"; 1.4829 + break; 1.4830 + case NS_CONTENT_COMMAND_DELETE: 1.4831 + cmd = "cmd_delete"; 1.4832 + break; 1.4833 + case NS_CONTENT_COMMAND_UNDO: 1.4834 + cmd = "cmd_undo"; 1.4835 + break; 1.4836 + case NS_CONTENT_COMMAND_REDO: 1.4837 + cmd = "cmd_redo"; 1.4838 + break; 1.4839 + case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE: 1.4840 + cmd = "cmd_pasteTransferable"; 1.4841 + break; 1.4842 + default: 1.4843 + return NS_ERROR_NOT_IMPLEMENTED; 1.4844 + } 1.4845 + nsCOMPtr<nsIController> controller; 1.4846 + nsresult rv = root->GetControllerForCommand(cmd, getter_AddRefs(controller)); 1.4847 + NS_ENSURE_SUCCESS(rv, rv); 1.4848 + if (!controller) { 1.4849 + // When GetControllerForCommand succeeded but there is no controller, the 1.4850 + // command isn't supported. 1.4851 + aEvent->mIsEnabled = false; 1.4852 + } else { 1.4853 + bool canDoIt; 1.4854 + rv = controller->IsCommandEnabled(cmd, &canDoIt); 1.4855 + NS_ENSURE_SUCCESS(rv, rv); 1.4856 + aEvent->mIsEnabled = canDoIt; 1.4857 + if (canDoIt && !aEvent->mOnlyEnabledCheck) { 1.4858 + switch (aEvent->message) { 1.4859 + case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE: { 1.4860 + nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller); 1.4861 + NS_ENSURE_STATE(commandController); 1.4862 + 1.4863 + nsCOMPtr<nsICommandParams> params = do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv); 1.4864 + NS_ENSURE_SUCCESS(rv, rv); 1.4865 + 1.4866 + rv = params->SetISupportsValue("transferable", aEvent->mTransferable); 1.4867 + NS_ENSURE_SUCCESS(rv, rv); 1.4868 + 1.4869 + rv = commandController->DoCommandWithParams(cmd, params); 1.4870 + break; 1.4871 + } 1.4872 + 1.4873 + default: 1.4874 + rv = controller->DoCommand(cmd); 1.4875 + break; 1.4876 + } 1.4877 + NS_ENSURE_SUCCESS(rv, rv); 1.4878 + } 1.4879 + } 1.4880 + aEvent->mSucceeded = true; 1.4881 + return NS_OK; 1.4882 +} 1.4883 + 1.4884 +nsresult 1.4885 +EventStateManager::DoContentCommandScrollEvent( 1.4886 + WidgetContentCommandEvent* aEvent) 1.4887 +{ 1.4888 + NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE); 1.4889 + nsIPresShell* ps = mPresContext->GetPresShell(); 1.4890 + NS_ENSURE_TRUE(ps, NS_ERROR_NOT_AVAILABLE); 1.4891 + NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG); 1.4892 + 1.4893 + nsIScrollableFrame::ScrollUnit scrollUnit; 1.4894 + switch (aEvent->mScroll.mUnit) { 1.4895 + case WidgetContentCommandEvent::eCmdScrollUnit_Line: 1.4896 + scrollUnit = nsIScrollableFrame::LINES; 1.4897 + break; 1.4898 + case WidgetContentCommandEvent::eCmdScrollUnit_Page: 1.4899 + scrollUnit = nsIScrollableFrame::PAGES; 1.4900 + break; 1.4901 + case WidgetContentCommandEvent::eCmdScrollUnit_Whole: 1.4902 + scrollUnit = nsIScrollableFrame::WHOLE; 1.4903 + break; 1.4904 + default: 1.4905 + return NS_ERROR_INVALID_ARG; 1.4906 + } 1.4907 + 1.4908 + aEvent->mSucceeded = true; 1.4909 + 1.4910 + nsIScrollableFrame* sf = 1.4911 + ps->GetFrameToScrollAsScrollable(nsIPresShell::eEither); 1.4912 + aEvent->mIsEnabled = sf ? 1.4913 + (aEvent->mScroll.mIsHorizontal ? 1.4914 + WheelHandlingUtils::CanScrollOn(sf, aEvent->mScroll.mAmount, 0) : 1.4915 + WheelHandlingUtils::CanScrollOn(sf, 0, aEvent->mScroll.mAmount)) : false; 1.4916 + 1.4917 + if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) { 1.4918 + return NS_OK; 1.4919 + } 1.4920 + 1.4921 + nsIntPoint pt(0, 0); 1.4922 + if (aEvent->mScroll.mIsHorizontal) { 1.4923 + pt.x = aEvent->mScroll.mAmount; 1.4924 + } else { 1.4925 + pt.y = aEvent->mScroll.mAmount; 1.4926 + } 1.4927 + 1.4928 + // The caller may want synchronous scrolling. 1.4929 + sf->ScrollBy(pt, scrollUnit, nsIScrollableFrame::INSTANT); 1.4930 + return NS_OK; 1.4931 +} 1.4932 + 1.4933 +void 1.4934 +EventStateManager::DoQuerySelectedText(WidgetQueryContentEvent* aEvent) 1.4935 +{ 1.4936 + if (RemoteQueryContentEvent(aEvent)) { 1.4937 + return; 1.4938 + } 1.4939 + ContentEventHandler handler(mPresContext); 1.4940 + handler.OnQuerySelectedText(aEvent); 1.4941 +} 1.4942 + 1.4943 +void 1.4944 +EventStateManager::SetActiveManager(EventStateManager* aNewESM, 1.4945 + nsIContent* aContent) 1.4946 +{ 1.4947 + if (sActiveESM && aNewESM != sActiveESM) { 1.4948 + sActiveESM->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE); 1.4949 + } 1.4950 + sActiveESM = aNewESM; 1.4951 + if (sActiveESM && aContent) { 1.4952 + sActiveESM->SetContentState(aContent, NS_EVENT_STATE_ACTIVE); 1.4953 + } 1.4954 +} 1.4955 + 1.4956 +void 1.4957 +EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer) 1.4958 +{ 1.4959 + if (aClearer) { 1.4960 + aClearer->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE); 1.4961 + if (sDragOverContent) { 1.4962 + aClearer->SetContentState(nullptr, NS_EVENT_STATE_DRAGOVER); 1.4963 + } 1.4964 + } 1.4965 + if (sActiveESM && aClearer != sActiveESM) { 1.4966 + sActiveESM->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE); 1.4967 + } 1.4968 + sActiveESM = nullptr; 1.4969 +} 1.4970 + 1.4971 +/******************************************************************/ 1.4972 +/* mozilla::EventStateManager::DeltaAccumulator */ 1.4973 +/******************************************************************/ 1.4974 + 1.4975 +void 1.4976 +EventStateManager::DeltaAccumulator::InitLineOrPageDelta( 1.4977 + nsIFrame* aTargetFrame, 1.4978 + EventStateManager* aESM, 1.4979 + WidgetWheelEvent* aEvent) 1.4980 +{ 1.4981 + MOZ_ASSERT(aESM); 1.4982 + MOZ_ASSERT(aEvent); 1.4983 + 1.4984 + // Reset if the previous wheel event is too old. 1.4985 + if (!mLastTime.IsNull()) { 1.4986 + TimeDuration duration = TimeStamp::Now() - mLastTime; 1.4987 + if (duration.ToMilliseconds() > WheelTransaction::GetTimeoutTime()) { 1.4988 + Reset(); 1.4989 + } 1.4990 + } 1.4991 + // If we have accumulated delta, we may need to reset it. 1.4992 + if (IsInTransaction()) { 1.4993 + // If wheel event type is changed, reset the values. 1.4994 + if (mHandlingDeltaMode != aEvent->deltaMode || 1.4995 + mHandlingPixelOnlyDevice != aEvent->isPixelOnlyDevice) { 1.4996 + Reset(); 1.4997 + } else { 1.4998 + // If the delta direction is changed, we should reset only the 1.4999 + // accumulated values. 1.5000 + if (mX && aEvent->deltaX && ((aEvent->deltaX > 0.0) != (mX > 0.0))) { 1.5001 + mX = mPendingScrollAmountX = 0.0; 1.5002 + } 1.5003 + if (mY && aEvent->deltaY && ((aEvent->deltaY > 0.0) != (mY > 0.0))) { 1.5004 + mY = mPendingScrollAmountY = 0.0; 1.5005 + } 1.5006 + } 1.5007 + } 1.5008 + 1.5009 + mHandlingDeltaMode = aEvent->deltaMode; 1.5010 + mHandlingPixelOnlyDevice = aEvent->isPixelOnlyDevice; 1.5011 + 1.5012 + // If it's handling neither pixel scroll mode for pixel only device nor 1.5013 + // delta values multiplied by prefs, we must not modify lineOrPageDelta 1.5014 + // values. 1.5015 + if (!(mHandlingDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL && 1.5016 + mHandlingPixelOnlyDevice) && 1.5017 + !EventStateManager::WheelPrefs::GetInstance()-> 1.5018 + NeedToComputeLineOrPageDelta(aEvent)) { 1.5019 + // Set the delta values to mX and mY. They would be used when above block 1.5020 + // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction 1.5021 + // is changed. 1.5022 + // NOTE: We shouldn't accumulate the delta values, it might could cause 1.5023 + // overflow even though it's not a realistic situation. 1.5024 + if (aEvent->deltaX) { 1.5025 + mX = aEvent->deltaX; 1.5026 + } 1.5027 + if (aEvent->deltaY) { 1.5028 + mY = aEvent->deltaY; 1.5029 + } 1.5030 + mLastTime = TimeStamp::Now(); 1.5031 + return; 1.5032 + } 1.5033 + 1.5034 + mX += aEvent->deltaX; 1.5035 + mY += aEvent->deltaY; 1.5036 + 1.5037 + if (mHandlingDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) { 1.5038 + // Records pixel delta values and init lineOrPageDeltaX and 1.5039 + // lineOrPageDeltaY for wheel events which are caused by pixel only 1.5040 + // devices. Ignore mouse wheel transaction for computing this. The 1.5041 + // lineOrPageDelta values will be used by dispatching legacy 1.5042 + // NS_MOUSE_SCROLL_EVENT (DOMMouseScroll) but not be used for scrolling 1.5043 + // of default action. The transaction should be used only for the default 1.5044 + // action. 1.5045 + nsIScrollableFrame* scrollTarget = 1.5046 + aESM->ComputeScrollTarget(aTargetFrame, aEvent, 1.5047 + COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET); 1.5048 + nsIFrame* frame = do_QueryFrame(scrollTarget); 1.5049 + nsPresContext* pc = 1.5050 + frame ? frame->PresContext() : aTargetFrame->PresContext(); 1.5051 + nsSize scrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget); 1.5052 + nsIntSize scrollAmountInCSSPixels( 1.5053 + nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width), 1.5054 + nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.height)); 1.5055 + 1.5056 + aEvent->lineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width; 1.5057 + aEvent->lineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height; 1.5058 + 1.5059 + mX -= aEvent->lineOrPageDeltaX * scrollAmountInCSSPixels.width; 1.5060 + mY -= aEvent->lineOrPageDeltaY * scrollAmountInCSSPixels.height; 1.5061 + } else { 1.5062 + aEvent->lineOrPageDeltaX = RoundDown(mX); 1.5063 + aEvent->lineOrPageDeltaY = RoundDown(mY); 1.5064 + mX -= aEvent->lineOrPageDeltaX; 1.5065 + mY -= aEvent->lineOrPageDeltaY; 1.5066 + } 1.5067 + 1.5068 + mLastTime = TimeStamp::Now(); 1.5069 +} 1.5070 + 1.5071 +void 1.5072 +EventStateManager::DeltaAccumulator::Reset() 1.5073 +{ 1.5074 + mX = mY = 0.0; 1.5075 + mPendingScrollAmountX = mPendingScrollAmountY = 0.0; 1.5076 + mHandlingDeltaMode = UINT32_MAX; 1.5077 + mHandlingPixelOnlyDevice = false; 1.5078 +} 1.5079 + 1.5080 +nsIntPoint 1.5081 +EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction( 1.5082 + WidgetWheelEvent* aEvent, 1.5083 + const nsIntSize& aScrollAmountInDevPixels) 1.5084 +{ 1.5085 + MOZ_ASSERT(aEvent); 1.5086 + 1.5087 + // If the wheel event is line scroll and the delta value is computed from 1.5088 + // system settings, allow to override the system speed. 1.5089 + bool allowScrollSpeedOverride = 1.5090 + (!aEvent->customizedByUserPrefs && 1.5091 + aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE); 1.5092 + DeltaValues acceleratedDelta = 1.5093 + WheelTransaction::AccelerateWheelDelta(aEvent, allowScrollSpeedOverride); 1.5094 + 1.5095 + nsIntPoint result(0, 0); 1.5096 + if (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) { 1.5097 + mPendingScrollAmountX += acceleratedDelta.deltaX; 1.5098 + mPendingScrollAmountY += acceleratedDelta.deltaY; 1.5099 + } else { 1.5100 + mPendingScrollAmountX += 1.5101 + aScrollAmountInDevPixels.width * acceleratedDelta.deltaX; 1.5102 + mPendingScrollAmountY += 1.5103 + aScrollAmountInDevPixels.height * acceleratedDelta.deltaY; 1.5104 + } 1.5105 + result.x = RoundDown(mPendingScrollAmountX); 1.5106 + result.y = RoundDown(mPendingScrollAmountY); 1.5107 + mPendingScrollAmountX -= result.x; 1.5108 + mPendingScrollAmountY -= result.y; 1.5109 + 1.5110 + return result; 1.5111 +} 1.5112 + 1.5113 +/******************************************************************/ 1.5114 +/* mozilla::EventStateManager::WheelPrefs */ 1.5115 +/******************************************************************/ 1.5116 + 1.5117 +// static 1.5118 +EventStateManager::WheelPrefs* 1.5119 +EventStateManager::WheelPrefs::GetInstance() 1.5120 +{ 1.5121 + if (!sInstance) { 1.5122 + sInstance = new WheelPrefs(); 1.5123 + } 1.5124 + return sInstance; 1.5125 +} 1.5126 + 1.5127 +// static 1.5128 +void 1.5129 +EventStateManager::WheelPrefs::Shutdown() 1.5130 +{ 1.5131 + delete sInstance; 1.5132 + sInstance = nullptr; 1.5133 +} 1.5134 + 1.5135 +// static 1.5136 +void 1.5137 +EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName, 1.5138 + void* aClosure) 1.5139 +{ 1.5140 + // forget all prefs, it's not problem for performance. 1.5141 + sInstance->Reset(); 1.5142 + DeltaAccumulator::GetInstance()->Reset(); 1.5143 +} 1.5144 + 1.5145 +EventStateManager::WheelPrefs::WheelPrefs() 1.5146 +{ 1.5147 + Reset(); 1.5148 + Preferences::RegisterCallback(OnPrefChanged, "mousewheel.", nullptr); 1.5149 +} 1.5150 + 1.5151 +EventStateManager::WheelPrefs::~WheelPrefs() 1.5152 +{ 1.5153 + Preferences::UnregisterCallback(OnPrefChanged, "mousewheel.", nullptr); 1.5154 +} 1.5155 + 1.5156 +void 1.5157 +EventStateManager::WheelPrefs::Reset() 1.5158 +{ 1.5159 + memset(mInit, 0, sizeof(mInit)); 1.5160 + 1.5161 +} 1.5162 + 1.5163 +EventStateManager::WheelPrefs::Index 1.5164 +EventStateManager::WheelPrefs::GetIndexFor(WidgetWheelEvent* aEvent) 1.5165 +{ 1.5166 + if (!aEvent) { 1.5167 + return INDEX_DEFAULT; 1.5168 + } 1.5169 + 1.5170 + Modifiers modifiers = 1.5171 + (aEvent->modifiers & (MODIFIER_ALT | 1.5172 + MODIFIER_CONTROL | 1.5173 + MODIFIER_META | 1.5174 + MODIFIER_SHIFT | 1.5175 + MODIFIER_OS)); 1.5176 + 1.5177 + switch (modifiers) { 1.5178 + case MODIFIER_ALT: 1.5179 + return INDEX_ALT; 1.5180 + case MODIFIER_CONTROL: 1.5181 + return INDEX_CONTROL; 1.5182 + case MODIFIER_META: 1.5183 + return INDEX_META; 1.5184 + case MODIFIER_SHIFT: 1.5185 + return INDEX_SHIFT; 1.5186 + case MODIFIER_OS: 1.5187 + return INDEX_OS; 1.5188 + default: 1.5189 + // If two or more modifier keys are pressed, we should use default 1.5190 + // settings. 1.5191 + return INDEX_DEFAULT; 1.5192 + } 1.5193 +} 1.5194 + 1.5195 +void 1.5196 +EventStateManager::WheelPrefs::GetBasePrefName( 1.5197 + EventStateManager::WheelPrefs::Index aIndex, 1.5198 + nsACString& aBasePrefName) 1.5199 +{ 1.5200 + aBasePrefName.AssignLiteral("mousewheel."); 1.5201 + switch (aIndex) { 1.5202 + case INDEX_ALT: 1.5203 + aBasePrefName.AppendLiteral("with_alt."); 1.5204 + break; 1.5205 + case INDEX_CONTROL: 1.5206 + aBasePrefName.AppendLiteral("with_control."); 1.5207 + break; 1.5208 + case INDEX_META: 1.5209 + aBasePrefName.AppendLiteral("with_meta."); 1.5210 + break; 1.5211 + case INDEX_SHIFT: 1.5212 + aBasePrefName.AppendLiteral("with_shift."); 1.5213 + break; 1.5214 + case INDEX_OS: 1.5215 + aBasePrefName.AppendLiteral("with_win."); 1.5216 + break; 1.5217 + case INDEX_DEFAULT: 1.5218 + default: 1.5219 + aBasePrefName.AppendLiteral("default."); 1.5220 + break; 1.5221 + } 1.5222 +} 1.5223 + 1.5224 +void 1.5225 +EventStateManager::WheelPrefs::Init(EventStateManager::WheelPrefs::Index aIndex) 1.5226 +{ 1.5227 + if (mInit[aIndex]) { 1.5228 + return; 1.5229 + } 1.5230 + mInit[aIndex] = true; 1.5231 + 1.5232 + nsAutoCString basePrefName; 1.5233 + GetBasePrefName(aIndex, basePrefName); 1.5234 + 1.5235 + nsAutoCString prefNameX(basePrefName); 1.5236 + prefNameX.AppendLiteral("delta_multiplier_x"); 1.5237 + mMultiplierX[aIndex] = 1.5238 + static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100; 1.5239 + 1.5240 + nsAutoCString prefNameY(basePrefName); 1.5241 + prefNameY.AppendLiteral("delta_multiplier_y"); 1.5242 + mMultiplierY[aIndex] = 1.5243 + static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100; 1.5244 + 1.5245 + nsAutoCString prefNameZ(basePrefName); 1.5246 + prefNameZ.AppendLiteral("delta_multiplier_z"); 1.5247 + mMultiplierZ[aIndex] = 1.5248 + static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100; 1.5249 + 1.5250 + nsAutoCString prefNameAction(basePrefName); 1.5251 + prefNameAction.AppendLiteral("action"); 1.5252 + int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL); 1.5253 + if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) { 1.5254 + NS_WARNING("Unsupported action pref value, replaced with 'Scroll'."); 1.5255 + action = ACTION_SCROLL; 1.5256 + } 1.5257 + mActions[aIndex] = static_cast<Action>(action); 1.5258 + 1.5259 + // Compute action values overridden by .override_x pref. 1.5260 + // At present, override is possible only for the x-direction 1.5261 + // because this pref is introduced mainly for tilt wheels. 1.5262 + prefNameAction.AppendLiteral(".override_x"); 1.5263 + int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1); 1.5264 + if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST)) { 1.5265 + NS_WARNING("Unsupported action override pref value, didn't override."); 1.5266 + actionOverrideX = -1; 1.5267 + } 1.5268 + mOverriddenActionsX[aIndex] = (actionOverrideX == -1) 1.5269 + ? static_cast<Action>(action) 1.5270 + : static_cast<Action>(actionOverrideX); 1.5271 +} 1.5272 + 1.5273 +void 1.5274 +EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent) 1.5275 +{ 1.5276 + Index index = GetIndexFor(aEvent); 1.5277 + Init(index); 1.5278 + 1.5279 + aEvent->deltaX *= mMultiplierX[index]; 1.5280 + aEvent->deltaY *= mMultiplierY[index]; 1.5281 + aEvent->deltaZ *= mMultiplierZ[index]; 1.5282 + 1.5283 + // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute 1.5284 + // value, we should use lineOrPageDelta values which were set by widget. 1.5285 + // Otherwise, we need to compute them from accumulated delta values. 1.5286 + if (!NeedToComputeLineOrPageDelta(aEvent)) { 1.5287 + aEvent->lineOrPageDeltaX *= static_cast<int32_t>(mMultiplierX[index]); 1.5288 + aEvent->lineOrPageDeltaY *= static_cast<int32_t>(mMultiplierY[index]); 1.5289 + } else { 1.5290 + aEvent->lineOrPageDeltaX = 0; 1.5291 + aEvent->lineOrPageDeltaY = 0; 1.5292 + } 1.5293 + 1.5294 + aEvent->customizedByUserPrefs = 1.5295 + ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) || 1.5296 + (mMultiplierZ[index] != 1.0)); 1.5297 +} 1.5298 + 1.5299 +void 1.5300 +EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta( 1.5301 + WidgetWheelEvent* aEvent) 1.5302 +{ 1.5303 + Index index = GetIndexFor(aEvent); 1.5304 + Init(index); 1.5305 + 1.5306 + // XXX If the multiplier pref value is negative, the scroll direction was 1.5307 + // changed and caused to scroll different direction. In such case, 1.5308 + // this method reverts the sign of overflowDelta. Does it make widget 1.5309 + // happy? Although, widget can know the pref applied delta values by 1.5310 + // referrencing the deltaX and deltaY of the event. 1.5311 + 1.5312 + if (mMultiplierX[index]) { 1.5313 + aEvent->overflowDeltaX /= mMultiplierX[index]; 1.5314 + } 1.5315 + if (mMultiplierY[index]) { 1.5316 + aEvent->overflowDeltaY /= mMultiplierY[index]; 1.5317 + } 1.5318 +} 1.5319 + 1.5320 +EventStateManager::WheelPrefs::Action 1.5321 +EventStateManager::WheelPrefs::ComputeActionFor(WidgetWheelEvent* aEvent) 1.5322 +{ 1.5323 + Index index = GetIndexFor(aEvent); 1.5324 + Init(index); 1.5325 + 1.5326 + bool deltaXPreferred = 1.5327 + (Abs(aEvent->deltaX) > Abs(aEvent->deltaY) && 1.5328 + Abs(aEvent->deltaX) > Abs(aEvent->deltaZ)); 1.5329 + Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions; 1.5330 + if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL) { 1.5331 + return actions[index]; 1.5332 + } 1.5333 + 1.5334 + // Momentum events shouldn't run special actions. 1.5335 + if (aEvent->isMomentum) { 1.5336 + // Use the default action. Note that user might kill the wheel scrolling. 1.5337 + Init(INDEX_DEFAULT); 1.5338 + return (actions[INDEX_DEFAULT] == ACTION_SCROLL) ? ACTION_SCROLL : 1.5339 + ACTION_NONE; 1.5340 + } 1.5341 + 1.5342 + return actions[index]; 1.5343 +} 1.5344 + 1.5345 +bool 1.5346 +EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta( 1.5347 + WidgetWheelEvent* aEvent) 1.5348 +{ 1.5349 + Index index = GetIndexFor(aEvent); 1.5350 + Init(index); 1.5351 + 1.5352 + return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) || 1.5353 + (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0); 1.5354 +} 1.5355 + 1.5356 +bool 1.5357 +EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX( 1.5358 + WidgetWheelEvent* aEvent) 1.5359 +{ 1.5360 + Index index = GetIndexFor(aEvent); 1.5361 + Init(index); 1.5362 + return Abs(mMultiplierX[index]) >= 1.5363 + MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL; 1.5364 +} 1.5365 + 1.5366 +bool 1.5367 +EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY( 1.5368 + WidgetWheelEvent* aEvent) 1.5369 +{ 1.5370 + Index index = GetIndexFor(aEvent); 1.5371 + Init(index); 1.5372 + return Abs(mMultiplierY[index]) >= 1.5373 + MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL; 1.5374 +} 1.5375 + 1.5376 +/******************************************************************/ 1.5377 +/* mozilla::EventStateManager::Prefs */ 1.5378 +/******************************************************************/ 1.5379 + 1.5380 +bool EventStateManager::Prefs::sKeyCausesActivation = true; 1.5381 +bool EventStateManager::Prefs::sClickHoldContextMenu = false; 1.5382 +int32_t EventStateManager::Prefs::sGenericAccessModifierKey = -1; 1.5383 +int32_t EventStateManager::Prefs::sChromeAccessModifierMask = 0; 1.5384 +int32_t EventStateManager::Prefs::sContentAccessModifierMask = 0; 1.5385 + 1.5386 +// static 1.5387 +void 1.5388 +EventStateManager::Prefs::Init() 1.5389 +{ 1.5390 + DebugOnly<nsresult> rv = 1.5391 + Preferences::AddBoolVarCache(&sKeyCausesActivation, 1.5392 + "accessibility.accesskeycausesactivation", 1.5393 + sKeyCausesActivation); 1.5394 + MOZ_ASSERT(NS_SUCCEEDED(rv), 1.5395 + "Failed to observe \"accessibility.accesskeycausesactivation\""); 1.5396 + rv = Preferences::AddBoolVarCache(&sClickHoldContextMenu, 1.5397 + "ui.click_hold_context_menus", 1.5398 + sClickHoldContextMenu); 1.5399 + MOZ_ASSERT(NS_SUCCEEDED(rv), 1.5400 + "Failed to observe \"ui.click_hold_context_menus\""); 1.5401 + rv = Preferences::AddIntVarCache(&sGenericAccessModifierKey, 1.5402 + "ui.key.generalAccessKey", 1.5403 + sGenericAccessModifierKey); 1.5404 + MOZ_ASSERT(NS_SUCCEEDED(rv), 1.5405 + "Failed to observe \"ui.key.generalAccessKey\""); 1.5406 + rv = Preferences::AddIntVarCache(&sChromeAccessModifierMask, 1.5407 + "ui.key.chromeAccess", 1.5408 + sChromeAccessModifierMask); 1.5409 + MOZ_ASSERT(NS_SUCCEEDED(rv), 1.5410 + "Failed to observe \"ui.key.chromeAccess\""); 1.5411 + rv = Preferences::AddIntVarCache(&sContentAccessModifierMask, 1.5412 + "ui.key.contentAccess", 1.5413 + sContentAccessModifierMask); 1.5414 + MOZ_ASSERT(NS_SUCCEEDED(rv), 1.5415 + "Failed to observe \"ui.key.contentAccess\""); 1.5416 + 1.5417 + rv = Preferences::RegisterCallback(OnChange, "dom.popup_allowed_events"); 1.5418 + MOZ_ASSERT(NS_SUCCEEDED(rv), 1.5419 + "Failed to observe \"dom.popup_allowed_events\""); 1.5420 +} 1.5421 + 1.5422 +// static 1.5423 +void 1.5424 +EventStateManager::Prefs::OnChange(const char* aPrefName, void*) 1.5425 +{ 1.5426 + nsDependentCString prefName(aPrefName); 1.5427 + if (prefName.EqualsLiteral("dom.popup_allowed_events")) { 1.5428 + Event::PopupAllowedEventsChanged(); 1.5429 + } 1.5430 +} 1.5431 + 1.5432 +// static 1.5433 +void 1.5434 +EventStateManager::Prefs::Shutdown() 1.5435 +{ 1.5436 + Preferences::UnregisterCallback(OnChange, "dom.popup_allowed_events"); 1.5437 +} 1.5438 + 1.5439 +// static 1.5440 +int32_t 1.5441 +EventStateManager::Prefs::ChromeAccessModifierMask() 1.5442 +{ 1.5443 + return GetAccessModifierMask(nsIDocShellTreeItem::typeChrome); 1.5444 +} 1.5445 + 1.5446 +// static 1.5447 +int32_t 1.5448 +EventStateManager::Prefs::ContentAccessModifierMask() 1.5449 +{ 1.5450 + return GetAccessModifierMask(nsIDocShellTreeItem::typeContent); 1.5451 +} 1.5452 + 1.5453 +// static 1.5454 +int32_t 1.5455 +EventStateManager::Prefs::GetAccessModifierMask(int32_t aItemType) 1.5456 +{ 1.5457 + switch (sGenericAccessModifierKey) { 1.5458 + case -1: break; // use the individual prefs 1.5459 + case nsIDOMKeyEvent::DOM_VK_SHIFT: return NS_MODIFIER_SHIFT; 1.5460 + case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL; 1.5461 + case nsIDOMKeyEvent::DOM_VK_ALT: return NS_MODIFIER_ALT; 1.5462 + case nsIDOMKeyEvent::DOM_VK_META: return NS_MODIFIER_META; 1.5463 + case nsIDOMKeyEvent::DOM_VK_WIN: return NS_MODIFIER_OS; 1.5464 + default: return 0; 1.5465 + } 1.5466 + 1.5467 + switch (aItemType) { 1.5468 + case nsIDocShellTreeItem::typeChrome: 1.5469 + return sChromeAccessModifierMask; 1.5470 + case nsIDocShellTreeItem::typeContent: 1.5471 + return sContentAccessModifierMask; 1.5472 + default: 1.5473 + return 0; 1.5474 + } 1.5475 +} 1.5476 + 1.5477 +/******************************************************************/ 1.5478 +/* mozilla::AutoHandlingUserInputStatePusher */ 1.5479 +/******************************************************************/ 1.5480 + 1.5481 +AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher( 1.5482 + bool aIsHandlingUserInput, 1.5483 + WidgetEvent* aEvent, 1.5484 + nsIDocument* aDocument) : 1.5485 + mIsHandlingUserInput(aIsHandlingUserInput), 1.5486 + mIsMouseDown(aEvent && aEvent->message == NS_MOUSE_BUTTON_DOWN), 1.5487 + mResetFMMouseDownState(false) 1.5488 +{ 1.5489 + if (!aIsHandlingUserInput) { 1.5490 + return; 1.5491 + } 1.5492 + EventStateManager::StartHandlingUserInput(); 1.5493 + if (!mIsMouseDown) { 1.5494 + return; 1.5495 + } 1.5496 + nsIPresShell::SetCapturingContent(nullptr, 0); 1.5497 + nsIPresShell::AllowMouseCapture(true); 1.5498 + if (!aDocument || !aEvent->mFlags.mIsTrusted) { 1.5499 + return; 1.5500 + } 1.5501 + nsFocusManager* fm = nsFocusManager::GetFocusManager(); 1.5502 + NS_ENSURE_TRUE_VOID(fm); 1.5503 + fm->SetMouseButtonDownHandlingDocument(aDocument); 1.5504 + mResetFMMouseDownState = true; 1.5505 +} 1.5506 + 1.5507 +AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() 1.5508 +{ 1.5509 + if (!mIsHandlingUserInput) { 1.5510 + return; 1.5511 + } 1.5512 + EventStateManager::StopHandlingUserInput(); 1.5513 + if (!mIsMouseDown) { 1.5514 + return; 1.5515 + } 1.5516 + nsIPresShell::AllowMouseCapture(false); 1.5517 + if (!mResetFMMouseDownState) { 1.5518 + return; 1.5519 + } 1.5520 + nsFocusManager* fm = nsFocusManager::GetFocusManager(); 1.5521 + NS_ENSURE_TRUE_VOID(fm); 1.5522 + fm->SetMouseButtonDownHandlingDocument(nullptr); 1.5523 +} 1.5524 + 1.5525 +} // namespace mozilla 1.5526 +