gfx/layers/apz/util/ActiveElementManager.cpp

changeset 0
6474c204b198
     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 +}

mercurial