OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights | 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights |
3 * reserved. | 3 * reserved. |
4 * | 4 * |
5 * Portions are Copyright (C) 1998 Netscape Communications Corporation. | 5 * Portions are Copyright (C) 1998 Netscape Communications Corporation. |
6 * | 6 * |
7 * Other contributors: | 7 * Other contributors: |
8 * Robert O'Callahan <roc+@cs.cmu.edu> | 8 * Robert O'Callahan <roc+@cs.cmu.edu> |
9 * David Baron <dbaron@fas.harvard.edu> | 9 * David Baron <dbaron@fas.harvard.edu> |
10 * Christian Biesinger <cbiesinger@web.de> | 10 * Christian Biesinger <cbiesinger@web.de> |
(...skipping 30 matching lines...) Expand all Loading... |
41 * If you do not delete the provisions above, a recipient may use your | 41 * If you do not delete the provisions above, a recipient may use your |
42 * version of this file under any of the LGPL, the MPL or the GPL. | 42 * version of this file under any of the LGPL, the MPL or the GPL. |
43 */ | 43 */ |
44 | 44 |
45 #include "core/paint/PaintLayerClipper.h" | 45 #include "core/paint/PaintLayerClipper.h" |
46 | 46 |
47 #include "core/frame/FrameView.h" | 47 #include "core/frame/FrameView.h" |
48 #include "core/frame/Settings.h" | 48 #include "core/frame/Settings.h" |
49 #include "core/layout/LayoutView.h" | 49 #include "core/layout/LayoutView.h" |
50 #include "core/layout/svg/LayoutSVGRoot.h" | 50 #include "core/layout/svg/LayoutSVGRoot.h" |
| 51 #include "core/paint/ObjectPaintProperties.h" |
51 #include "core/paint/PaintLayer.h" | 52 #include "core/paint/PaintLayer.h" |
52 | 53 |
53 namespace blink { | 54 namespace blink { |
54 | 55 |
55 static void adjustClipRectsForChildren(const LayoutBoxModelObject& layoutObject, | 56 static void adjustClipRectsForChildren(const LayoutBoxModelObject& layoutObject, |
56 ClipRects& clipRects) { | 57 ClipRects& clipRects) { |
57 EPosition position = layoutObject.styleRef().position(); | 58 EPosition position = layoutObject.styleRef().position(); |
58 // A fixed object is essentially the root of its containing block hierarchy, | 59 // A fixed object is essentially the root of its containing block hierarchy, |
59 // so when we encounter such an object, we reset our clip rects to the | 60 // so when we encounter such an object, we reset our clip rects to the |
60 // fixedClipRect. | 61 // fixedClipRect. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 clipRects.setPosClipRect( | 109 clipRects.setPosClipRect( |
109 intersection(newClip, clipRects.posClipRect()).setIsClippedByClipCss()); | 110 intersection(newClip, clipRects.posClipRect()).setIsClippedByClipCss()); |
110 clipRects.setOverflowClipRect( | 111 clipRects.setOverflowClipRect( |
111 intersection(newClip, clipRects.overflowClipRect()) | 112 intersection(newClip, clipRects.overflowClipRect()) |
112 .setIsClippedByClipCss()); | 113 .setIsClippedByClipCss()); |
113 clipRects.setFixedClipRect(intersection(newClip, clipRects.fixedClipRect()) | 114 clipRects.setFixedClipRect(intersection(newClip, clipRects.fixedClipRect()) |
114 .setIsClippedByClipCss()); | 115 .setIsClippedByClipCss()); |
115 } | 116 } |
116 } | 117 } |
117 | 118 |
| 119 PaintLayerClipper::PaintLayerClipper(const PaintLayer& layer, |
| 120 bool useGeometryMapper) |
| 121 : m_layer(layer), |
| 122 m_geometryMapper(useGeometryMapper ? new GeometryMapper : nullptr) {} |
| 123 |
118 ClipRects* PaintLayerClipper::clipRectsIfCached( | 124 ClipRects* PaintLayerClipper::clipRectsIfCached( |
119 const ClipRectsContext& context) const { | 125 const ClipRectsContext& context) const { |
120 DCHECK(context.usesCache()); | 126 DCHECK(context.usesCache()); |
121 if (!m_layer.clipRectsCache()) | 127 if (!m_layer.clipRectsCache()) |
122 return nullptr; | 128 return nullptr; |
123 ClipRectsCache::Entry& entry = | 129 ClipRectsCache::Entry& entry = |
124 m_layer.clipRectsCache()->get(context.cacheSlot()); | 130 m_layer.clipRectsCache()->get(context.cacheSlot()); |
125 // FIXME: We used to ASSERT that we always got a consistent root layer. | 131 // FIXME: We used to ASSERT that we always got a consistent root layer. |
126 // We should add a test that has an inconsistent root. See | 132 // We should add a test that has an inconsistent root. See |
127 // http://crbug.com/366118 for an example. | 133 // http://crbug.com/366118 for an example. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 // the cache. | 170 // the cache. |
165 ClipRects* parentClipRects = nullptr; | 171 ClipRects* parentClipRects = nullptr; |
166 if (context.rootLayer != &m_layer && m_layer.parent()) | 172 if (context.rootLayer != &m_layer && m_layer.parent()) |
167 parentClipRects = &m_layer.parent()->clipper().getClipRects(context); | 173 parentClipRects = &m_layer.parent()->clipper().getClipRects(context); |
168 RefPtr<ClipRects> clipRects = ClipRects::create(); | 174 RefPtr<ClipRects> clipRects = ClipRects::create(); |
169 calculateClipRects(context, *clipRects); | 175 calculateClipRects(context, *clipRects); |
170 return storeClipRectsInCache(context, parentClipRects, *clipRects); | 176 return storeClipRectsInCache(context, parentClipRects, *clipRects); |
171 } | 177 } |
172 | 178 |
173 void PaintLayerClipper::clearClipRectsIncludingDescendants() { | 179 void PaintLayerClipper::clearClipRectsIncludingDescendants() { |
| 180 if (m_geometryMapper) |
| 181 m_geometryMapper.reset(new GeometryMapper); |
174 m_layer.clearClipRectsCache(); | 182 m_layer.clearClipRectsCache(); |
175 | 183 |
176 for (PaintLayer* layer = m_layer.firstChild(); layer; | 184 for (PaintLayer* layer = m_layer.firstChild(); layer; |
177 layer = layer->nextSibling()) { | 185 layer = layer->nextSibling()) { |
178 layer->clipper().clearClipRectsIncludingDescendants(); | 186 layer->clipper().clearClipRectsIncludingDescendants(); |
179 } | 187 } |
180 } | 188 } |
181 | 189 |
182 void PaintLayerClipper::clearClipRectsIncludingDescendants( | 190 void PaintLayerClipper::clearClipRectsIncludingDescendants( |
183 ClipRectsCacheSlot cacheSlot) { | 191 ClipRectsCacheSlot cacheSlot) { |
| 192 if (m_geometryMapper) |
| 193 m_geometryMapper.reset(new GeometryMapper); |
| 194 |
184 if (ClipRectsCache* cache = m_layer.clipRectsCache()) | 195 if (ClipRectsCache* cache = m_layer.clipRectsCache()) |
185 cache->clear(cacheSlot); | 196 cache->clear(cacheSlot); |
186 | 197 |
187 for (PaintLayer* layer = m_layer.firstChild(); layer; | 198 for (PaintLayer* layer = m_layer.firstChild(); layer; |
188 layer = layer->nextSibling()) { | 199 layer = layer->nextSibling()) { |
189 layer->clipper().clearClipRectsIncludingDescendants(cacheSlot); | 200 layer->clipper().clearClipRectsIncludingDescendants(cacheSlot); |
190 } | 201 } |
191 } | 202 } |
192 | 203 |
193 LayoutRect PaintLayerClipper::localClipRect( | 204 LayoutRect PaintLayerClipper::localClipRect( |
194 const PaintLayer* clippingRootLayer) const { | 205 const PaintLayer* clippingRootLayer) const { |
| 206 ClipRectsContext context(clippingRootLayer, PaintingClipRects); |
| 207 if (m_geometryMapper) { |
| 208 ClipRect clipRect = applyOverflowClipToBackgroundRectWithGeometryMapper( |
| 209 context, clipRectWithGeometryMapper(context, false)); |
| 210 |
| 211 // The rect now needs to be transformed to the local space of this |
| 212 // PaintLayer. |
| 213 bool success = false; |
| 214 FloatRect clippedRectInLocalSpace = |
| 215 m_geometryMapper->mapRectToDestinationSpace( |
| 216 FloatRect(clipRect.rect()), clippingRootLayer->layoutObject() |
| 217 ->objectPaintProperties() |
| 218 ->localBorderBoxProperties() |
| 219 ->propertyTreeState, |
| 220 m_layer.layoutObject() |
| 221 ->objectPaintProperties() |
| 222 ->localBorderBoxProperties() |
| 223 ->propertyTreeState, |
| 224 success); |
| 225 DCHECK(success); |
| 226 |
| 227 return LayoutRect(clippedRectInLocalSpace); |
| 228 } |
| 229 |
195 LayoutRect layerBounds; | 230 LayoutRect layerBounds; |
196 ClipRect backgroundRect, foregroundRect; | 231 ClipRect backgroundRect, foregroundRect; |
197 ClipRectsContext context(clippingRootLayer, PaintingClipRects); | |
198 calculateRects(context, LayoutRect(LayoutRect::infiniteIntRect()), | 232 calculateRects(context, LayoutRect(LayoutRect::infiniteIntRect()), |
199 layerBounds, backgroundRect, foregroundRect); | 233 layerBounds, backgroundRect, foregroundRect); |
200 | 234 |
201 LayoutRect clipRect = backgroundRect.rect(); | 235 LayoutRect clipRect = backgroundRect.rect(); |
202 // TODO(chrishtr): avoid converting to IntRect and back. | 236 // TODO(chrishtr): avoid converting to IntRect and back. |
203 if (clipRect == LayoutRect(LayoutRect::infiniteIntRect())) | 237 if (clipRect == LayoutRect(LayoutRect::infiniteIntRect())) |
204 return clipRect; | 238 return clipRect; |
205 | 239 |
206 LayoutPoint clippingRootOffset; | 240 LayoutPoint clippingRootOffset; |
207 m_layer.convertToLayerCoords(clippingRootLayer, clippingRootOffset); | 241 m_layer.convertToLayerCoords(clippingRootLayer, clippingRootOffset); |
208 clipRect.moveBy(-clippingRootOffset); | 242 clipRect.moveBy(-clippingRootOffset); |
209 | 243 |
210 return clipRect; | 244 return clipRect; |
211 } | 245 } |
212 | 246 |
| 247 #ifdef CHECK_CLIP_RECTS |
| 248 #define CHECK_RECTS_EQ(expected, actual) \ |
| 249 CHECK((expected.isEmpty() && actual.isEmpty()) || expected == actual) \ |
| 250 << "expected=" << expected.toString() << " actual=" << actual.toString() |
| 251 #endif |
| 252 |
| 253 void PaintLayerClipper::mapLocalToRootWithGeometryMapper( |
| 254 const ClipRectsContext& context, |
| 255 LayoutRect& layoutRect) const { |
| 256 DCHECK(m_geometryMapper); |
| 257 bool success; |
| 258 |
| 259 const ObjectPaintProperties::PropertyTreeStateWithOffset* |
| 260 layerBorderBoxProperties = m_layer.layoutObject() |
| 261 ->objectPaintProperties() |
| 262 ->localBorderBoxProperties(); |
| 263 FloatRect localRect(layoutRect); |
| 264 localRect.moveBy(FloatPoint(layerBorderBoxProperties->paintOffset)); |
| 265 |
| 266 layoutRect = LayoutRect(m_geometryMapper->mapRectToDestinationSpace( |
| 267 localRect, layerBorderBoxProperties->propertyTreeState, |
| 268 context.rootLayer->layoutObject() |
| 269 ->objectPaintProperties() |
| 270 ->localBorderBoxProperties() |
| 271 ->propertyTreeState, |
| 272 success)); |
| 273 DCHECK(success); |
| 274 } |
| 275 |
| 276 void PaintLayerClipper::calculateRectsWithGeometryMapper( |
| 277 const ClipRectsContext& context, |
| 278 const LayoutRect& paintDirtyRect, |
| 279 LayoutRect& layerBounds, |
| 280 ClipRect& backgroundRect, |
| 281 ClipRect& foregroundRect, |
| 282 const LayoutPoint* offsetFromRoot) const { |
| 283 backgroundRect = applyOverflowClipToBackgroundRectWithGeometryMapper( |
| 284 context, clipRectWithGeometryMapper(context, false)); |
| 285 backgroundRect.move( |
| 286 context.subPixelAccumulation); // TODO(chrishtr): is this needed? |
| 287 backgroundRect.intersect(paintDirtyRect); |
| 288 |
| 289 foregroundRect.move( |
| 290 context.subPixelAccumulation); // TODO(chrishtr): is this needed? |
| 291 foregroundRect = clipRectWithGeometryMapper(context, true); |
| 292 foregroundRect.intersect(paintDirtyRect); |
| 293 LayoutPoint offset; |
| 294 if (offsetFromRoot) |
| 295 offset = *offsetFromRoot; |
| 296 else |
| 297 m_layer.convertToLayerCoords(context.rootLayer, offset); |
| 298 layerBounds = LayoutRect(offset, LayoutSize(m_layer.size())); |
| 299 |
| 300 #ifdef CHECK_CLIP_RECTS |
| 301 ClipRect testBackgroundRect, testForegroundRect; |
| 302 LayoutRect testLayerBounds; |
| 303 PaintLayerClipper(m_layer, false) |
| 304 .calculateRects(context, paintDirtyRect, testLayerBounds, |
| 305 testBackgroundRect, testForegroundRect); |
| 306 CHECK_RECTS_EQ(testBackgroundRect, backgroundRect); |
| 307 CHECK_RECTS_EQ(testForegroundRect, foregroundRect); |
| 308 CHECK_RECTS_EQ(testLayerBounds, layerBounds); |
| 309 #endif |
| 310 } |
| 311 |
213 void PaintLayerClipper::calculateRects( | 312 void PaintLayerClipper::calculateRects( |
214 const ClipRectsContext& context, | 313 const ClipRectsContext& context, |
215 const LayoutRect& paintDirtyRect, | 314 const LayoutRect& paintDirtyRect, |
216 LayoutRect& layerBounds, | 315 LayoutRect& layerBounds, |
217 ClipRect& backgroundRect, | 316 ClipRect& backgroundRect, |
218 ClipRect& foregroundRect, | 317 ClipRect& foregroundRect, |
219 const LayoutPoint* offsetFromRoot) const { | 318 const LayoutPoint* offsetFromRoot) const { |
| 319 if (m_geometryMapper) { |
| 320 calculateRectsWithGeometryMapper(context, paintDirtyRect, layerBounds, |
| 321 backgroundRect, foregroundRect, |
| 322 offsetFromRoot); |
| 323 return; |
| 324 } |
| 325 |
220 bool isClippingRoot = &m_layer == context.rootLayer; | 326 bool isClippingRoot = &m_layer == context.rootLayer; |
221 LayoutBoxModelObject& layoutObject = *m_layer.layoutObject(); | 327 LayoutBoxModelObject& layoutObject = *m_layer.layoutObject(); |
222 | 328 |
223 if (!isClippingRoot && m_layer.parent()) { | 329 if (!isClippingRoot && m_layer.parent()) { |
224 backgroundRect = backgroundClipRect(context); | 330 backgroundRect = backgroundClipRect(context); |
225 backgroundRect.move(context.subPixelAccumulation); | 331 backgroundRect.move(context.subPixelAccumulation); |
226 backgroundRect.intersect(paintDirtyRect); | 332 backgroundRect.intersect(paintDirtyRect); |
227 } else { | 333 } else { |
228 backgroundRect = paintDirtyRect; | 334 backgroundRect = paintDirtyRect; |
229 } | 335 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 EPosition position) { | 426 EPosition position) { |
321 if (position == FixedPosition) | 427 if (position == FixedPosition) |
322 return parentRects.fixedClipRect(); | 428 return parentRects.fixedClipRect(); |
323 | 429 |
324 if (position == AbsolutePosition) | 430 if (position == AbsolutePosition) |
325 return parentRects.posClipRect(); | 431 return parentRects.posClipRect(); |
326 | 432 |
327 return parentRects.overflowClipRect(); | 433 return parentRects.overflowClipRect(); |
328 } | 434 } |
329 | 435 |
| 436 ClipRect PaintLayerClipper::clipRectWithGeometryMapper( |
| 437 const ClipRectsContext& context, |
| 438 bool isForeground) const { |
| 439 DCHECK(m_geometryMapper); |
| 440 LayoutRect source(LayoutRect::infiniteIntRect()); |
| 441 bool success = false; |
| 442 const ObjectPaintProperties* properties = |
| 443 m_layer.layoutObject()->objectPaintProperties(); |
| 444 PropertyTreeState propertyTreeState = |
| 445 properties->localBorderBoxProperties()->propertyTreeState; |
| 446 |
| 447 if (properties->cssClip()) |
| 448 propertyTreeState.setClip(properties->cssClip()); |
| 449 |
| 450 const LayoutObject& layoutObject = *m_layer.layoutObject(); |
| 451 if (shouldRespectOverflowClip(context) && isForeground && |
| 452 (layoutObject.hasOverflowClip() || |
| 453 layoutObject.styleRef().containsPaint())) { |
| 454 if (properties->overflowClip()) |
| 455 propertyTreeState.setClip(properties->overflowClip()); |
| 456 } |
| 457 |
| 458 const ObjectPaintProperties* ancestorProperties = |
| 459 context.rootLayer->layoutObject()->objectPaintProperties(); |
| 460 PropertyTreeState destinationPropertyTreeState = |
| 461 ancestorProperties->localBorderBoxProperties()->propertyTreeState; |
| 462 if (!context.rootLayer->clipper().shouldRespectOverflowClip(context)) { |
| 463 if (ancestorProperties->overflowClip()) |
| 464 destinationPropertyTreeState.setClip(ancestorProperties->overflowClip()); |
| 465 } |
| 466 FloatRect clippedRectInRootLayerSpace = |
| 467 m_geometryMapper->mapToVisualRectInDestinationSpace( |
| 468 FloatRect(source), propertyTreeState, destinationPropertyTreeState, |
| 469 success); |
| 470 DCHECK(success); |
| 471 return ClipRect(LayoutRect(clippedRectInRootLayerSpace)); |
| 472 } |
| 473 |
| 474 ClipRect PaintLayerClipper::applyOverflowClipToBackgroundRectWithGeometryMapper( |
| 475 const ClipRectsContext& context, |
| 476 const ClipRect& clip) const { |
| 477 const LayoutObject& layoutObject = *m_layer.layoutObject(); |
| 478 FloatRect clipRect(clip.rect()); |
| 479 if ((layoutObject.hasOverflowClip() || |
| 480 layoutObject.styleRef().containsPaint()) && |
| 481 shouldRespectOverflowClip(context)) { |
| 482 LayoutRect layerBoundsWithVisualOverflow = |
| 483 layoutObject.isLayoutView() |
| 484 ? toLayoutView(layoutObject).viewRect() |
| 485 : toLayoutBox(layoutObject).visualOverflowRect(); |
| 486 toLayoutBox(layoutObject) |
| 487 .flipForWritingMode( |
| 488 // PaintLayer are in physical coordinates, so the overflow has to be |
| 489 // flipped. |
| 490 layerBoundsWithVisualOverflow); |
| 491 mapLocalToRootWithGeometryMapper(context, layerBoundsWithVisualOverflow); |
| 492 clipRect.intersect(FloatRect(layerBoundsWithVisualOverflow)); |
| 493 } |
| 494 |
| 495 return ClipRect(LayoutRect(clipRect)); |
| 496 } |
| 497 |
330 ClipRect PaintLayerClipper::backgroundClipRect( | 498 ClipRect PaintLayerClipper::backgroundClipRect( |
331 const ClipRectsContext& context) const { | 499 const ClipRectsContext& context) const { |
| 500 if (m_geometryMapper) { |
| 501 ClipRect backgroundClipRect = clipRectWithGeometryMapper(context, false); |
| 502 #ifdef CHECK_CLIP_RECTS |
| 503 ClipRect testBackgroundClipRect = |
| 504 PaintLayerClipper(m_layer, false).backgroundClipRect(context); |
| 505 CHECK_RECTS_EQ(testBackgroundClipRect, backgroundClipRect); |
| 506 #endif |
| 507 return backgroundClipRect; |
| 508 } |
332 DCHECK(m_layer.parent()); | 509 DCHECK(m_layer.parent()); |
333 LayoutView* layoutView = m_layer.layoutObject()->view(); | 510 LayoutView* layoutView = m_layer.layoutObject()->view(); |
334 DCHECK(layoutView); | 511 DCHECK(layoutView); |
335 | 512 |
336 RefPtr<ClipRects> parentClipRects = ClipRects::create(); | 513 RefPtr<ClipRects> parentClipRects = ClipRects::create(); |
337 if (&m_layer == context.rootLayer) | 514 if (&m_layer == context.rootLayer) |
338 parentClipRects->reset(LayoutRect(LayoutRect::infiniteIntRect())); | 515 parentClipRects->reset(LayoutRect(LayoutRect::infiniteIntRect())); |
339 else | 516 else |
340 m_layer.parent()->clipper().getOrCalculateClipRects(context, | 517 m_layer.parent()->clipper().getOrCalculateClipRects(context, |
341 *parentClipRects); | 518 *parentClipRects); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 context.respectOverflowClipForViewport == IgnoreOverflowClip) | 550 context.respectOverflowClipForViewport == IgnoreOverflowClip) |
374 return false; | 551 return false; |
375 | 552 |
376 return true; | 553 return true; |
377 } | 554 } |
378 | 555 |
379 ClipRects& PaintLayerClipper::paintingClipRects( | 556 ClipRects& PaintLayerClipper::paintingClipRects( |
380 const PaintLayer* rootLayer, | 557 const PaintLayer* rootLayer, |
381 ShouldRespectOverflowClipType respectOverflowClip, | 558 ShouldRespectOverflowClipType respectOverflowClip, |
382 const LayoutSize& subpixelAccumulation) const { | 559 const LayoutSize& subpixelAccumulation) const { |
| 560 DCHECK(!m_geometryMapper); |
383 ClipRectsContext context(rootLayer, PaintingClipRects, | 561 ClipRectsContext context(rootLayer, PaintingClipRects, |
384 IgnoreOverlayScrollbarSize, subpixelAccumulation); | 562 IgnoreOverlayScrollbarSize, subpixelAccumulation); |
385 if (respectOverflowClip == IgnoreOverflowClip) | 563 if (respectOverflowClip == IgnoreOverflowClip) |
386 context.setIgnoreOverflowClip(); | 564 context.setIgnoreOverflowClip(); |
387 return getClipRects(context); | 565 return getClipRects(context); |
388 } | 566 } |
389 | 567 |
390 } // namespace blink | 568 } // namespace blink |
OLD | NEW |