snap_selection_strategy.h 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef CC_INPUT_SNAP_SELECTION_STRATEGY_H_
  5. #define CC_INPUT_SNAP_SELECTION_STRATEGY_H_
  6. #include <memory>
  7. #include "cc/input/scroll_snap_data.h"
  8. namespace cc {
  9. enum class SnapStopAlwaysFilter { kIgnore, kRequire };
  10. enum class SnapTargetsPrioritization { kIgnore, kRequire };
  11. // This class represents an abstract strategy that decide which snap selection
  12. // should be considered valid. There are concrete implementations for three core
  13. // scrolling types: scroll with end position only, scroll with direction only,
  14. // and scroll with end position and direction.
  15. class CC_EXPORT SnapSelectionStrategy {
  16. public:
  17. SnapSelectionStrategy() = default;
  18. virtual ~SnapSelectionStrategy() = default;
  19. static std::unique_ptr<SnapSelectionStrategy> CreateForEndPosition(
  20. const gfx::PointF& current_position,
  21. bool scrolled_x,
  22. bool scrolled_y,
  23. SnapTargetsPrioritization prioritization =
  24. SnapTargetsPrioritization::kIgnore);
  25. // |use_fractional_offsets| should be true when the current position is
  26. // provided in fractional pixels.
  27. static std::unique_ptr<SnapSelectionStrategy> CreateForDirection(
  28. gfx::PointF current_position,
  29. gfx::Vector2dF step,
  30. bool use_fractional_offsets,
  31. SnapStopAlwaysFilter filter = SnapStopAlwaysFilter::kIgnore);
  32. static std::unique_ptr<SnapSelectionStrategy> CreateForEndAndDirection(
  33. gfx::PointF current_position,
  34. gfx::Vector2dF displacement,
  35. bool use_fractional_offsets);
  36. // Creates a selection strategy that attempts to snap to previously snapped
  37. // targets if possible, but defaults to finding the closest snap point if
  38. // the target no longer exists.
  39. static std::unique_ptr<SnapSelectionStrategy> CreateForTargetElement(
  40. gfx::PointF current_position);
  41. // Returns whether it's snappable on x or y depending on the scroll performed.
  42. virtual bool ShouldSnapOnX() const = 0;
  43. virtual bool ShouldSnapOnY() const = 0;
  44. // Returns whether snapping should attempt to snap to the previously snapped
  45. // area if possible.
  46. virtual bool ShouldPrioritizeSnapTargets() const;
  47. // Returns the end position of the scroll if no snap interferes.
  48. virtual gfx::PointF intended_position() const = 0;
  49. // Returns the scroll position from which the snap position should minimize
  50. // its distance.
  51. virtual gfx::PointF base_position() const = 0;
  52. // Returns the current scroll position of the snap container.
  53. const gfx::PointF& current_position() const { return current_position_; }
  54. // Returns true if the selection strategy considers the given snap offset
  55. // valid for the current axis.
  56. virtual bool IsValidSnapPosition(SearchAxis axis, float position) const = 0;
  57. virtual bool IsValidSnapArea(SearchAxis axis, const SnapAreaData& data) const;
  58. virtual bool HasIntendedDirection() const;
  59. // Returns true if a snap area with scroll-snap-stop:always should not be
  60. // bypassed.
  61. virtual bool ShouldRespectSnapStop() const;
  62. // Returns the best result according to snap selection strategy. This method
  63. // is called at the end of selection process to make the final decision.
  64. //
  65. // -closest: snap search result representing closest match.
  66. // -covering: snap search result representing the original target if it makes
  67. // a snaparea covering the snapport.
  68. virtual const absl::optional<SnapSearchResult>& PickBestResult(
  69. const absl::optional<SnapSearchResult>& closest,
  70. const absl::optional<SnapSearchResult>& covering) const = 0;
  71. // Returns true when the current scroll offset is provided in fractional
  72. // pixels.
  73. virtual bool UsingFractionalOffsets() const;
  74. protected:
  75. explicit SnapSelectionStrategy(const gfx::PointF& current_position)
  76. : current_position_(current_position) {}
  77. const gfx::PointF current_position_;
  78. };
  79. // Examples for intended end position scrolls include
  80. // - a panning gesture, released without momentum
  81. // - manupulating the scrollbar "thumb" explicitly
  82. // - programmatically scrolling via APIs such as scrollTo()
  83. // - tabbing through the document's focusable elements
  84. // - navigating to an anchor within the page
  85. // - homing operations such as the Home/End keys
  86. // For this type of scrolls, we want to
  87. // * Minimize the distance between the snap position and the end position.
  88. // * Return the end position if that makes a snap area covers the snapport.
  89. class EndPositionStrategy : public SnapSelectionStrategy {
  90. public:
  91. EndPositionStrategy(const gfx::PointF& current_position,
  92. bool scrolled_x,
  93. bool scrolled_y,
  94. SnapTargetsPrioritization snap_targets_prioritization)
  95. : SnapSelectionStrategy(current_position),
  96. scrolled_x_(scrolled_x),
  97. scrolled_y_(scrolled_y),
  98. snap_targets_prioritization_(snap_targets_prioritization) {}
  99. ~EndPositionStrategy() override = default;
  100. bool ShouldSnapOnX() const override;
  101. bool ShouldSnapOnY() const override;
  102. gfx::PointF intended_position() const override;
  103. gfx::PointF base_position() const override;
  104. bool IsValidSnapPosition(SearchAxis axis, float position) const override;
  105. bool HasIntendedDirection() const override;
  106. bool ShouldPrioritizeSnapTargets() const override;
  107. const absl::optional<SnapSearchResult>& PickBestResult(
  108. const absl::optional<SnapSearchResult>& closest,
  109. const absl::optional<SnapSearchResult>& covering) const override;
  110. private:
  111. // Whether the x axis and y axis have been scrolled in this scroll gesture.
  112. const bool scrolled_x_;
  113. const bool scrolled_y_;
  114. SnapTargetsPrioritization snap_targets_prioritization_;
  115. };
  116. // Examples for intended direction scrolls include
  117. // - pressing an arrow key on the keyboard
  118. // - a swiping gesture interpreted as a fixed (rather than inertial) scroll
  119. // For this type of scrolls, we want to
  120. // * Minimize the distance between the snap position and the starting position,
  121. // so that we stop at the first snap position in that direction.
  122. // * Return the default intended position (using the default step) if that makes
  123. // a snap area covers the snapport.
  124. class DirectionStrategy : public SnapSelectionStrategy {
  125. public:
  126. // |use_fractional_offsets| should be true when the current position is
  127. // provided in fractional pixels.
  128. DirectionStrategy(const gfx::PointF& current_position,
  129. const gfx::Vector2dF& step,
  130. SnapStopAlwaysFilter filter,
  131. bool use_fractional_offsets)
  132. : SnapSelectionStrategy(current_position),
  133. step_(step),
  134. snap_stop_always_filter_(filter),
  135. use_fractional_offsets_(use_fractional_offsets) {}
  136. ~DirectionStrategy() override = default;
  137. bool ShouldSnapOnX() const override;
  138. bool ShouldSnapOnY() const override;
  139. gfx::PointF intended_position() const override;
  140. gfx::PointF base_position() const override;
  141. bool IsValidSnapPosition(SearchAxis axis, float position) const override;
  142. bool IsValidSnapArea(SearchAxis axis,
  143. const SnapAreaData& area) const override;
  144. const absl::optional<SnapSearchResult>& PickBestResult(
  145. const absl::optional<SnapSearchResult>& closest,
  146. const absl::optional<SnapSearchResult>& covering) const override;
  147. bool UsingFractionalOffsets() const override;
  148. private:
  149. // The default step for this DirectionStrategy.
  150. const gfx::Vector2dF step_;
  151. SnapStopAlwaysFilter snap_stop_always_filter_;
  152. bool use_fractional_offsets_;
  153. };
  154. // Examples for intended direction and end position scrolls include
  155. // - a “fling” gesture, interpreted with momentum
  156. // - programmatically scrolling via APIs such as scrollBy()
  157. // - paging operations such as the PgUp/PgDn keys (or equivalent operations on
  158. // the scrollbar)
  159. // For this type of scrolls, we want to
  160. // * Minimize the distance between the snap position and the end position.
  161. // * Return the end position if that makes a snap area covers the snapport.
  162. class EndAndDirectionStrategy : public SnapSelectionStrategy {
  163. public:
  164. // |use_fractional_offsets| should be true when the current position is
  165. // provided in fractional pixels.
  166. EndAndDirectionStrategy(const gfx::PointF& current_position,
  167. const gfx::Vector2dF& displacement,
  168. bool use_fractional_offsets)
  169. : SnapSelectionStrategy(current_position),
  170. displacement_(displacement),
  171. use_fractional_offsets_(use_fractional_offsets) {}
  172. ~EndAndDirectionStrategy() override = default;
  173. bool ShouldSnapOnX() const override;
  174. bool ShouldSnapOnY() const override;
  175. gfx::PointF intended_position() const override;
  176. gfx::PointF base_position() const override;
  177. bool IsValidSnapPosition(SearchAxis axis, float position) const override;
  178. bool ShouldRespectSnapStop() const override;
  179. const absl::optional<SnapSearchResult>& PickBestResult(
  180. const absl::optional<SnapSearchResult>& closest,
  181. const absl::optional<SnapSearchResult>& covering) const override;
  182. bool UsingFractionalOffsets() const override;
  183. private:
  184. const gfx::Vector2dF displacement_;
  185. bool use_fractional_offsets_;
  186. };
  187. } // namespace cc
  188. #endif // CC_INPUT_SNAP_SELECTION_STRATEGY_H_