OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/dom/IntersectionObserver.h" | 5 #include "core/dom/IntersectionObserver.h" |
6 | 6 |
7 #include "bindings/core/v8/ExceptionState.h" | 7 #include "bindings/core/v8/ExceptionState.h" |
8 #include "core/css/parser/CSSParserTokenRange.h" | 8 #include "core/css/parser/CSSParserTokenRange.h" |
9 #include "core/css/parser/CSSTokenizer.h" | 9 #include "core/css/parser/CSSTokenizer.h" |
| 10 #include "core/dom/ElementIntersectionObserverData.h" |
10 #include "core/dom/ExceptionCode.h" | 11 #include "core/dom/ExceptionCode.h" |
11 #include "core/dom/ExecutionContext.h" | 12 #include "core/dom/ExecutionContext.h" |
12 #include "core/dom/IntersectionObserverCallback.h" | 13 #include "core/dom/IntersectionObserverCallback.h" |
13 #include "core/dom/IntersectionObserverController.h" | 14 #include "core/dom/IntersectionObserverController.h" |
14 #include "core/dom/IntersectionObserverEntry.h" | 15 #include "core/dom/IntersectionObserverEntry.h" |
15 #include "core/dom/IntersectionObserverInit.h" | 16 #include "core/dom/IntersectionObserverInit.h" |
16 #include "core/dom/NodeIntersectionObserverData.h" | |
17 #include "core/html/HTMLFrameOwnerElement.h" | 17 #include "core/html/HTMLFrameOwnerElement.h" |
18 #include "core/layout/LayoutView.h" | 18 #include "core/layout/LayoutView.h" |
19 #include "platform/Timer.h" | 19 #include "platform/Timer.h" |
20 #include "wtf/MainThread.h" | 20 #include "wtf/MainThread.h" |
21 #include <algorithm> | 21 #include <algorithm> |
22 | 22 |
23 namespace blink { | 23 namespace blink { |
24 | 24 |
25 static void parseRootMargin(String rootMarginParameter, Vector<Length>& rootMarg
in, ExceptionState& exceptionState) | 25 static void parseRootMargin(String rootMarginParameter, Vector<Length>& rootMarg
in, ExceptionState& exceptionState) |
26 { | 26 { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 exceptionState.throwTypeError("Threshold values must be between 0 an
d 1"); | 74 exceptionState.throwTypeError("Threshold values must be between 0 an
d 1"); |
75 break; | 75 break; |
76 } | 76 } |
77 } | 77 } |
78 | 78 |
79 std::sort(thresholds.begin(), thresholds.end()); | 79 std::sort(thresholds.begin(), thresholds.end()); |
80 } | 80 } |
81 | 81 |
82 IntersectionObserver* IntersectionObserver::create(const IntersectionObserverIni
t& observerInit, IntersectionObserverCallback& callback, ExceptionState& excepti
onState) | 82 IntersectionObserver* IntersectionObserver::create(const IntersectionObserverIni
t& observerInit, IntersectionObserverCallback& callback, ExceptionState& excepti
onState) |
83 { | 83 { |
84 RefPtrWillBeRawPtr<Node> root = observerInit.root(); | 84 RefPtrWillBeRawPtr<Element> root = observerInit.root(); |
85 if (!root) { | 85 if (!root) { |
86 // TODO(szager): Use Document instead of document element for implicit r
oot. (crbug.com/570538) | 86 // TODO(szager): Use Document instead of document element for implicit r
oot. (crbug.com/570538) |
87 ExecutionContext* context = callback.executionContext(); | 87 ExecutionContext* context = callback.executionContext(); |
88 ASSERT(context->isDocument()); | 88 ASSERT(context->isDocument()); |
89 Frame* mainFrame = toDocument(context)->frame()->tree().top(); | 89 Frame* mainFrame = toDocument(context)->frame()->tree().top(); |
90 if (mainFrame && mainFrame->isLocalFrame()) | 90 if (mainFrame && mainFrame->isLocalFrame()) |
91 root = toLocalFrame(mainFrame)->document(); | 91 root = toLocalFrame(mainFrame)->document()->documentElement(); |
92 } | 92 } |
93 if (!root) { | 93 if (!root) { |
94 exceptionState.throwDOMException(HierarchyRequestError, "Unable to get r
oot node in main frame to track."); | 94 exceptionState.throwDOMException(HierarchyRequestError, "Unable to get r
oot element in main frame to track."); |
95 return nullptr; | 95 return nullptr; |
96 } | 96 } |
97 | 97 |
98 Vector<Length> rootMargin; | 98 Vector<Length> rootMargin; |
99 if (observerInit.hasRootMargin()) | 99 if (observerInit.hasRootMargin()) |
100 parseRootMargin(observerInit.rootMargin(), rootMargin, exceptionState); | 100 parseRootMargin(observerInit.rootMargin(), rootMargin, exceptionState); |
101 if (exceptionState.hadException()) | 101 if (exceptionState.hadException()) |
102 return nullptr; | 102 return nullptr; |
103 | 103 |
104 Vector<float> thresholds; | 104 Vector<float> thresholds; |
105 if (observerInit.hasThreshold()) | 105 if (observerInit.hasThreshold()) |
106 parseThresholds(observerInit.threshold(), thresholds, exceptionState); | 106 parseThresholds(observerInit.threshold(), thresholds, exceptionState); |
107 else | 107 else |
108 thresholds.append(0); | 108 thresholds.append(0); |
109 if (exceptionState.hadException()) | 109 if (exceptionState.hadException()) |
110 return nullptr; | 110 return nullptr; |
111 | 111 |
112 return new IntersectionObserver(callback, *root, rootMargin, thresholds); | 112 return new IntersectionObserver(callback, *root, rootMargin, thresholds); |
113 } | 113 } |
114 | 114 |
115 IntersectionObserver::IntersectionObserver(IntersectionObserverCallback& callbac
k, Node& root, const Vector<Length>& rootMargin, const Vector<float>& thresholds
) | 115 IntersectionObserver::IntersectionObserver(IntersectionObserverCallback& callbac
k, Element& root, const Vector<Length>& rootMargin, const Vector<float>& thresho
lds) |
116 : m_callback(&callback) | 116 : m_callback(&callback) |
| 117 , m_root(root.ensureIntersectionObserverData().createWeakPtr(&root)) |
117 , m_thresholds(thresholds) | 118 , m_thresholds(thresholds) |
118 , m_topMargin(Fixed) | 119 , m_topMargin(Fixed) |
119 , m_rightMargin(Fixed) | 120 , m_rightMargin(Fixed) |
120 , m_bottomMargin(Fixed) | 121 , m_bottomMargin(Fixed) |
121 , m_leftMargin(Fixed) | 122 , m_leftMargin(Fixed) |
122 { | 123 { |
123 if (root.isDocumentNode()) | |
124 m_root = toDocument(root).ensureIntersectionObserverData().createWeakPtr
(&root); | |
125 else | |
126 m_root = toElement(root).ensureIntersectionObserverData().createWeakPtr(
&root); | |
127 switch (rootMargin.size()) { | 124 switch (rootMargin.size()) { |
128 case 0: | 125 case 0: |
129 break; | 126 break; |
130 case 1: | 127 case 1: |
131 m_topMargin = m_rightMargin = m_bottomMargin = m_leftMargin = rootMargin
[0]; | 128 m_topMargin = m_rightMargin = m_bottomMargin = m_leftMargin = rootMargin
[0]; |
132 break; | 129 break; |
133 case 2: | 130 case 2: |
134 m_topMargin = m_bottomMargin = rootMargin[0]; | 131 m_topMargin = m_bottomMargin = rootMargin[0]; |
135 m_rightMargin = m_leftMargin = rootMargin[1]; | 132 m_rightMargin = m_leftMargin = rootMargin[1]; |
136 break; | 133 break; |
137 case 3: | 134 case 3: |
138 m_topMargin = rootMargin[0]; | 135 m_topMargin = rootMargin[0]; |
139 m_rightMargin = m_leftMargin = rootMargin[1]; | 136 m_rightMargin = m_leftMargin = rootMargin[1]; |
140 m_bottomMargin = rootMargin[2]; | 137 m_bottomMargin = rootMargin[2]; |
141 break; | 138 break; |
142 case 4: | 139 case 4: |
143 m_topMargin = rootMargin[0]; | 140 m_topMargin = rootMargin[0]; |
144 m_rightMargin = rootMargin[1]; | 141 m_rightMargin = rootMargin[1]; |
145 m_bottomMargin = rootMargin[2]; | 142 m_bottomMargin = rootMargin[2]; |
146 m_leftMargin = rootMargin[3]; | 143 m_leftMargin = rootMargin[3]; |
147 break; | 144 break; |
148 default: | 145 default: |
149 ASSERT_NOT_REACHED(); | 146 ASSERT_NOT_REACHED(); |
150 break; | 147 break; |
151 } | 148 } |
152 root.document().ensureIntersectionObserverController().addTrackedObserver(*t
his); | 149 root.document().ensureIntersectionObserverController().addTrackedObserver(*t
his); |
153 } | 150 } |
154 | 151 |
155 LayoutObject* IntersectionObserver::rootLayoutObject() const | 152 LayoutObject* IntersectionObserver::rootLayoutObject() |
156 { | 153 { |
157 Node* rootNode = root(); | 154 Element* rootElement = root(); |
158 if (rootNode->isDocumentNode()) | 155 if (rootElement == rootElement->document().documentElement()) |
159 return toDocument(rootNode)->layoutView(); | 156 return rootElement->document().layoutView(); |
160 return toElement(rootNode)->layoutObject(); | 157 return rootElement->layoutObject(); |
161 } | 158 } |
162 | 159 |
163 bool IntersectionObserver::isDescendantOfRoot(const Element* target) const | 160 bool IntersectionObserver::isDescendantOfRoot(const Element* target) const |
164 { | 161 { |
165 // Is m_root an ancestor, through the DOM and frame trees, of target? | 162 // Is m_root an ancestor, through the DOM and frame trees, of target? |
166 Node* rootNode = root(); | 163 Element* rootElement = m_root.get(); |
167 if (!rootNode || !target || target == rootNode) | 164 if (!rootElement || !target || target == rootElement) |
168 return false; | 165 return false; |
169 if (!target->inDocument() || !rootNode->inDocument()) | 166 if (!target->inDocument() || !rootElement->inDocument()) |
170 return false; | 167 return false; |
171 | 168 |
172 Document* rootDocument = &rootNode->document(); | 169 Document* rootDocument = &rootElement->document(); |
173 Document* targetDocument = &target->document(); | 170 Document* targetDocument = &target->document(); |
174 while (targetDocument != rootDocument) { | 171 while (targetDocument != rootDocument) { |
175 target = targetDocument->ownerElement(); | 172 target = targetDocument->ownerElement(); |
176 if (!target) | 173 if (!target) |
177 return false; | 174 return false; |
178 targetDocument = &target->document(); | 175 targetDocument = &target->document(); |
179 } | 176 } |
180 if (rootNode->isDocumentNode()) { | 177 return target->isDescendantOf(rootElement); |
181 ASSERT(targetDocument == rootNode); | |
182 return true; | |
183 } | |
184 return target->isDescendantOf(rootNode); | |
185 } | 178 } |
186 | 179 |
187 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) | 180 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) |
188 { | 181 { |
189 checkRootAndDetachIfNeeded(); | 182 checkRootAndDetachIfNeeded(); |
190 if (!m_root) { | 183 if (!m_root) { |
191 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); | 184 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); |
192 return; | 185 return; |
193 } | 186 } |
194 if (!target) { | 187 if (!target) { |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 | 336 |
344 DEFINE_TRACE(IntersectionObserver) | 337 DEFINE_TRACE(IntersectionObserver) |
345 { | 338 { |
346 visitor->trace(m_callback); | 339 visitor->trace(m_callback); |
347 visitor->trace(m_root); | 340 visitor->trace(m_root); |
348 visitor->trace(m_observations); | 341 visitor->trace(m_observations); |
349 visitor->trace(m_entries); | 342 visitor->trace(m_entries); |
350 } | 343 } |
351 | 344 |
352 } // namespace blink | 345 } // namespace blink |
OLD | NEW |