LEFT | RIGHT |
1 /* | 1 /* |
2 * Copyright (C) 2016 Apple Inc. All rights reserved. | 2 * Copyright (C) 2016 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 12 matching lines...) Expand all Loading... |
23 * THE POSSIBILITY OF SUCH DAMAGE. | 23 * THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 | 27 |
28 #if ENABLE(INTERSECTION_OBSERVER) | 28 #if ENABLE(INTERSECTION_OBSERVER) |
29 #include "IntersectionObserver.h" | 29 #include "IntersectionObserver.h" |
30 | 30 |
31 #include "CSSParser.h" | 31 #include "CSSParser.h" |
32 #include "CSSPropertyParser.h" | 32 #include "CSSPropertyParser.h" |
| 33 #include "CSSPropertyParserHelpers.h" |
33 #include "CSSTokenizer.h" | 34 #include "CSSTokenizer.h" |
34 #include "DOMWindow.h" | 35 #include "DOMWindow.h" |
35 #include "Element.h" | 36 #include "Element.h" |
36 #include "ExceptionCode.h" | 37 #include "ExceptionCode.h" |
37 #include "IntersectionObserverCallback.h" | 38 #include "IntersectionObserverCallback.h" |
38 #include "IntersectionObserverEntry.h" | 39 #include "IntersectionObserverEntry.h" |
39 #include "Logging.h" | 40 #include "Logging.h" |
40 #include "StyleResolver.h" | 41 #include "StyleResolver.h" |
41 #include <wtf/text/TextStream.h> | |
42 #include <wtf/Vector.h> | |
43 #include <algorithm> | 42 #include <algorithm> |
44 #include <functional> | 43 #include <functional> |
| 44 #include <wtf/Vector.h> |
| 45 #include <wtf/text/TextStream.h> |
45 | 46 |
46 namespace WebCore { | 47 namespace WebCore { |
47 | 48 |
48 static bool isThresholdWithinRange(double threshold) { | 49 static bool isThresholdWithinRange(double threshold) |
49 return threshold >= 0.0 && threshold <= 1.0; | 50 { |
| 51 return threshold >= 0 && threshold <= 1; |
50 } | 52 } |
51 | 53 |
52 static ExceptionOr<LengthBox> parseRootMargin(String& rootMargin) | 54 static ExceptionOr<LengthBox> parseRootMargin(String& rootMargin) |
53 { | 55 { |
54 CSSTokenizer tokenizer(rootMargin); | 56 CSSTokenizer tokenizer(rootMargin); |
55 auto tokenRange = tokenizer.tokenRange(); | 57 auto tokenRange = tokenizer.tokenRange(); |
56 Vector<Length, 4> margins; | 58 Vector<Length, 4> margins; |
57 while (!tokenRange.atEnd()) { | 59 while (!tokenRange.atEnd()) { |
58 if (margins.size() == 4) | 60 if (margins.size() == 4) |
59 return Exception { SyntaxError, "Failed to construct 'IntersectionOb
server': Extra text found at the end of rootMargin." }; | 61 return Exception { SyntaxError, "Failed to construct 'IntersectionOb
server': Extra text found at the end of rootMargin." }; |
60 const CSSParserToken& token = tokenRange.consumeIncludingWhitespace(); | 62 RefPtr<CSSPrimitiveValue> parsedValue = CSSPropertyParserHelpers::consum
eLengthOrPercent(tokenRange, HTMLStandardMode, ValueRangeAll); |
61 switch (token.type()) { | 63 if (!parsedValue || parsedValue->isCalculated()) |
62 case PercentageToken: | |
63 margins.append(Length(token.numericValue(), Percent)); | |
64 break; | |
65 case DimensionToken: | |
66 switch (token.unitType()) { | |
67 case CSSPrimitiveValue::CSS_PX: | |
68 margins.append(Length(static_cast<int>(floor(token.numericValue(
))), Fixed)); | |
69 break; | |
70 case CSSPrimitiveValue::CSS_PERCENTAGE: | |
71 margins.append(Length(token.numericValue(), Percent)); | |
72 break; | |
73 default: | |
74 return Exception { SyntaxError, "Failed to construct 'Intersecti
onObserver': rootMargin must be specified in pixels or percent." }; | |
75 } | |
76 break; | |
77 default: | |
78 return Exception { SyntaxError, "Failed to construct 'IntersectionOb
server': rootMargin must be specified in pixels or percent." }; | 64 return Exception { SyntaxError, "Failed to construct 'IntersectionOb
server': rootMargin must be specified in pixels or percent." }; |
79 } | 65 if (parsedValue->isPercentage()) |
| 66 margins.append(Length(parsedValue->doubleValue(), Percent)); |
| 67 else if (parsedValue->isPx()) |
| 68 margins.append(Length(parsedValue->intValue(), Fixed)); |
| 69 else |
| 70 return Exception { SyntaxError, "Failed to construct 'IntersectionOb
server': rootMargin must be specified in pixels or percent." }; |
80 } | 71 } |
81 | 72 |
82 Length top, right, bottom, left; | 73 Length top, right, bottom, left; |
83 switch (margins.size()) { | 74 switch (margins.size()) { |
84 case 0: | 75 case 0: |
85 for (int i = 0; i < 4; ++i) | 76 for (int i = 0; i < 4; ++i) |
86 margins.append(Length()); | 77 margins.append(Length()); |
87 break; | 78 break; |
88 case 1: | 79 case 1: |
89 for (int i = 0; i < 3; ++i) | 80 for (int i = 0; i < 3; ++i) |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 if (rootMarginOrException.hasException()) | 114 if (rootMarginOrException.hasException()) |
124 return rootMarginOrException.releaseException(); | 115 return rootMarginOrException.releaseException(); |
125 | 116 |
126 bool foundOutOfRangeThreshold = false; | 117 bool foundOutOfRangeThreshold = false; |
127 if (WTF::holds_alternative<double>(init.threshold)) | 118 if (WTF::holds_alternative<double>(init.threshold)) |
128 foundOutOfRangeThreshold = !isThresholdWithinRange(WTF::get<double>(init
.threshold)); | 119 foundOutOfRangeThreshold = !isThresholdWithinRange(WTF::get<double>(init
.threshold)); |
129 else { | 120 else { |
130 for (auto& threshold : WTF::get<Vector<double>>(init.threshold)) | 121 for (auto& threshold : WTF::get<Vector<double>>(init.threshold)) |
131 foundOutOfRangeThreshold |= !isThresholdWithinRange(threshold); | 122 foundOutOfRangeThreshold |= !isThresholdWithinRange(threshold); |
132 } | 123 } |
133 if (foundOutOfRangeThreshold) { | 124 if (foundOutOfRangeThreshold) |
134 return Exception { RangeError, "Failed to construct 'IntersectionObserve
r': all thresholds must lie in the range [0.0, 1.0]." }; | 125 return Exception { RangeError, "Failed to construct 'IntersectionObserve
r': all thresholds must lie in the range [0.0, 1.0]." }; |
135 } | |
136 | 126 |
137 return adoptRef(*new IntersectionObserver(document, WTFMove(callback), WTFMo
ve(init), rootMarginOrException.releaseReturnValue())); | 127 return adoptRef(*new IntersectionObserver(document, WTFMove(callback), WTFMo
ve(init), rootMarginOrException.releaseReturnValue())); |
138 } | 128 } |
139 | 129 |
140 // FIXME: need to stop observing if the root is deleted. | 130 // FIXME: need to stop observing if the root is deleted. |
141 IntersectionObserver::IntersectionObserver(Document& document, Ref<IntersectionO
bserverCallback>&& callback, Init&& init, LengthBox&& marginBox) | 131 IntersectionObserver::IntersectionObserver(Document& document, Ref<IntersectionO
bserverCallback>&& callback, Init&& init, LengthBox&& marginBox) |
142 : m_document(document) | 132 : m_document(document) |
143 , m_root(init.root) | 133 , m_root(init.root) |
144 , m_rootMargin(WTFMove(init.rootMargin)) | 134 , m_rootMargin(WTFMove(init.rootMargin)) |
145 , m_callback(WTFMove(callback)) | 135 , m_callback(WTFMove(callback)) |
146 , m_marginBox(marginBox) | 136 , m_marginBox(marginBox) |
147 { | 137 { |
148 if (WTF::holds_alternative<double>(init.threshold)) | 138 if (WTF::holds_alternative<double>(init.threshold)) |
149 m_thresholds.append(WTF::get<double>(init.threshold)); | 139 m_thresholds.append(WTF::get<double>(init.threshold)); |
150 else | 140 else |
151 m_thresholds = WTF::get<Vector<double>>(WTFMove(init.threshold)); | 141 m_thresholds = WTF::get<Vector<double>>(WTFMove(init.threshold)); |
152 std::sort(m_thresholds.begin(), m_thresholds.end(), std::less<double>()); | 142 std::sort(m_thresholds.begin(), m_thresholds.end(), std::less<double>()); |
153 } | 143 } |
154 | 144 |
155 IntersectionObserver::~IntersectionObserver() | 145 IntersectionObserver::~IntersectionObserver() |
156 { | 146 { |
157 disconnect(); | 147 disconnect(); |
158 } | 148 } |
159 | 149 |
160 ExceptionOr<void> IntersectionObserver::observe(Element& element) | 150 ExceptionOr<void> IntersectionObserver::observe(Element& element) |
161 { | 151 { |
162 if (&element.document() != &m_document) { | 152 if (m_root && &element.document() != &m_document) { |
| 153 // FIXME: Should we be raising an exception or just silently doing nothi
ng (which is what the spec wants and what other browsers do). |
163 m_document.domWindow()->printErrorMessage("IntersectionObserver.observe(
) on an element from another document is not allowed."); | 154 m_document.domWindow()->printErrorMessage("IntersectionObserver.observe(
) on an element from another document is not allowed."); |
164 return Exception { WrongDocumentError }; | 155 return Exception { WrongDocumentError }; |
165 } | 156 } |
166 | 157 |
167 element.startObservingIntersections(*this); | 158 element.startObservingIntersections(*this); |
168 return { }; | 159 return { }; |
169 } | 160 } |
170 | 161 |
171 void IntersectionObserver::unobserve(Element& element) | 162 void IntersectionObserver::unobserve(Element& element) |
172 { | 163 { |
(...skipping 25 matching lines...) Expand all Loading... |
198 m_observationTargets.removeFirst(&element); | 189 m_observationTargets.removeFirst(&element); |
199 } | 190 } |
200 | 191 |
201 bool IntersectionObserver::hasObservationTarget(Element& element) const | 192 bool IntersectionObserver::hasObservationTarget(Element& element) const |
202 { | 193 { |
203 return m_observationTargets.contains(&element); | 194 return m_observationTargets.contains(&element); |
204 } | 195 } |
205 | 196 |
206 void IntersectionObserver::appendQueuedEntry(Ref<IntersectionObserverEntry>&& en
try) | 197 void IntersectionObserver::appendQueuedEntry(Ref<IntersectionObserverEntry>&& en
try) |
207 { | 198 { |
208 BACKTRACE(); | |
209 LOG_WITH_STREAM(IntersectionObserver, stream << " adding queued entry " << e
ntry.get()); | 199 LOG_WITH_STREAM(IntersectionObserver, stream << " adding queued entry " << e
ntry.get()); |
210 | 200 |
211 m_queuedEntries.append(WTFMove(entry)); | 201 m_queuedEntries.append(WTFMove(entry)); |
212 } | 202 } |
213 | 203 |
214 void IntersectionObserver::notify() | 204 void IntersectionObserver::notify() |
215 { | 205 { |
216 if (m_queuedEntries.isEmpty()) | 206 if (m_queuedEntries.isEmpty()) |
217 return; | 207 return; |
218 | 208 |
219 LOG(IntersectionObserver, "IntersectionObserver %p callback(): %lu records",
this, m_queuedEntries.size()); | 209 LOG(IntersectionObserver, "IntersectionObserver %p callback(): %lu records",
this, m_queuedEntries.size()); |
220 | 210 |
221 m_callback->handleEvent(takeRecords(), *this); | 211 m_callback->handleEvent(takeRecords(), *this); |
222 } | 212 } |
223 | 213 |
224 } // namespace WebCore | 214 } // namespace WebCore |
225 | 215 |
226 #endif // ENABLE(INTERSECTION_OBSERVER) | 216 #endif // ENABLE(INTERSECTION_OBSERVER) |
LEFT | RIGHT |