LCOV - code coverage report
Current view: top level - gfx/layers/apz/src - FocusState.h (source / functions) Hit Total Coverage
Test: output.info Lines: 1 4 25.0 %
Date: 2017-07-14 16:53:18 Functions: 1 3 33.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13