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/IntersectionObservation.h" | 5 #include "core/dom/IntersectionObservation.h" |
6 | 6 |
7 #include "core/dom/ElementRareData.h" | 7 #include "core/dom/ElementRareData.h" |
8 #include "core/dom/IntersectionObserver.h" | 8 #include "core/dom/IntersectionObserver.h" |
9 #include "core/frame/FrameView.h" | 9 #include "core/frame/FrameView.h" |
10 #include "core/layout/LayoutBox.h" | 10 #include "core/layout/LayoutBox.h" |
(...skipping 16 matching lines...) Expand all Loading... | |
27 { | 27 { |
28 return toElement(m_target.get()); | 28 return toElement(m_target.get()); |
29 } | 29 } |
30 | 30 |
31 void IntersectionObservation::applyRootMargin(LayoutRect& rect) const | 31 void IntersectionObservation::applyRootMargin(LayoutRect& rect) const |
32 { | 32 { |
33 if (m_shouldReportRootBounds) | 33 if (m_shouldReportRootBounds) |
34 m_observer->applyRootMargin(rect); | 34 m_observer->applyRootMargin(rect); |
35 } | 35 } |
36 | 36 |
37 void IntersectionObservation::initializeGeometry(IntersectionGeometry& geometry) const | |
38 { | |
39 initializeTargetRect(geometry.targetRect); | |
40 geometry.intersectionRect = geometry.targetRect; | |
41 initializeRootRect(geometry.rootRect); | |
42 geometry.doesIntersect = true; | |
ojan
2016/03/21 22:23:05
Why do you need this line? It looks like it always
szager1
2016/03/22 00:55:48
No reason other than my instinctive aversion to le
| |
43 } | |
44 | |
37 void IntersectionObservation::initializeTargetRect(LayoutRect& rect) const | 45 void IntersectionObservation::initializeTargetRect(LayoutRect& rect) const |
38 { | 46 { |
39 ASSERT(m_target); | 47 ASSERT(m_target); |
40 LayoutObject* targetLayoutObject = target()->layoutObject(); | 48 LayoutObject* targetLayoutObject = target()->layoutObject(); |
41 ASSERT(targetLayoutObject && targetLayoutObject->isBoxModelObject()); | 49 ASSERT(targetLayoutObject && targetLayoutObject->isBoxModelObject()); |
42 rect = toLayoutBoxModelObject(targetLayoutObject)->visualOverflowRect(); | 50 rect = toLayoutBoxModelObject(targetLayoutObject)->visualOverflowRect(); |
43 | |
44 // TODO(szager): Properly support intersection observations for zero-area ta rgets | |
45 // by using edge-inclusive geometry. | |
46 if (!rect.size().width()) | |
47 rect.setWidth(LayoutUnit(1)); | |
48 if (!rect.size().height()) | |
49 rect.setHeight(LayoutUnit(1)); | |
50 } | 51 } |
51 | 52 |
52 void IntersectionObservation::initializeRootRect(LayoutRect& rect) const | 53 void IntersectionObservation::initializeRootRect(LayoutRect& rect) const |
53 { | 54 { |
54 LayoutObject* rootLayoutObject = m_observer->rootLayoutObject(); | 55 LayoutObject* rootLayoutObject = m_observer->rootLayoutObject(); |
55 if (rootLayoutObject->isLayoutView()) | 56 if (rootLayoutObject->isLayoutView()) |
56 rect = LayoutRect(toLayoutView(rootLayoutObject)->frameView()->visibleCo ntentRect()); | 57 rect = LayoutRect(toLayoutView(rootLayoutObject)->frameView()->visibleCo ntentRect()); |
57 // TODO(szager): Obey the spec -- use content box for a scrolling element, b order box otherwise. | 58 // TODO(szager): Obey the spec -- use content box for a scrolling element, b order box otherwise. |
58 else if (rootLayoutObject->isBox()) | 59 else if (rootLayoutObject->isBox()) |
59 rect = LayoutRect(toLayoutBox(rootLayoutObject)->contentBoxRect()); | 60 rect = LayoutRect(toLayoutBox(rootLayoutObject)->contentBoxRect()); |
60 else | 61 else |
61 rect = LayoutRect(toLayoutBoxModelObject(rootLayoutObject)->borderBoundi ngBox()); | 62 rect = LayoutRect(toLayoutBoxModelObject(rootLayoutObject)->borderBoundi ngBox()); |
62 applyRootMargin(rect); | 63 applyRootMargin(rect); |
63 } | 64 } |
64 | 65 |
65 void IntersectionObservation::clipToRoot(LayoutRect& rect, const LayoutRect& roo tRect) const | 66 void IntersectionObservation::clipToRoot(IntersectionGeometry& geometry) const |
66 { | 67 { |
67 // Map and clip rect into root element coordinates. | 68 // Map and clip rect into root element coordinates. |
68 // TODO(szager): the writing mode flipping needs a test. | 69 // TODO(szager): the writing mode flipping needs a test. |
69 ASSERT(m_target); | 70 ASSERT(m_target); |
70 LayoutObject* rootLayoutObject = m_observer->rootLayoutObject(); | 71 LayoutObject* rootLayoutObject = m_observer->rootLayoutObject(); |
71 LayoutObject* targetLayoutObject = target()->layoutObject(); | 72 LayoutObject* targetLayoutObject = target()->layoutObject(); |
72 | 73 |
73 targetLayoutObject->mapToVisibleRectInAncestorSpace(toLayoutBoxModelObject(r ootLayoutObject), rect, nullptr); | 74 geometry.doesIntersect = targetLayoutObject->mapToVisibleRectInAncestorSpace (toLayoutBoxModelObject(rootLayoutObject), geometry.intersectionRect, nullptr, t rue); |
74 LayoutRect rootClipRect(rootRect); | 75 if (!geometry.doesIntersect) |
76 return; | |
77 LayoutRect rootClipRect(geometry.rootRect); | |
75 toLayoutBox(rootLayoutObject)->flipForWritingMode(rootClipRect); | 78 toLayoutBox(rootLayoutObject)->flipForWritingMode(rootClipRect); |
76 rect.intersect(rootClipRect); | 79 geometry.doesIntersect &= geometry.intersectionRect.inclusiveIntersect(rootC lipRect); |
77 } | 80 } |
78 | 81 |
79 static void mapRectUpToDocument(LayoutRect& rect, const LayoutObject& layoutObje ct, const Document& document) | 82 static void mapRectUpToDocument(LayoutRect& rect, const LayoutObject& layoutObje ct, const Document& document) |
80 { | 83 { |
81 FloatQuad mappedQuad = layoutObject.localToAbsoluteQuad( | 84 FloatQuad mappedQuad = layoutObject.localToAbsoluteQuad( |
82 FloatQuad(FloatRect(rect)), | 85 FloatQuad(FloatRect(rect)), |
83 UseTransforms | ApplyContainerFlip); | 86 UseTransforms | ApplyContainerFlip); |
84 rect = LayoutRect(mappedQuad.boundingBox()); | 87 rect = LayoutRect(mappedQuad.boundingBox()); |
85 } | 88 } |
86 | 89 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
157 // TODO(szager): Support SVG | 160 // TODO(szager): Support SVG |
158 if (!targetLayoutObject) | 161 if (!targetLayoutObject) |
159 return false; | 162 return false; |
160 if (!targetLayoutObject->isBoxModelObject() && !targetLayoutObject->isText() ) | 163 if (!targetLayoutObject->isBoxModelObject() && !targetLayoutObject->isText() ) |
161 return false; | 164 return false; |
162 if (!rootLayoutObject || !rootLayoutObject->isBoxModelObject()) | 165 if (!rootLayoutObject || !rootLayoutObject->isBoxModelObject()) |
163 return false; | 166 return false; |
164 if (!isContainingBlockChainDescendant(targetLayoutObject, rootLayoutObject)) | 167 if (!isContainingBlockChainDescendant(targetLayoutObject, rootLayoutObject)) |
165 return false; | 168 return false; |
166 | 169 |
167 initializeTargetRect(geometry.targetRect); | 170 initializeGeometry(geometry); |
168 geometry.intersectionRect = geometry.targetRect; | |
169 initializeRootRect(geometry.rootRect); | |
170 | 171 |
171 clipToRoot(geometry.intersectionRect, geometry.rootRect); | 172 clipToRoot(geometry); |
172 | 173 |
173 // TODO(szager): there are some simple optimizations that can be done here: | |
174 // - Don't transform rootRect if it's not going to be reported | |
175 // - Don't transform intersectionRect if it's empty | |
176 mapTargetRectToTargetFrameCoordinates(geometry.targetRect); | 174 mapTargetRectToTargetFrameCoordinates(geometry.targetRect); |
177 mapRootRectToTargetFrameCoordinates(geometry.intersectionRect); | |
178 mapRootRectToRootFrameCoordinates(geometry.rootRect); | |
179 | 175 |
180 if (geometry.intersectionRect.size().isZero()) | 176 if (geometry.doesIntersect) |
177 mapRootRectToTargetFrameCoordinates(geometry.intersectionRect); | |
178 else | |
181 geometry.intersectionRect = LayoutRect(); | 179 geometry.intersectionRect = LayoutRect(); |
ojan
2016/03/21 22:23:05
Doesn't this get the x/y coordinates of the inters
szager1
2016/03/22 00:55:48
If there's no intersection, then there are no righ
ojan
2016/03/22 04:24:47
Oh, I misread this code. This is only in the non-i
| |
182 | 180 |
181 if (m_shouldReportRootBounds) | |
182 mapRootRectToRootFrameCoordinates(geometry.rootRect); | |
183 else | |
184 geometry.rootRect = LayoutRect(); | |
185 | |
183 return true; | 186 return true; |
184 } | 187 } |
185 | 188 |
186 void IntersectionObservation::computeIntersectionObservations(DOMHighResTimeStam p timestamp) | 189 void IntersectionObservation::computeIntersectionObservations(DOMHighResTimeStam p timestamp) |
187 { | 190 { |
188 IntersectionGeometry geometry; | 191 IntersectionGeometry geometry; |
189 if (!computeGeometry(geometry)) | 192 if (!computeGeometry(geometry)) |
190 return; | 193 return; |
191 | 194 |
192 float intersectionArea = geometry.intersectionRect.size().width().toFloat() * geometry.intersectionRect.size().height().toFloat(); | 195 float intersectionArea = geometry.intersectionRect.size().width().toFloat() * geometry.intersectionRect.size().height().toFloat(); |
193 float targetArea = geometry.targetRect.size().width().toFloat() * geometry.t argetRect.size().height().toFloat(); | 196 float targetArea = geometry.targetRect.size().width().toFloat() * geometry.t argetRect.size().height().toFloat(); |
194 if (!targetArea) | 197 float newVisibleRatio; |
195 return; | 198 if (!intersectionArea && geometry.doesIntersect) |
196 float newVisibleRatio = intersectionArea / targetArea; | 199 newVisibleRatio = std::numeric_limits<float>::denorm_min(); |
ojan
2016/03/21 22:23:04
This can't be 0? /me is probably ignorant about wo
szager1
2016/03/22 00:55:48
Zero is a special value that means "not intersecti
| |
200 else | |
201 newVisibleRatio = intersectionArea / targetArea; | |
197 unsigned newThresholdIndex = observer().firstThresholdGreaterThan(newVisible Ratio); | 202 unsigned newThresholdIndex = observer().firstThresholdGreaterThan(newVisible Ratio); |
198 IntRect snappedRootBounds = pixelSnappedIntRect(geometry.rootRect); | 203 IntRect snappedRootBounds = pixelSnappedIntRect(geometry.rootRect); |
199 IntRect* rootBoundsPointer = m_shouldReportRootBounds ? &snappedRootBounds : nullptr; | 204 IntRect* rootBoundsPointer = m_shouldReportRootBounds ? &snappedRootBounds : nullptr; |
200 if (m_lastThresholdIndex != newThresholdIndex) { | 205 if (m_lastThresholdIndex != newThresholdIndex) { |
201 IntersectionObserverEntry* newEntry = new IntersectionObserverEntry( | 206 IntersectionObserverEntry* newEntry = new IntersectionObserverEntry( |
202 timestamp, | 207 timestamp, |
203 pixelSnappedIntRect(geometry.targetRect), | 208 pixelSnappedIntRect(geometry.targetRect), |
204 rootBoundsPointer, | 209 rootBoundsPointer, |
205 pixelSnappedIntRect(geometry.intersectionRect), | 210 pixelSnappedIntRect(geometry.intersectionRect), |
206 target()); | 211 target()); |
(...skipping 16 matching lines...) Expand all Loading... | |
223 m_observer.clear(); | 228 m_observer.clear(); |
224 } | 229 } |
225 | 230 |
226 DEFINE_TRACE(IntersectionObservation) | 231 DEFINE_TRACE(IntersectionObservation) |
227 { | 232 { |
228 visitor->trace(m_observer); | 233 visitor->trace(m_observer); |
229 visitor->trace(m_target); | 234 visitor->trace(m_target); |
230 } | 235 } |
231 | 236 |
232 } // namespace blink | 237 } // namespace blink |
OLD | NEW |