1 // Copyright 2016 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 
5 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_SCROLL_PAINT_PROPERTY_NODE_H_
6 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_SCROLL_PAINT_PROPERTY_NODE_H_
7 
8 #include <algorithm>
9 #include "base/optional.h"
10 #include "cc/input/main_thread_scrolling_reason.h"
11 #include "cc/input/overscroll_behavior.h"
12 #include "cc/input/scroll_snap_data.h"
13 #include "third_party/blink/renderer/platform/geometry/float_point.h"
14 #include "third_party/blink/renderer/platform/geometry/float_size.h"
15 #include "third_party/blink/renderer/platform/geometry/int_rect.h"
16 #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
17 #include "third_party/blink/renderer/platform/graphics/paint/paint_property_node.h"
18 #include "third_party/blink/renderer/platform/platform_export.h"
19 
20 namespace blink {
21 
22 using MainThreadScrollingReasons = uint32_t;
23 
24 // A scroll node contains auxiliary scrolling information which includes how far
25 // an area can be scrolled, main thread scrolling reasons, etc. Scroll nodes
26 // are referenced by TransformPaintPropertyNodes that are used for the scroll
27 // offset translation, though scroll offset translation can exist without a
28 // scroll node (e.g., overflow: hidden).
29 //
30 // Main thread scrolling reasons force scroll updates to go to the main thread
31 // and can have dependencies on other nodes. For example, all parents of a
32 // scroll node with background attachment fixed set should also have it set.
33 //
34 // The scroll tree differs from the other trees because it does not affect
35 // geometry directly.
36 class PLATFORM_EXPORT ScrollPaintPropertyNode
37     : public PaintPropertyNode<ScrollPaintPropertyNode,
38                                ScrollPaintPropertyNode> {
39  public:
40   // To make it less verbose and more readable to construct and update a node,
41   // a struct with default values is used to represent the state.
42   struct State {
43     IntRect container_rect;
44     IntSize contents_size;
45     bool user_scrollable_horizontal = false;
46     bool user_scrollable_vertical = false;
47 
48     // This bit tells the compositor whether the inner viewport should be
49     // scrolled using the full viewport mechanism (overscroll, top control
50     // movement, inner+outer panning, etc.). This can differ depending on
51     // whether the page has a non-default root scroller and is used to affect
52     // scroll chaining from fixed elements. See discussion on
53     // https://crbug.com/977954 for details.
54     bool prevent_viewport_scrolling_from_inner = false;
55 
56     bool max_scroll_offset_affected_by_page_scale = false;
57     MainThreadScrollingReasons main_thread_scrolling_reasons =
58         cc::MainThreadScrollingReason::kNotScrollingOnMain;
59     // The scrolling element id is stored directly on the scroll node and not
60     // on the associated TransformPaintPropertyNode used for scroll offset.
61     CompositorElementId compositor_element_id;
62     cc::OverscrollBehavior overscroll_behavior =
63         cc::OverscrollBehavior(cc::OverscrollBehavior::Type::kAuto);
64     base::Optional<cc::SnapContainerData> snap_container_data;
65 
ComputeChangeState66     PaintPropertyChangeType ComputeChange(const State& other) const {
67       if (container_rect != other.container_rect ||
68           contents_size != other.contents_size ||
69           user_scrollable_horizontal != other.user_scrollable_horizontal ||
70           user_scrollable_vertical != other.user_scrollable_vertical ||
71           prevent_viewport_scrolling_from_inner !=
72               other.prevent_viewport_scrolling_from_inner ||
73           max_scroll_offset_affected_by_page_scale !=
74               other.max_scroll_offset_affected_by_page_scale ||
75           main_thread_scrolling_reasons !=
76               other.main_thread_scrolling_reasons ||
77           compositor_element_id != other.compositor_element_id ||
78           overscroll_behavior != other.overscroll_behavior ||
79           snap_container_data != other.snap_container_data) {
80         return PaintPropertyChangeType::kChangedOnlyValues;
81       }
82       return PaintPropertyChangeType::kUnchanged;
83     }
84   };
85 
86   // This node is really a sentinel, and does not represent a real scroll.
87   static const ScrollPaintPropertyNode& Root();
88 
Create(const ScrollPaintPropertyNode & parent,State && state)89   static scoped_refptr<ScrollPaintPropertyNode> Create(
90       const ScrollPaintPropertyNode& parent,
91       State&& state) {
92     return base::AdoptRef(
93         new ScrollPaintPropertyNode(&parent, std::move(state)));
94   }
CreateAlias(const ScrollPaintPropertyNode &)95   static scoped_refptr<ScrollPaintPropertyNode> CreateAlias(
96       const ScrollPaintPropertyNode&) {
97     // ScrollPaintPropertyNodes cannot be aliases.
98     NOTREACHED();
99     return nullptr;
100   }
101 
102   // The empty AnimationState struct is to meet the requirement of
103   // ObjectPaintProperties.
104   struct AnimationState {};
105   PaintPropertyChangeType Update(const ScrollPaintPropertyNode& parent,
106                                  State&& state,
107                                  const AnimationState& = AnimationState()) {
108     auto parent_changed = SetParent(parent);
109     auto state_changed = state_.ComputeChange(state);
110     if (state_changed != PaintPropertyChangeType::kUnchanged) {
111       state_ = std::move(state);
112       Validate();
113       AddChanged(state_changed);
114     }
115     return std::max(parent_changed, state_changed);
116   }
117 
118   const ScrollPaintPropertyNode& Unalias() const = delete;
119 
OverscrollBehaviorX()120   cc::OverscrollBehavior::Type OverscrollBehaviorX() const {
121     return state_.overscroll_behavior.x;
122   }
123 
OverscrollBehaviorY()124   cc::OverscrollBehavior::Type OverscrollBehaviorY() const {
125     return state_.overscroll_behavior.y;
126   }
127 
GetSnapContainerData()128   base::Optional<cc::SnapContainerData> GetSnapContainerData() const {
129     return state_.snap_container_data;
130   }
131 
132   // Rect of the container area that the contents scrolls in, in the space of
133   // the parent of the associated transform node (ScrollTranslation).
134   // It doesn't include non-overlay scrollbars. Overlay scrollbars do not affect
135   // the rect.
ContainerRect()136   const IntRect& ContainerRect() const { return state_.container_rect; }
137 
138   // Size of the contents that is scrolled within the container rect.
ContentsSize()139   const IntSize& ContentsSize() const { return state_.contents_size; }
140 
UserScrollableHorizontal()141   bool UserScrollableHorizontal() const {
142     return state_.user_scrollable_horizontal;
143   }
UserScrollableVertical()144   bool UserScrollableVertical() const {
145     return state_.user_scrollable_vertical;
146   }
PreventViewportScrollingFromInner()147   bool PreventViewportScrollingFromInner() const {
148     return state_.prevent_viewport_scrolling_from_inner;
149   }
MaxScrollOffsetAffectedByPageScale()150   bool MaxScrollOffsetAffectedByPageScale() const {
151     return state_.max_scroll_offset_affected_by_page_scale;
152   }
153 
154   // Return reason bitfield with values from cc::MainThreadScrollingReason.
GetMainThreadScrollingReasons()155   MainThreadScrollingReasons GetMainThreadScrollingReasons() const {
156     return state_.main_thread_scrolling_reasons;
157   }
158 
159   // Main thread scrolling reason for the threaded scrolling disabled setting.
ThreadedScrollingDisabled()160   bool ThreadedScrollingDisabled() const {
161     return state_.main_thread_scrolling_reasons &
162            cc::MainThreadScrollingReason::kThreadedScrollingDisabled;
163   }
164 
165   // Main thread scrolling reason for background attachment fixed descendants.
HasBackgroundAttachmentFixedDescendants()166   bool HasBackgroundAttachmentFixedDescendants() const {
167     return state_.main_thread_scrolling_reasons &
168            cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
169   }
170 
GetCompositorElementId()171   const CompositorElementId& GetCompositorElementId() const {
172     return state_.compositor_element_id;
173   }
174 
175   std::unique_ptr<JSONObject> ToJSON() const;
176 
177  private:
ScrollPaintPropertyNode(const ScrollPaintPropertyNode * parent,State && state)178   ScrollPaintPropertyNode(const ScrollPaintPropertyNode* parent, State&& state)
179       : PaintPropertyNode(parent), state_(std::move(state)) {
180     Validate();
181   }
182 
183   using PaintPropertyNode::SetParent;
184 
Validate()185   void Validate() const {
186 #if DCHECK_IS_ON()
187     DCHECK(!state_.compositor_element_id ||
188            NamespaceFromCompositorElementId(state_.compositor_element_id) ==
189                CompositorElementIdNamespace::kScroll);
190 #endif
191   }
192 
193   State state_;
194 };
195 
196 }  // namespace blink
197 
198 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_SCROLL_PAINT_PROPERTY_NODE_H_
199