summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h
blob: 63380b0f538e5f31d9028f019c8d462b0a2a4487 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SPATIAL_NAVIGATION_CONTROLLER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SPATIAL_NAVIGATION_CONTROLLER_H_

#include "third_party/blink/public/mojom/page/spatial_navigation.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/page/spatial_navigation.h"
#include "third_party/blink/renderer/platform/heap/handle.h"

namespace blink {

struct FocusCandidate;
class KeyboardEvent;
class LocalFrameView;
class Node;
class Page;
struct PhysicalRect;

// Encapsulates logic and state related to "spatial navigation". Spatial
// Navigation is used to move and interact with a page in a purely directional
// way, e.g. keyboard arrows. We use the term "interest" to specify which
// element the user is currently on.
class CORE_EXPORT SpatialNavigationController
    : public GarbageCollectedFinalized<SpatialNavigationController> {
 public:
  explicit SpatialNavigationController(Page& page);

  bool HandleArrowKeyboardEvent(KeyboardEvent* event);
  bool HandleEnterKeyboardEvent(KeyboardEvent* event);
  bool HandleEscapeKeyboardEvent(KeyboardEvent* event);
  bool HandleImeSubmitKeyboardEvent(KeyboardEvent* event);

  // Called when the enter key is released to clear local state because we don't
  // get a consistent event stream when the Enter key is partially handled.
  void ResetEnterKeyState();

  // Returns the element that's currently interested. i.e. the Element that's
  // currently indicated to the user.
  Element* GetInterestedElement() const;

  void DidDetachFrameView(const LocalFrameView&);

  void OnSpatialNavigationSettingChanged();
  void FocusedNodeChanged(Document*);
  void FullscreenStateChanged(Element* element);

  void Trace(blink::Visitor*);

 private:
  // Entry-point into SpatialNavigation advancement. Will return true if an
  // action (moving interest or scrolling), false otherwise.
  bool Advance(SpatialNavigationDirection direction);

  /*
   * Advances interest only within the specified container. Returns true if
   * interest was advanced or the container was scrolled, false if no
   * advancement was possible within the container.
   *
   * container - The scrollable container within which to limit advancement.
   * starting_rect_in_root_frame - The rect to use to begin searching for the
   *                               next node. Intuitively, the interest node's
   *                               rect (but sometimes different for scrollers).
   * direction - Direction of advancement
   * interest_child_in_container - The inner-most child _within this container_
   *                               where interest is located. This may differ
   *                               from the starting_rect as the interest node
   *                               may be in a nested container.
   */
  bool AdvanceWithinContainer(Node& container,
                              const PhysicalRect& starting_rect_in_root_frame,
                              SpatialNavigationDirection direction,
                              Node* interest_child_in_container);

  // Parameters have same meanings as method above.
  FocusCandidate FindNextCandidateInContainer(
      Node& container,
      const PhysicalRect& starting_rect_in_root_frame,
      SpatialNavigationDirection direction,
      Node* interest_child_in_container);

  // Returns which Node we're starting navigation from or nullptr if we should
  // abort navigation.
  Node* StartingNode();
  void MoveInterestTo(Node* next_node);

  // Dispatches a fake mouse move event at the center of the given element to
  // produce hover state and mouse enter/exit events. If no element is given,
  // we dispatch a mouse event outside of the page to simulate the pointer
  // leaving the page (and clearing hover, producing mouse leave).
  void DispatchMouseMoveAt(Element* element);

  // Returns true if the element should be considered for navigation.
  bool IsValidCandidate(const Element* element) const;

  Element* GetFocusedElement() const;

  void UpdateSpatialNavigationState(Element* element);
  void OnSpatialNavigationStateChanged();
  bool UpdateCanExitFocus(Element* element);
  bool UpdateCanSelectInterestedElement(Element* element);
  bool UpdateHasNextFormElement(Element* element);
  bool UpdateIsFormFocused(Element* element);
  bool UpdateHasDefaultVideoControls(Element* element);

  const mojom::blink::SpatialNavigationHostPtr& GetSpatialNavigationHost();
  void ResetMojoBindings();

  // The currently indicated element or nullptr if no node is indicated by
  // spatial navigation.
  WeakMember<Element> interest_element_;
  Member<Page> page_;

  // We need to track whether the enter key has been handled in down or press to
  // know whether to generate a click on the up.
  bool enter_key_down_seen_ = false;
  bool enter_key_press_seen_ = false;

  mojom::blink::SpatialNavigationStatePtr spatial_navigation_state_;
  mojom::blink::SpatialNavigationHostPtr spatial_navigation_host_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SPATIAL_NAVIGATION_CONTROLLER_H_