1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/apz/util/ActiveElementManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,153 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "ActiveElementManager.h" 1.10 +#include "mozilla/EventStates.h" 1.11 +#include "mozilla/Preferences.h" 1.12 +#include "mozilla/Services.h" 1.13 +#include "inIDOMUtils.h" 1.14 +#include "nsIDOMDocument.h" 1.15 +#include "nsIDOMElement.h" 1.16 +#include "nsIDOMEventTarget.h" 1.17 +#include "base/message_loop.h" 1.18 +#include "base/task.h" 1.19 + 1.20 +namespace mozilla { 1.21 +namespace layers { 1.22 + 1.23 +static int32_t sActivationDelayMs = 100; 1.24 +static bool sActivationDelayMsSet = false; 1.25 + 1.26 +ActiveElementManager::ActiveElementManager() 1.27 + : mDomUtils(services::GetInDOMUtils()), 1.28 + mCanBePan(false), 1.29 + mCanBePanSet(false), 1.30 + mSetActiveTask(nullptr) 1.31 +{ 1.32 + if (!sActivationDelayMsSet) { 1.33 + Preferences::AddIntVarCache(&sActivationDelayMs, 1.34 + "ui.touch_activation.delay_ms", 1.35 + sActivationDelayMs); 1.36 + sActivationDelayMsSet = true; 1.37 + } 1.38 +} 1.39 + 1.40 +ActiveElementManager::~ActiveElementManager() {} 1.41 + 1.42 +void 1.43 +ActiveElementManager::SetTargetElement(nsIDOMEventTarget* aTarget) 1.44 +{ 1.45 + if (mTarget) { 1.46 + // Multiple fingers on screen (since HandleTouchEnd clears mTarget). 1.47 + CancelTask(); 1.48 + ResetActive(); 1.49 + mTarget = nullptr; 1.50 + return; 1.51 + } 1.52 + 1.53 + mTarget = do_QueryInterface(aTarget); 1.54 + TriggerElementActivation(); 1.55 +} 1.56 + 1.57 +void 1.58 +ActiveElementManager::HandleTouchStart(bool aCanBePan) 1.59 +{ 1.60 + mCanBePan = aCanBePan; 1.61 + mCanBePanSet = true; 1.62 + TriggerElementActivation(); 1.63 +} 1.64 + 1.65 +void 1.66 +ActiveElementManager::TriggerElementActivation() 1.67 +{ 1.68 + // Both HandleTouchStart() and SetTargetElement() call this. They can be 1.69 + // called in either order. One will set mCanBePanSet, and the other, mTarget. 1.70 + // We want to actually trigger the activation once both are set. 1.71 + if (!(mTarget && mCanBePanSet)) { 1.72 + return; 1.73 + } 1.74 + 1.75 + // If the touch cannot be a pan, make mTarget :active right away. 1.76 + // Otherwise, wait a bit to see if the user will pan or not. 1.77 + if (!mCanBePan) { 1.78 + SetActive(mTarget); 1.79 + } else { 1.80 + mSetActiveTask = NewRunnableMethod( 1.81 + this, &ActiveElementManager::SetActiveTask, mTarget); 1.82 + MessageLoop::current()->PostDelayedTask( 1.83 + FROM_HERE, mSetActiveTask, sActivationDelayMs); 1.84 + } 1.85 +} 1.86 + 1.87 +void 1.88 +ActiveElementManager::HandlePanStart() 1.89 +{ 1.90 + // The user started to pan, so we don't want mTarget to be :active. 1.91 + // Make it not :active, and clear any pending task to make it :active. 1.92 + CancelTask(); 1.93 + ResetActive(); 1.94 +} 1.95 + 1.96 +void 1.97 +ActiveElementManager::HandleTouchEnd(bool aWasClick) 1.98 +{ 1.99 + // If the touch was a click, make mTarget :active right away. 1.100 + // nsEventStateManager will reset the active element when processing 1.101 + // the mouse-down event generated by the click. 1.102 + CancelTask(); 1.103 + if (aWasClick) { 1.104 + SetActive(mTarget); 1.105 + } 1.106 + 1.107 + // Clear mTarget for next touch. 1.108 + mTarget = nullptr; 1.109 +} 1.110 + 1.111 +void 1.112 +ActiveElementManager::SetActive(nsIDOMElement* aTarget) 1.113 +{ 1.114 + if (mDomUtils) { 1.115 + mDomUtils->SetContentState(aTarget, NS_EVENT_STATE_ACTIVE.GetInternalValue());; 1.116 + } 1.117 +} 1.118 + 1.119 +void 1.120 +ActiveElementManager::ResetActive() 1.121 +{ 1.122 + // Clear the :active flag from mTarget by setting it on the document root. 1.123 + if (mTarget) { 1.124 + nsCOMPtr<nsIDOMDocument> doc; 1.125 + mTarget->GetOwnerDocument(getter_AddRefs(doc)); 1.126 + if (doc) { 1.127 + nsCOMPtr<nsIDOMElement> root; 1.128 + doc->GetDocumentElement(getter_AddRefs(root)); 1.129 + if (root) { 1.130 + SetActive(root); 1.131 + } 1.132 + } 1.133 + } 1.134 +} 1.135 + 1.136 +void 1.137 +ActiveElementManager::SetActiveTask(nsIDOMElement* aTarget) 1.138 +{ 1.139 + // This gets called from mSetActiveTask's Run() method. The message loop 1.140 + // deletes the task right after running it, so we need to null out 1.141 + // mSetActiveTask to make sure we're not left with a dangling pointer. 1.142 + mSetActiveTask = nullptr; 1.143 + SetActive(aTarget); 1.144 +} 1.145 + 1.146 +void 1.147 +ActiveElementManager::CancelTask() 1.148 +{ 1.149 + if (mSetActiveTask) { 1.150 + mSetActiveTask->Cancel(); 1.151 + mSetActiveTask = nullptr; 1.152 + } 1.153 +} 1.154 + 1.155 +} 1.156 +}