tor-browser

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

FocusState.h (7419B)


      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 #ifndef mozilla_layers_FocusState_h
      8 #define mozilla_layers_FocusState_h
      9 
     10 #include <unordered_map>  // for std::unordered_map
     11 #include <unordered_set>  // for std::unordered_set
     12 
     13 #include "mozilla/layers/FocusTarget.h"          // for FocusTarget
     14 #include "mozilla/layers/ScrollableLayerGuid.h"  // for ViewID
     15 #include "mozilla/Mutex.h"                       // for Mutex
     16 
     17 namespace mozilla {
     18 namespace layers {
     19 
     20 /**
     21 * This class is used for tracking chrome and content focus targets and
     22 * calculating global focus information from them for use by APZCTreeManager
     23 * for async keyboard scrolling.
     24 *
     25 * # Calculating the element to scroll
     26 *
     27 * Chrome and content processes have independently focused elements. This makes
     28 * it difficult to calculate the global focused element and its scrollable
     29 * frame from the chrome or content side. So instead we send the local focus
     30 * information from each process to here and then calculate the global focus
     31 * information. This local information resides in a `focus target`.
     32 *
     33 * A focus target indicates that either:
     34 *    1. The focused element is a remote browser along with its layer tree ID
     35 *    2. The focused element is not scrollable
     36 *    3. The focused element is scrollable along with the ViewID's of its
     37         scrollable layers
     38 *
     39 * Using this information we can determine the global focus information by
     40 * starting at the focus target of the root layer tree ID and following remote
     41 * browsers until we reach a scrollable or non-scrollable focus target.
     42 *
     43 * # Determinism and sequence numbers
     44 *
     45 * The focused element in content can be changed within any javascript code. And
     46 * javascript can run in response to an event or at any moment from `setTimeout`
     47 * and others. This makes it impossible to always have the current focus
     48 * information in APZ as it can be changed asynchronously at any moment. If we
     49 * don't have the latest focus information, we may incorrectly scroll a target
     50 * when we shouldn't.
     51 *
     52 * A tradeoff is designed here whereby we will maintain deterministic focus
     53 * changes for user input, but not for other javascript code. The reasoning
     54 * here is that `setTimeout` and others are already non-deterministic and so it
     55 * might not be as breaking to web content.
     56 *
     57 * To maintain deterministic focus changes for a given stream of user inputs,
     58 * we invalidate our focus state whenever we receive a user input that may
     59 * trigger event listeners. We then attach a new sequence number to these
     60 * events and dispatch them to content. Content will then include the latest
     61 * sequence number it has processed to every focus update. Using this we can
     62 * determine whether any potentially focus changing events have yet to be
     63 * handled by content.
     64 *
     65 * Once we have received the latest focus sequence number from content, we know
     66 * that all event listeners triggered by user inputs, and their resulting focus
     67 * changes, have been processed and so we have a current target that we can use
     68 * again.
     69 */
     70 class FocusState final {
     71 public:
     72  FocusState();
     73 
     74  /**
     75   * The sequence number of the last potentially focus changing event processed
     76   * by APZ. This number starts at one and increases monotonically. This number
     77   * will never be zero as that is used to catch uninitialized focus sequence
     78   * numbers on input events.
     79   */
     80  uint64_t LastAPZProcessedEvent() const;
     81 
     82  /**
     83   * Notify focus state of a potentially focus changing event. This will
     84   * increment the current focus sequence number. The new value can be gotten
     85   * from LastAPZProcessedEvent().
     86   */
     87  void ReceiveFocusChangingEvent();
     88 
     89  /**
     90   * Update the internal focus tree and recalculate the global focus target for
     91   * a focus target update received from chrome or content.
     92   *
     93   * @param aRootLayerTreeId the layer tree ID of the root layer for the
     94                             parent APZCTreeManager
     95   * @param aOriginatingLayersId the layer tree ID that this focus target
     96                                 belongs to
     97   */
     98  void Update(LayersId aRootLayerTreeId, LayersId aOriginatingLayersId,
     99              const FocusTarget& aTarget);
    100 
    101  /**
    102   * Removes a focus target by its layer tree ID.
    103   */
    104  void RemoveFocusTarget(LayersId aLayersId);
    105 
    106  /**
    107   * Gets the scrollable layer that should be horizontally scrolled for a key
    108   * event, if any. The returned ScrollableLayerGuid doesn't contain a
    109   * presShellId, and so it should not be used in comparisons.
    110   *
    111   * No scrollable layer is returned if any of the following are true:
    112   *   1. We don't have a current focus target
    113   *   2. There are event listeners that could change the focus
    114   *   3. The target has not been layerized
    115   */
    116  Maybe<ScrollableLayerGuid> GetHorizontalTarget() const;
    117  /**
    118   * The same as GetHorizontalTarget() but for vertical scrolling.
    119   */
    120  Maybe<ScrollableLayerGuid> GetVerticalTarget() const;
    121 
    122  /**
    123   * Gets whether it is safe to not increment the focus sequence number for an
    124   * unmatched keyboard event.
    125   */
    126  bool CanIgnoreKeyboardShortcutMisses() const;
    127 
    128  /**
    129   * Reset to initial state.
    130   */
    131  void Reset();
    132 
    133 private:
    134  /**
    135   * Whether the current focus state is known to be current or else if an event
    136   * has been processed that could change the focus but we have not received an
    137   * update with a new confirmed target.
    138   * This can only be called by methods that have already acquired mMutex; they
    139   * have to pass their lock as compile-time proof.
    140   */
    141  bool IsCurrent(const MutexAutoLock& aLock) const;
    142 
    143 private:
    144  // All methods should hold this lock, since this class is accessed via both
    145  // the updater and controller threads.
    146  mutable Mutex mMutex MOZ_UNANNOTATED;
    147 
    148  // The set of focus targets received indexed by their layer tree ID
    149  std::unordered_map<LayersId, FocusTarget, LayersId::HashFn> mFocusTree;
    150 
    151  // The focus sequence number of the last potentially focus changing event
    152  // processed by APZ. This number starts at one and increases monotonically.
    153  // We don't worry about wrap around here because at a pace of 100
    154  // increments/sec, it would take 5.85*10^9 years before we would wrap around.
    155  // This number will never be zero as that is used to catch uninitialized focus
    156  // sequence numbers on input events.
    157  uint64_t mLastAPZProcessedEvent;
    158  // The focus sequence number last received in a focus update.
    159  uint64_t mLastContentProcessedEvent;
    160 
    161  // A flag whether there is a key listener on the event target chain for the
    162  // focused element
    163  bool mFocusHasKeyEventListeners;
    164  // A flag that is false until the first call to Update().
    165  bool mReceivedUpdate;
    166 
    167  // The layer tree ID which contains the scrollable frame of the focused
    168  // element
    169  LayersId mFocusLayersId;
    170  // The scrollable layer corresponding to the scrollable frame that is used to
    171  // scroll the focused element. This depends on the direction the user is
    172  // scrolling.
    173  ScrollableLayerGuid::ViewID mFocusHorizontalTarget;
    174  ScrollableLayerGuid::ViewID mFocusVerticalTarget;
    175 };
    176 
    177 }  // namespace layers
    178 }  // namespace mozilla
    179 
    180 #endif  // mozilla_layers_FocusState_h