| 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/ExceptionCode.h" | 10 #include "core/dom/ExceptionCode.h" |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 { | 159 { |
| 160 if (Heap::isHeapObjectAlive(m_root)) | 160 if (Heap::isHeapObjectAlive(m_root)) |
| 161 return; | 161 return; |
| 162 disconnect(); | 162 disconnect(); |
| 163 m_root = nullptr; | 163 m_root = nullptr; |
| 164 } | 164 } |
| 165 #endif | 165 #endif |
| 166 | 166 |
| 167 LayoutObject* IntersectionObserver::rootLayoutObject() const | 167 LayoutObject* IntersectionObserver::rootLayoutObject() const |
| 168 { | 168 { |
| 169 Node* rootNode = root(); | 169 Node* node = rootNode(); |
| 170 if (rootNode->isDocumentNode()) | 170 if (node->isDocumentNode()) |
| 171 return toDocument(rootNode)->layoutView(); | 171 return toDocument(node)->layoutView(); |
| 172 return toElement(rootNode)->layoutObject(); | 172 return toElement(node)->layoutObject(); |
| 173 } | 173 } |
| 174 | 174 |
| 175 bool IntersectionObserver::isDescendantOfRoot(const Element* target) const | 175 bool IntersectionObserver::isDescendantOfRoot(const Element* target) const |
| 176 { | 176 { |
| 177 // Is m_root an ancestor, through the DOM and frame trees, of target? | 177 // Is m_root an ancestor, through the DOM and frame trees, of target? |
| 178 Node* rootNode = root(); | 178 Node* node = rootNode(); |
| 179 if (!rootNode || !target || target == rootNode) | 179 if (!node || !target || target == node) |
| 180 return false; | 180 return false; |
| 181 if (!target->inDocument() || !rootNode->inDocument()) | 181 if (!target->inDocument() || !node->inDocument()) |
| 182 return false; | 182 return false; |
| 183 | 183 |
| 184 Document* rootDocument = &rootNode->document(); | 184 Document* rootDocument = &node->document(); |
| 185 Document* targetDocument = &target->document(); | 185 Document* targetDocument = &target->document(); |
| 186 while (targetDocument != rootDocument) { | 186 while (targetDocument != rootDocument) { |
| 187 target = targetDocument->ownerElement(); | 187 target = targetDocument->ownerElement(); |
| 188 if (!target) | 188 if (!target) |
| 189 return false; | 189 return false; |
| 190 targetDocument = &target->document(); | 190 targetDocument = &target->document(); |
| 191 } | 191 } |
| 192 if (rootNode->isDocumentNode()) { | 192 if (node->isDocumentNode()) { |
| 193 ASSERT(targetDocument == rootNode); | 193 ASSERT(targetDocument == node); |
| 194 return true; | 194 return true; |
| 195 } | 195 } |
| 196 return target->isDescendantOf(rootNode); | 196 return target->isDescendantOf(node); |
| 197 } | 197 } |
| 198 | 198 |
| 199 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) | 199 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) |
| 200 { | 200 { |
| 201 if (!m_root) { | 201 if (!m_root) { |
| 202 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); | 202 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); |
| 203 return; | 203 return; |
| 204 } | 204 } |
| 205 if (!target) { | 205 if (!target) { |
| 206 exceptionState.throwTypeError("Observation target must be an element."); | 206 exceptionState.throwTypeError("Observation target must be an element."); |
| 207 return; | 207 return; |
| 208 } | 208 } |
| 209 if (m_root.get() == target) { | 209 if (m_root.get() == target) { |
| 210 exceptionState.throwDOMException(HierarchyRequestError, "Cannot use the
same element for root and target."); | 210 exceptionState.throwDOMException(HierarchyRequestError, "Cannot use the
same element for root and target."); |
| 211 return; | 211 return; |
| 212 } | 212 } |
| 213 if (!isDescendantOfRoot(target)) { | 213 if (!isDescendantOfRoot(target)) { |
| 214 exceptionState.throwDOMException(HierarchyRequestError, "Observed elemen
t must be a descendant of the observer's root element."); | 214 exceptionState.throwDOMException(HierarchyRequestError, "Observed elemen
t must be a descendant of the observer's root element."); |
| 215 return; | 215 return; |
| 216 } | 216 } |
| 217 | 217 |
| 218 // TODO(szager): Add a pointer to the spec that describes this policy. | 218 // TODO(szager): Add a pointer to the spec that describes this policy. |
| 219 bool shouldReportRootBounds = target->document().frame()->securityContext()-
>securityOrigin()->canAccess(root()->document().frame()->securityContext()->secu
rityOrigin()); | 219 bool shouldReportRootBounds = target->document().frame()->securityContext()-
>securityOrigin()->canAccess(rootNode()->document().frame()->securityContext()->
securityOrigin()); |
| 220 if (!shouldReportRootBounds && hasPercentMargin()) { | 220 if (!shouldReportRootBounds && hasPercentMargin()) { |
| 221 exceptionState.throwDOMException(HierarchyRequestError, "Cannot observe
a cross-origin target because the observer has a root margin value specified as
a percent."); | 221 exceptionState.throwDOMException(HierarchyRequestError, "Cannot observe
a cross-origin target because the observer has a root margin value specified as
a percent."); |
| 222 return; | 222 return; |
| 223 } | 223 } |
| 224 | 224 |
| 225 if (target->ensureIntersectionObserverData().getObservationFor(*this)) | 225 if (target->ensureIntersectionObserverData().getObservationFor(*this)) |
| 226 return; | 226 return; |
| 227 | 227 |
| 228 IntersectionObservation* observation = new IntersectionObservation(*this, *t
arget, shouldReportRootBounds); | 228 IntersectionObservation* observation = new IntersectionObservation(*this, *t
arget, shouldReportRootBounds); |
| 229 target->ensureIntersectionObserverData().addObservation(*observation); | 229 target->ensureIntersectionObserverData().addObservation(*observation); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 m_observations.remove(&observation); | 266 m_observations.remove(&observation); |
| 267 } | 267 } |
| 268 | 268 |
| 269 HeapVector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords(
) | 269 HeapVector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords(
) |
| 270 { | 270 { |
| 271 HeapVector<Member<IntersectionObserverEntry>> entries; | 271 HeapVector<Member<IntersectionObserverEntry>> entries; |
| 272 entries.swap(m_entries); | 272 entries.swap(m_entries); |
| 273 return entries; | 273 return entries; |
| 274 } | 274 } |
| 275 | 275 |
| 276 Element* IntersectionObserver::root() const |
| 277 { |
| 278 Node* node = rootNode(); |
| 279 if (node->isDocumentNode()) |
| 280 return nullptr; |
| 281 return toElement(node); |
| 282 } |
| 283 |
| 284 static void appendLength(StringBuilder& stringBuilder, const Length& length) |
| 285 { |
| 286 stringBuilder.appendNumber(length.intValue()); |
| 287 if (length.type() == Percent) |
| 288 stringBuilder.append('%'); |
| 289 else |
| 290 stringBuilder.append("px", 2); |
| 291 } |
| 292 |
| 293 String IntersectionObserver::rootMargin() const |
| 294 { |
| 295 StringBuilder stringBuilder; |
| 296 appendLength(stringBuilder, m_topMargin); |
| 297 stringBuilder.append(' '); |
| 298 appendLength(stringBuilder, m_rightMargin); |
| 299 stringBuilder.append(' '); |
| 300 appendLength(stringBuilder, m_bottomMargin); |
| 301 stringBuilder.append(' '); |
| 302 appendLength(stringBuilder, m_leftMargin); |
| 303 return stringBuilder.toString(); |
| 304 } |
| 305 |
| 276 void IntersectionObserver::enqueueIntersectionObserverEntry(IntersectionObserver
Entry& entry) | 306 void IntersectionObserver::enqueueIntersectionObserverEntry(IntersectionObserver
Entry& entry) |
| 277 { | 307 { |
| 278 m_entries.append(&entry); | 308 m_entries.append(&entry); |
| 279 toDocument(m_callback->executionContext())->ensureIntersectionObserverContro
ller().scheduleIntersectionObserverForDelivery(*this); | 309 toDocument(m_callback->executionContext())->ensureIntersectionObserverContro
ller().scheduleIntersectionObserverForDelivery(*this); |
| 280 } | 310 } |
| 281 | 311 |
| 282 static LayoutUnit computeMargin(const Length& length, LayoutUnit referenceLength
) | 312 static LayoutUnit computeMargin(const Length& length, LayoutUnit referenceLength
) |
| 283 { | 313 { |
| 284 if (length.type() == Percent) | 314 if (length.type() == Percent) |
| 285 return LayoutUnit(static_cast<int>(referenceLength.toFloat() * length.pe
rcent() / 100.0)); | 315 return LayoutUnit(static_cast<int>(referenceLength.toFloat() * length.pe
rcent() / 100.0)); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 { | 369 { |
| 340 #if ENABLE(OILPAN) | 370 #if ENABLE(OILPAN) |
| 341 visitor->template registerWeakMembers<IntersectionObserver, &IntersectionObs
erver::clearWeakMembers>(this); | 371 visitor->template registerWeakMembers<IntersectionObserver, &IntersectionObs
erver::clearWeakMembers>(this); |
| 342 #endif | 372 #endif |
| 343 visitor->trace(m_callback); | 373 visitor->trace(m_callback); |
| 344 visitor->trace(m_observations); | 374 visitor->trace(m_observations); |
| 345 visitor->trace(m_entries); | 375 visitor->trace(m_entries); |
| 346 } | 376 } |
| 347 | 377 |
| 348 } // namespace blink | 378 } // namespace blink |
| OLD | NEW |