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 : #include "mozilla/layers/FocusState.h"
7 :
8 : // #define FS_LOG(...) printf_stderr("FS: " __VA_ARGS__)
9 : #define FS_LOG(...)
10 :
11 : namespace mozilla {
12 : namespace layers {
13 :
14 1 : FocusState::FocusState()
15 : : mLastAPZProcessedEvent(1)
16 : , mLastContentProcessedEvent(0)
17 : , mFocusHasKeyEventListeners(false)
18 : , mFocusLayersId(0)
19 : , mFocusHorizontalTarget(FrameMetrics::NULL_SCROLL_ID)
20 1 : , mFocusVerticalTarget(FrameMetrics::NULL_SCROLL_ID)
21 : {
22 1 : }
23 :
24 : bool
25 0 : FocusState::IsCurrent() const
26 : {
27 : FS_LOG("Checking IsCurrent() with cseq=%" PRIu64 ", aseq=%" PRIu64 "\n",
28 : mLastContentProcessedEvent,
29 : mLastAPZProcessedEvent);
30 :
31 0 : MOZ_ASSERT(mLastContentProcessedEvent <= mLastAPZProcessedEvent);
32 0 : return mLastContentProcessedEvent == mLastAPZProcessedEvent;
33 : }
34 :
35 : void
36 6 : FocusState::ReceiveFocusChangingEvent()
37 : {
38 6 : mLastAPZProcessedEvent += 1;
39 6 : }
40 :
41 : void
42 0 : FocusState::Update(uint64_t aRootLayerTreeId,
43 : uint64_t aOriginatingLayersId,
44 : const FocusTarget& aState)
45 : {
46 : FS_LOG("Update with rlt=%" PRIu64 ", olt=%" PRIu64 ", ft=(%d, %" PRIu64 ")\n",
47 : aRootLayerTreeId,
48 : aOriginatingLayersId,
49 : (int)aState.mType,
50 : aState.mSequenceNumber);
51 :
52 : // Update the focus tree with the latest target
53 0 : mFocusTree[aOriginatingLayersId] = aState;
54 :
55 : // Reset our internal state so we can recalculate it
56 0 : mFocusHasKeyEventListeners = false;
57 0 : mFocusLayersId = aRootLayerTreeId;
58 0 : mFocusHorizontalTarget = FrameMetrics::NULL_SCROLL_ID;
59 0 : mFocusVerticalTarget = FrameMetrics::NULL_SCROLL_ID;
60 :
61 : // To update the focus state for the entire APZCTreeManager, we need
62 : // to traverse the focus tree to find the current leaf which is the global
63 : // focus target we can use for async keyboard scrolling
64 : while (true) {
65 0 : auto currentNode = mFocusTree.find(mFocusLayersId);
66 0 : if (currentNode == mFocusTree.end()) {
67 : FS_LOG("Setting target to nil (cannot find lt=%" PRIu64 ")\n",
68 : mFocusLayersId);
69 0 : return;
70 : }
71 :
72 0 : const FocusTarget& target = currentNode->second;
73 :
74 : // Accumulate event listener flags on the path to the focus target
75 0 : mFocusHasKeyEventListeners |= target.mFocusHasKeyEventListeners;
76 :
77 0 : switch (target.mType) {
78 : case FocusTarget::eRefLayer: {
79 : // Guard against infinite loops
80 0 : MOZ_ASSERT(mFocusLayersId != target.mData.mRefLayerId);
81 0 : if (mFocusLayersId == target.mData.mRefLayerId) {
82 : FS_LOG("Setting target to nil (bailing out of infinite loop, lt=%" PRIu64 ")\n",
83 : mFocusLayersId);
84 0 : return;
85 : }
86 :
87 : FS_LOG("Looking for target in lt=%" PRIu64 "\n", target.mData.mRefLayerId);
88 :
89 : // The focus target is in a child layer tree
90 0 : mFocusLayersId = target.mData.mRefLayerId;
91 0 : break;
92 : }
93 : case FocusTarget::eScrollLayer: {
94 : FS_LOG("Setting target to h=%" PRIu64 ", v=%" PRIu64 ", and seq=%" PRIu64 "\n",
95 : target.mData.mScrollTargets.mHorizontal,
96 : target.mData.mScrollTargets.mVertical,
97 : target.mSequenceNumber);
98 :
99 : // This is the global focus target
100 0 : mFocusHorizontalTarget = target.mData.mScrollTargets.mHorizontal;
101 0 : mFocusVerticalTarget = target.mData.mScrollTargets.mVertical;
102 :
103 : // Mark what sequence number this target has so we can determine whether
104 : // it is stale or not
105 0 : mLastContentProcessedEvent = target.mSequenceNumber;
106 0 : return;
107 : }
108 : case FocusTarget::eNone: {
109 : FS_LOG("Setting target to nil (reached a nil target)\n");
110 :
111 : // Mark what sequence number this target has for debugging purposes so
112 : // we can always accurately report on whether we are stale or not
113 0 : mLastContentProcessedEvent = target.mSequenceNumber;
114 0 : return;
115 : }
116 : }
117 0 : }
118 : }
119 :
120 : std::unordered_set<uint64_t>
121 28 : FocusState::GetFocusTargetLayerIds() const
122 : {
123 28 : std::unordered_set<uint64_t> layersIds;
124 28 : layersIds.reserve(mFocusTree.size());
125 :
126 28 : for (const auto& focusNode : mFocusTree) {
127 0 : layersIds.insert(focusNode.first);
128 : }
129 :
130 28 : return layersIds;
131 : }
132 :
133 : void
134 0 : FocusState::RemoveFocusTarget(uint64_t aLayersId)
135 : {
136 0 : mFocusTree.erase(aLayersId);
137 0 : }
138 :
139 : Maybe<ScrollableLayerGuid>
140 0 : FocusState::GetHorizontalTarget() const
141 : {
142 : // There is not a scrollable layer to async scroll if
143 : // 1. We aren't current
144 : // 2. There are event listeners that could change the focus
145 : // 3. The target has not been layerized
146 0 : if (!IsCurrent() ||
147 0 : mFocusHasKeyEventListeners ||
148 0 : mFocusHorizontalTarget == FrameMetrics::NULL_SCROLL_ID) {
149 0 : return Nothing();
150 : }
151 0 : return Some(ScrollableLayerGuid(mFocusLayersId, 0, mFocusHorizontalTarget));
152 : }
153 :
154 : Maybe<ScrollableLayerGuid>
155 0 : FocusState::GetVerticalTarget() const
156 : {
157 : // There is not a scrollable layer to async scroll if:
158 : // 1. We aren't current
159 : // 2. There are event listeners that could change the focus
160 : // 3. The target has not been layerized
161 0 : if (!IsCurrent() ||
162 0 : mFocusHasKeyEventListeners ||
163 0 : mFocusVerticalTarget == FrameMetrics::NULL_SCROLL_ID) {
164 0 : return Nothing();
165 : }
166 0 : return Some(ScrollableLayerGuid(mFocusLayersId, 0, mFocusVerticalTarget));
167 : }
168 :
169 : } // namespace layers
170 : } // namespace mozilla
|