OLD | NEW |
| (Empty) |
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 #include "core/page/scrolling/RootScroller.h" | |
6 | |
7 #include "core/dom/Document.h" | |
8 #include "core/dom/Element.h" | |
9 #include "core/frame/FrameHost.h" | |
10 #include "core/frame/FrameView.h" | |
11 #include "core/frame/TopControls.h" | |
12 #include "core/layout/LayoutBox.h" | |
13 #include "core/page/Page.h" | |
14 #include "core/page/scrolling/OverscrollController.h" | |
15 #include "core/page/scrolling/ViewportScrollCallback.h" | |
16 #include "core/paint/PaintLayerScrollableArea.h" | |
17 #include "platform/scroll/ScrollableArea.h" | |
18 | |
19 namespace blink { | |
20 | |
21 namespace { | |
22 | |
23 ScrollableArea* scrollableAreaFor(const Element& element) | |
24 { | |
25 if (!element.layoutObject() || !element.layoutObject()->isBox()) | |
26 return nullptr; | |
27 | |
28 LayoutBox* box = toLayoutBox(element.layoutObject()); | |
29 | |
30 if (box->isDocumentElement()) | |
31 return element.document().view()->getScrollableArea(); | |
32 | |
33 return static_cast<PaintInvalidationCapableScrollableArea*>( | |
34 box->getScrollableArea()); | |
35 } | |
36 | |
37 bool fillsViewport(const Element& element) | |
38 { | |
39 DCHECK(element.layoutObject()); | |
40 DCHECK(element.layoutObject()->isBox()); | |
41 | |
42 LayoutObject* layoutObject = element.layoutObject(); | |
43 | |
44 // TODO(bokan): Broken for OOPIF. | |
45 Document& topDocument = element.document().topDocument(); | |
46 | |
47 Vector<FloatQuad> quads; | |
48 layoutObject->absoluteQuads(quads); | |
49 DCHECK_EQ(quads.size(), 1u); | |
50 | |
51 if (!quads[0].isRectilinear()) | |
52 return false; | |
53 | |
54 LayoutRect boundingBox(quads[0].boundingBox()); | |
55 | |
56 return boundingBox.location() == LayoutPoint::zero() | |
57 && boundingBox.size() == topDocument.layoutViewItem().size(); | |
58 } | |
59 | |
60 bool isValidRootScroller(const Element& element) | |
61 { | |
62 if (!element.layoutObject()) | |
63 return false; | |
64 | |
65 if (!scrollableAreaFor(element)) | |
66 return false; | |
67 | |
68 if (!fillsViewport(element)) | |
69 return false; | |
70 | |
71 return true; | |
72 } | |
73 | |
74 } // namespace | |
75 | |
76 ViewportScrollCallback* RootScroller::createViewportApplyScroll( | |
77 TopControls& topControls, OverscrollController& overscrollController) | |
78 { | |
79 return new ViewportScrollCallback(topControls, overscrollController); | |
80 } | |
81 | |
82 RootScroller::RootScroller(Document& document, ViewportScrollCallback* applyScro
llCallback) | |
83 : m_document(&document) | |
84 , m_viewportApplyScroll(applyScrollCallback) | |
85 { | |
86 } | |
87 | |
88 DEFINE_TRACE(RootScroller) | |
89 { | |
90 visitor->trace(m_document); | |
91 visitor->trace(m_viewportApplyScroll); | |
92 visitor->trace(m_rootScroller); | |
93 visitor->trace(m_effectiveRootScroller); | |
94 } | |
95 | |
96 void RootScroller::set(Element* newRootScroller) | |
97 { | |
98 m_rootScroller = newRootScroller; | |
99 updateEffectiveRootScroller(); | |
100 } | |
101 | |
102 Element* RootScroller::get() const | |
103 { | |
104 return m_rootScroller; | |
105 } | |
106 | |
107 Element* RootScroller::effectiveRootScroller() const | |
108 { | |
109 return m_effectiveRootScroller; | |
110 } | |
111 | |
112 void RootScroller::didUpdateLayout() | |
113 { | |
114 updateEffectiveRootScroller(); | |
115 } | |
116 | |
117 void RootScroller::updateEffectiveRootScroller() | |
118 { | |
119 bool rootScrollerValid = | |
120 m_rootScroller && isValidRootScroller(*m_rootScroller); | |
121 | |
122 Element* newEffectiveRootScroller = rootScrollerValid | |
123 ? m_rootScroller.get() | |
124 : defaultEffectiveRootScroller(); | |
125 | |
126 if (m_effectiveRootScroller == newEffectiveRootScroller) | |
127 return; | |
128 | |
129 moveViewportApplyScroll(newEffectiveRootScroller); | |
130 m_effectiveRootScroller = newEffectiveRootScroller; | |
131 } | |
132 | |
133 void RootScroller::moveViewportApplyScroll(Element* target) | |
134 { | |
135 if (!m_viewportApplyScroll) | |
136 return; | |
137 | |
138 if (m_effectiveRootScroller) | |
139 m_effectiveRootScroller->removeApplyScroll(); | |
140 | |
141 ScrollableArea* targetScroller = | |
142 target ? scrollableAreaFor(*target) : nullptr; | |
143 | |
144 if (targetScroller) { | |
145 // Use disable-native-scroll since the ViewportScrollCallback needs to | |
146 // apply scroll actions both before (TopControls) and after (overscroll) | |
147 // scrolling the element so it will apply scroll to the element itself. | |
148 target->setApplyScroll( | |
149 m_viewportApplyScroll, | |
150 "disable-native-scroll"); | |
151 } | |
152 | |
153 // Ideally, scroll customization would pass the current element to scroll to | |
154 // the apply scroll callback but this doesn't happen today so we set it | |
155 // through a back door here. | |
156 m_viewportApplyScroll->setScroller(targetScroller); | |
157 } | |
158 | |
159 Element* RootScroller::defaultEffectiveRootScroller() | |
160 { | |
161 DCHECK(m_document); | |
162 return m_document->documentElement(); | |
163 } | |
164 | |
165 } // namespace blink | |
OLD | NEW |