tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TouchActionHelper.cpp (5314B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "TouchActionHelper.h"
      8 
      9 #include "mozilla/layers/IAPZCTreeManager.h"
     10 #include "mozilla/PresShell.h"
     11 #include "mozilla/ScrollContainerFrame.h"
     12 #include "mozilla/TouchEvents.h"
     13 #include "nsContainerFrame.h"
     14 #include "nsIFrameInlines.h"
     15 #include "nsLayoutUtils.h"
     16 
     17 namespace mozilla::layers {
     18 
     19 static void UpdateAllowedBehavior(StyleTouchAction aTouchActionValue,
     20                                  bool aConsiderPanning,
     21                                  TouchBehaviorFlags& aOutBehavior) {
     22  if (aTouchActionValue != StyleTouchAction::AUTO) {
     23    // Double-tap-zooming need property value AUTO
     24    aOutBehavior &= ~AllowedTouchBehavior::ANIMATING_ZOOM;
     25    if (aTouchActionValue != StyleTouchAction::MANIPULATION &&
     26        !(aTouchActionValue & StyleTouchAction::PINCH_ZOOM)) {
     27      // Pinch-zooming needs value AUTO or MANIPULATION, or the PINCH_ZOOM bit
     28      // set
     29      aOutBehavior &= ~AllowedTouchBehavior::PINCH_ZOOM;
     30    }
     31  }
     32 
     33  if (aConsiderPanning) {
     34    if (aTouchActionValue == StyleTouchAction::NONE) {
     35      aOutBehavior &= ~AllowedTouchBehavior::VERTICAL_PAN;
     36      aOutBehavior &= ~AllowedTouchBehavior::HORIZONTAL_PAN;
     37    }
     38 
     39    // Values pan-x and pan-y set at the same time to the same element do not
     40    // affect panning constraints. Therefore we need to check whether pan-x is
     41    // set without pan-y and the same for pan-y.
     42    if ((aTouchActionValue & StyleTouchAction::PAN_X) &&
     43        !(aTouchActionValue & StyleTouchAction::PAN_Y)) {
     44      aOutBehavior &= ~AllowedTouchBehavior::VERTICAL_PAN;
     45    } else if ((aTouchActionValue & StyleTouchAction::PAN_Y) &&
     46               !(aTouchActionValue & StyleTouchAction::PAN_X)) {
     47      aOutBehavior &= ~AllowedTouchBehavior::HORIZONTAL_PAN;
     48    }
     49  }
     50 }
     51 
     52 static TouchBehaviorFlags GetAllowedTouchBehaviorForPoint(
     53    nsIWidget* aWidget, RelativeTo aRootFrame,
     54    const LayoutDeviceIntPoint& aPoint) {
     55  nsPoint relativePoint =
     56      nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget, aPoint, aRootFrame);
     57 
     58  nsIFrame* target = nsLayoutUtils::GetFrameForPoint(aRootFrame, relativePoint);
     59 
     60  return TouchActionHelper::GetAllowedTouchBehaviorForFrame(target);
     61 }
     62 
     63 nsTArray<TouchBehaviorFlags> TouchActionHelper::GetAllowedTouchBehavior(
     64    nsIWidget* aWidget, dom::Document* aDocument,
     65    const WidgetTouchEvent& aEvent) {
     66  nsTArray<TouchBehaviorFlags> flags;
     67  if (!aWidget || !aDocument) {
     68    return flags;
     69  }
     70  if (PresShell* presShell = aDocument->GetPresShell()) {
     71    if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
     72      for (const auto& touch : aEvent.mTouches) {
     73        flags.AppendElement(GetAllowedTouchBehaviorForPoint(
     74            aWidget, RelativeTo{rootFrame, ViewportType::Visual},
     75            touch->mRefPoint));
     76      }
     77    }
     78  }
     79  return flags;
     80 }
     81 
     82 TouchBehaviorFlags TouchActionHelper::GetAllowedTouchBehaviorForFrame(
     83    nsIFrame* aFrame) {
     84  TouchBehaviorFlags behavior = AllowedTouchBehavior::VERTICAL_PAN |
     85                                AllowedTouchBehavior::HORIZONTAL_PAN |
     86                                AllowedTouchBehavior::PINCH_ZOOM |
     87                                AllowedTouchBehavior::ANIMATING_ZOOM;
     88 
     89  if (!aFrame) {
     90    return behavior;
     91  }
     92 
     93  nsIFrame* nearestScrollContainerFrame =
     94      nsLayoutUtils::GetNearestScrollContainerFrame(aFrame, 0);
     95 
     96  // We're walking up the DOM tree until we meet the element with touch behavior
     97  // and accumulating touch-action restrictions of all elements in this chain.
     98  // The exact quote from the spec, that clarifies more:
     99  // To determine the effect of a touch, find the nearest ancestor (starting
    100  // from the element itself) that has a default touch behavior. Then examine
    101  // the touch-action property of each element between the hit tested element
    102  // and the element with the default touch behavior (including both the hit
    103  // tested element and the element with the default touch behavior). If the
    104  // touch-action property of any of those elements disallows the default touch
    105  // behavior, do nothing. Otherwise allow the element to start considering the
    106  // touch for the purposes of executing a default touch behavior.
    107 
    108  // Currently we support only two touch behaviors: panning and zooming.
    109  // For panning we walk up until we meet the first scrollable element (the
    110  // element that supports panning) or root element. For zooming we walk up
    111  // until the root element since Firefox currently supports only zooming of the
    112  // root frame but not the subframes.
    113 
    114  bool considerPanning = true;
    115 
    116  for (nsIFrame* frame = aFrame; frame && frame->GetContent() && behavior;
    117       frame = frame->GetInFlowParent()) {
    118    UpdateAllowedBehavior(frame->UsedTouchAction(), considerPanning, behavior);
    119 
    120    if (frame == nearestScrollContainerFrame) {
    121      // We met the scrollable element, after it we shouldn't consider
    122      // touch-action values for the purpose of panning but only for zooming.
    123      considerPanning = false;
    124    }
    125  }
    126 
    127  return behavior;
    128 }
    129 
    130 }  // namespace mozilla::layers