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" | |
11 #include "core/dom/ExceptionCode.h" | 10 #include "core/dom/ExceptionCode.h" |
12 #include "core/dom/ExecutionContext.h" | 11 #include "core/dom/ExecutionContext.h" |
13 #include "core/dom/IntersectionObserverCallback.h" | 12 #include "core/dom/IntersectionObserverCallback.h" |
14 #include "core/dom/IntersectionObserverController.h" | 13 #include "core/dom/IntersectionObserverController.h" |
15 #include "core/dom/IntersectionObserverEntry.h" | 14 #include "core/dom/IntersectionObserverEntry.h" |
16 #include "core/dom/IntersectionObserverInit.h" | 15 #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<Element> root = observerInit.root(); | 84 RefPtrWillBeRawPtr<Node> 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()->documentElement(); | 91 root = toLocalFrame(mainFrame)->document(); |
92 } | 92 } |
93 if (!root) { | 93 if (!root) { |
94 exceptionState.throwDOMException(HierarchyRequestError, "Unable to get r
oot element in main frame to track."); | 94 exceptionState.throwDOMException(HierarchyRequestError, "Unable to get r
oot node 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, Element& root, const Vector<Length>& rootMargin, const Vector<float>& thresho
lds) | 115 IntersectionObserver::IntersectionObserver(IntersectionObserverCallback& callbac
k, Node& root, const Vector<Length>& rootMargin, const Vector<float>& thresholds
) |
116 : m_callback(&callback) | 116 : m_callback(&callback) |
117 , m_root(root.ensureIntersectionObserverData().createWeakPtr(&root)) | |
118 , m_thresholds(thresholds) | 117 , m_thresholds(thresholds) |
119 , m_topMargin(Fixed) | 118 , m_topMargin(Fixed) |
120 , m_rightMargin(Fixed) | 119 , m_rightMargin(Fixed) |
121 , m_bottomMargin(Fixed) | 120 , m_bottomMargin(Fixed) |
122 , m_leftMargin(Fixed) | 121 , m_leftMargin(Fixed) |
123 { | 122 { |
| 123 if (root.isDocumentNode()) |
| 124 m_root = toDocument(root).ensureIntersectionObserverData().createWeakPtr
(&root); |
| 125 else |
| 126 m_root = toElement(root).ensureIntersectionObserverData().createWeakPtr(
&root); |
124 switch (rootMargin.size()) { | 127 switch (rootMargin.size()) { |
125 case 0: | 128 case 0: |
126 break; | 129 break; |
127 case 1: | 130 case 1: |
128 m_topMargin = m_rightMargin = m_bottomMargin = m_leftMargin = rootMargin
[0]; | 131 m_topMargin = m_rightMargin = m_bottomMargin = m_leftMargin = rootMargin
[0]; |
129 break; | 132 break; |
130 case 2: | 133 case 2: |
131 m_topMargin = m_bottomMargin = rootMargin[0]; | 134 m_topMargin = m_bottomMargin = rootMargin[0]; |
132 m_rightMargin = m_leftMargin = rootMargin[1]; | 135 m_rightMargin = m_leftMargin = rootMargin[1]; |
133 break; | 136 break; |
134 case 3: | 137 case 3: |
135 m_topMargin = rootMargin[0]; | 138 m_topMargin = rootMargin[0]; |
136 m_rightMargin = m_leftMargin = rootMargin[1]; | 139 m_rightMargin = m_leftMargin = rootMargin[1]; |
137 m_bottomMargin = rootMargin[2]; | 140 m_bottomMargin = rootMargin[2]; |
138 break; | 141 break; |
139 case 4: | 142 case 4: |
140 m_topMargin = rootMargin[0]; | 143 m_topMargin = rootMargin[0]; |
141 m_rightMargin = rootMargin[1]; | 144 m_rightMargin = rootMargin[1]; |
142 m_bottomMargin = rootMargin[2]; | 145 m_bottomMargin = rootMargin[2]; |
143 m_leftMargin = rootMargin[3]; | 146 m_leftMargin = rootMargin[3]; |
144 break; | 147 break; |
145 default: | 148 default: |
146 ASSERT_NOT_REACHED(); | 149 ASSERT_NOT_REACHED(); |
147 break; | 150 break; |
148 } | 151 } |
149 root.document().ensureIntersectionObserverController().addTrackedObserver(*t
his); | 152 root.document().ensureIntersectionObserverController().addTrackedObserver(*t
his); |
150 } | 153 } |
151 | 154 |
152 LayoutObject* IntersectionObserver::rootLayoutObject() | 155 LayoutObject* IntersectionObserver::rootLayoutObject() const |
153 { | 156 { |
154 Element* rootElement = root(); | 157 Node* rootNode = root(); |
155 if (rootElement == rootElement->document().documentElement()) | 158 if (rootNode->isDocumentNode()) |
156 return rootElement->document().layoutView(); | 159 return toDocument(rootNode)->layoutView(); |
157 return rootElement->layoutObject(); | 160 return toElement(rootNode)->layoutObject(); |
158 } | 161 } |
159 | 162 |
160 bool IntersectionObserver::isDescendantOfRoot(const Element* target) const | 163 bool IntersectionObserver::isDescendantOfRoot(const Element* target) const |
161 { | 164 { |
162 // Is m_root an ancestor, through the DOM and frame trees, of target? | 165 // Is m_root an ancestor, through the DOM and frame trees, of target? |
163 Element* rootElement = m_root.get(); | 166 Node* rootNode = root(); |
164 if (!rootElement || !target || target == rootElement) | 167 if (!rootNode || !target || target == rootNode) |
165 return false; | 168 return false; |
166 if (!target->inDocument() || !rootElement->inDocument()) | 169 if (!target->inDocument() || !rootNode->inDocument()) |
167 return false; | 170 return false; |
168 | 171 |
169 Document* rootDocument = &rootElement->document(); | 172 Document* rootDocument = &rootNode->document(); |
170 Document* targetDocument = &target->document(); | 173 Document* targetDocument = &target->document(); |
171 while (targetDocument != rootDocument) { | 174 while (targetDocument != rootDocument) { |
172 target = targetDocument->ownerElement(); | 175 target = targetDocument->ownerElement(); |
173 if (!target) | 176 if (!target) |
174 return false; | 177 return false; |
175 targetDocument = &target->document(); | 178 targetDocument = &target->document(); |
176 } | 179 } |
177 return target->isDescendantOf(rootElement); | 180 if (rootNode->isDocumentNode()) { |
| 181 ASSERT(targetDocument == rootNode); |
| 182 return true; |
| 183 } |
| 184 return target->isDescendantOf(rootNode); |
178 } | 185 } |
179 | 186 |
180 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) | 187 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) |
181 { | 188 { |
182 checkRootAndDetachIfNeeded(); | 189 checkRootAndDetachIfNeeded(); |
183 if (!m_root) { | 190 if (!m_root) { |
184 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); | 191 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); |
185 return; | 192 return; |
186 } | 193 } |
187 if (!target) { | 194 if (!target) { |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 | 343 |
337 DEFINE_TRACE(IntersectionObserver) | 344 DEFINE_TRACE(IntersectionObserver) |
338 { | 345 { |
339 visitor->trace(m_callback); | 346 visitor->trace(m_callback); |
340 visitor->trace(m_root); | 347 visitor->trace(m_root); |
341 visitor->trace(m_observations); | 348 visitor->trace(m_observations); |
342 visitor->trace(m_entries); | 349 visitor->trace(m_entries); |
343 } | 350 } |
344 | 351 |
345 } // namespace blink | 352 } // namespace blink |
OLD | NEW |