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/layout/LayoutBoxModelObject.h" | 5 #include "core/layout/LayoutBoxModelObject.h" |
6 | 6 |
7 #include "core/dom/DOMTokenList.h" | 7 #include "core/dom/DOMTokenList.h" |
8 #include "core/dom/DocumentLifecycle.h" | 8 #include "core/dom/DocumentLifecycle.h" |
9 #include "core/html/HTMLElement.h" | 9 #include "core/html/HTMLElement.h" |
10 #include "core/layout/ImageQualityController.h" | 10 #include "core/layout/ImageQualityController.h" |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
332 // computing the sticky constraints. Any such ancestor is the first sticky | 332 // computing the sticky constraints. Any such ancestor is the first sticky |
333 // element between you and your containing block (exclusive). | 333 // element between you and your containing block (exclusive). |
334 // | 334 // |
335 // In most cases, this pointer should be null since your parent is normally your | 335 // In most cases, this pointer should be null since your parent is normally your |
336 // containing block. However there are cases where this is not true, including | 336 // containing block. However there are cases where this is not true, including |
337 // inline blocks and tables. The latter is currently irrelevant since only table | 337 // inline blocks and tables. The latter is currently irrelevant since only table |
338 // cells can be sticky in CSS2.1, but we can test the former. | 338 // cells can be sticky in CSS2.1, but we can test the former. |
339 TEST_F(LayoutBoxModelObjectTest, | 339 TEST_F(LayoutBoxModelObjectTest, |
340 StickyPositionFindsCorrectStickyBoxShiftingAncestor) { | 340 StickyPositionFindsCorrectStickyBoxShiftingAncestor) { |
341 setBodyInnerHTML( | 341 setBodyInnerHTML( |
342 "<style>#stickyOuterDiv { position: sticky; }" | 342 "<style>#stickyOuterDiv { position: sticky; top: 0;}" |
343 "#stickyOuterInline { position: sticky; display: inline; }" | 343 "#stickyOuterInline { position: sticky; top: 0; display: inline; }" |
344 "#stickyInnerInline { position: sticky; display: inline; }</style>" | 344 "#unanchoredSticky { position: sticky; display: inline; }" |
345 "<div id='stickyOuterDiv'><div id='stickyOuterInline'>" | 345 "#stickyInnerInline { position: sticky; top: 0; display: inline; " |
346 "<div id='stickyInnerInline'></div></div></div>"); | 346 "}</style>" |
347 "<div id='stickyOuterDiv'>" | |
348 " <div id='stickyOuterInline'>" | |
349 " <div id='unanchoredSticky'>" | |
350 " <div id='stickyInnerInline'></div>" | |
351 " </div>" | |
352 " </div>" | |
353 "</div>"); | |
347 | 354 |
348 LayoutBoxModelObject* stickyOuterDiv = | 355 LayoutBoxModelObject* stickyOuterDiv = |
349 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyOuterDiv")); | 356 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyOuterDiv")); |
350 LayoutBoxModelObject* stickyOuterInline = | 357 LayoutBoxModelObject* stickyOuterInline = |
351 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyOuterInline")); | 358 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyOuterInline")); |
352 LayoutBoxModelObject* stickyInnerInline = | 359 LayoutBoxModelObject* stickyInnerInline = |
353 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyInnerInline")); | 360 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyInnerInline")); |
354 | 361 |
355 PaintLayerScrollableArea* scrollableArea = | 362 PaintLayerScrollableArea* scrollableArea = |
356 stickyOuterDiv->layer()->ancestorOverflowLayer()->getScrollableArea(); | 363 stickyOuterDiv->layer()->ancestorOverflowLayer()->getScrollableArea(); |
357 ASSERT_TRUE(scrollableArea); | 364 ASSERT_TRUE(scrollableArea); |
358 StickyConstraintsMap constraintsMap = scrollableArea->stickyConstraintsMap(); | 365 StickyConstraintsMap constraintsMap = scrollableArea->stickyConstraintsMap(); |
359 | 366 |
360 ASSERT_TRUE(constraintsMap.contains(stickyOuterDiv->layer())); | 367 ASSERT_TRUE(constraintsMap.contains(stickyOuterDiv->layer())); |
361 ASSERT_TRUE(constraintsMap.contains(stickyOuterInline->layer())); | 368 ASSERT_TRUE(constraintsMap.contains(stickyOuterInline->layer())); |
362 ASSERT_TRUE(constraintsMap.contains(stickyInnerInline->layer())); | 369 ASSERT_TRUE(constraintsMap.contains(stickyInnerInline->layer())); |
chrishtr
2017/03/27 16:28:07
ASSERT_FALSE for unanchoredSticky?
flackr
2017/04/07 18:15:45
Done.
| |
363 | 370 |
364 // The outer block element trivially has no sticky-box shifting ancestor. | 371 // The outer block element trivially has no sticky-box shifting ancestor. |
365 EXPECT_FALSE(constraintsMap.at(stickyOuterDiv->layer()) | 372 EXPECT_FALSE(constraintsMap.at(stickyOuterDiv->layer()) |
366 .nearestStickyBoxShiftingStickyBox()); | 373 .nearestStickyBoxShiftingStickyBox()); |
367 | 374 |
368 // Neither does the outer inline element, as its parent element is also its | 375 // Neither does the outer inline element, as its parent element is also its |
369 // containing block. | 376 // containing block. |
370 EXPECT_FALSE(constraintsMap.at(stickyOuterInline->layer()) | 377 EXPECT_FALSE(constraintsMap.at(stickyOuterInline->layer()) |
371 .nearestStickyBoxShiftingStickyBox()); | 378 .nearestStickyBoxShiftingStickyBox()); |
372 | 379 |
373 // However the inner inline element does have a sticky-box shifting ancestor, | 380 // However the inner inline element does have a sticky-box shifting ancestor, |
374 // as its containing block is the ancestor block element, not its parent. | 381 // as its containing block is the ancestor block element, not its parent. |
375 EXPECT_EQ(stickyOuterInline, | 382 EXPECT_EQ(stickyOuterInline, |
376 constraintsMap.at(stickyInnerInline->layer()) | 383 constraintsMap.at(stickyInnerInline->layer()) |
377 .nearestStickyBoxShiftingStickyBox()); | 384 .nearestStickyBoxShiftingStickyBox()); |
378 } | 385 } |
379 | 386 |
380 // Verifies that the correct containing-block shifting ancestor is found when | 387 // Verifies that the correct containing-block shifting ancestor is found when |
381 // computing the sticky constraints. Any such ancestor is the first sticky | 388 // computing the sticky constraints. Any such ancestor is the first sticky |
382 // element between your containing block (inclusive) and your ancestor overflow | 389 // element between your containing block (inclusive) and your ancestor overflow |
383 // layer (exclusive). | 390 // layer (exclusive). |
384 TEST_F(LayoutBoxModelObjectTest, | 391 TEST_F(LayoutBoxModelObjectTest, |
385 StickyPositionFindsCorrectContainingBlockShiftingAncestor) { | 392 StickyPositionFindsCorrectContainingBlockShiftingAncestor) { |
386 // We make the scroller itself sticky in order to check that elements do not | 393 // We make the scroller itself sticky in order to check that elements do not |
387 // detect it as their containing-block shifting ancestor. | 394 // detect it as their containing-block shifting ancestor. |
388 setBodyInnerHTML( | 395 setBodyInnerHTML( |
389 "<style>#scroller { overflow-y: scroll; position: sticky; }" | 396 "<style>#scroller { overflow-y: scroll; position: sticky; top: 0;}" |
390 "#stickyParent { position: sticky; }" | 397 "#stickyParent { position: sticky; top: 0;}" |
391 "#stickyChild { position: sticky; }" | 398 "#stickyChild { position: sticky; top: 0;}" |
392 "#stickyNestedChild { position: sticky; }</style>" | 399 "#unanchoredSticky { position: sticky; }" |
393 "<div id='scroller'><div id='stickyParent'><div id='stickyChild'></div>" | 400 "#stickyNestedChild { position: sticky; top: 0;}</style>" |
394 "<div><div id='stickyNestedChild'></div></div></div></div>"); | 401 "<div id='scroller'>" |
402 " <div id='stickyParent'>" | |
403 " <div id='unanchoredSticky'>" | |
404 " <div id='stickyChild'></div>" | |
405 " <div><div id='stickyNestedChild'></div></div>" | |
406 " </div>" | |
407 " </div>" | |
408 "</div>"); | |
395 | 409 |
396 LayoutBoxModelObject* scroller = | 410 LayoutBoxModelObject* scroller = |
397 toLayoutBoxModelObject(getLayoutObjectByElementId("scroller")); | 411 toLayoutBoxModelObject(getLayoutObjectByElementId("scroller")); |
398 LayoutBoxModelObject* stickyParent = | 412 LayoutBoxModelObject* stickyParent = |
399 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyParent")); | 413 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyParent")); |
400 LayoutBoxModelObject* stickyChild = | 414 LayoutBoxModelObject* stickyChild = |
401 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyChild")); | 415 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyChild")); |
402 LayoutBoxModelObject* stickyNestedChild = | 416 LayoutBoxModelObject* stickyNestedChild = |
403 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyNestedChild")); | 417 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyNestedChild")); |
404 | 418 |
405 PaintLayerScrollableArea* scrollableArea = | 419 PaintLayerScrollableArea* scrollableArea = |
406 scroller->layer()->getScrollableArea(); | 420 scroller->layer()->getScrollableArea(); |
407 ASSERT_TRUE(scrollableArea); | 421 ASSERT_TRUE(scrollableArea); |
408 StickyConstraintsMap constraintsMap = scrollableArea->stickyConstraintsMap(); | 422 StickyConstraintsMap constraintsMap = scrollableArea->stickyConstraintsMap(); |
409 | 423 |
410 ASSERT_FALSE(constraintsMap.contains(scroller->layer())); | 424 ASSERT_FALSE(constraintsMap.contains(scroller->layer())); |
411 ASSERT_TRUE(constraintsMap.contains(stickyParent->layer())); | 425 ASSERT_TRUE(constraintsMap.contains(stickyParent->layer())); |
412 ASSERT_TRUE(constraintsMap.contains(stickyChild->layer())); | 426 ASSERT_TRUE(constraintsMap.contains(stickyChild->layer())); |
413 ASSERT_TRUE(constraintsMap.contains(stickyNestedChild->layer())); | 427 ASSERT_TRUE(constraintsMap.contains(stickyNestedChild->layer())); |
414 | 428 |
415 // The outer <div> should not detect the scroller as its containing-block | 429 // The outer <div> should not detect the scroller as its containing-block |
416 // shifting ancestor. | 430 // shifting ancestor. |
417 EXPECT_FALSE(constraintsMap.at(stickyParent->layer()) | 431 EXPECT_FALSE(constraintsMap.at(stickyParent->layer()) |
418 .nearestStickyBoxShiftingContainingBlock()); | 432 .nearestStickyBoxShiftingContainingBlock()); |
419 | 433 |
420 // Both inner children should detect the parent <div> as their | 434 // Both inner children should detect the parent <div> as their |
421 // containing-block shifting ancestor. | 435 // containing-block shifting ancestor. They skip past unanchored sticky |
436 // because it will never have a non-zero offset. | |
422 EXPECT_EQ(stickyParent, | 437 EXPECT_EQ(stickyParent, |
423 constraintsMap.at(stickyChild->layer()) | 438 constraintsMap.at(stickyChild->layer()) |
424 .nearestStickyBoxShiftingContainingBlock()); | 439 .nearestStickyBoxShiftingContainingBlock()); |
425 EXPECT_EQ(stickyParent, | 440 EXPECT_EQ(stickyParent, |
426 constraintsMap.at(stickyNestedChild->layer()) | 441 constraintsMap.at(stickyNestedChild->layer()) |
427 .nearestStickyBoxShiftingContainingBlock()); | 442 .nearestStickyBoxShiftingContainingBlock()); |
428 } | 443 } |
429 | 444 |
430 // Verifies that the correct containing-block shifting ancestor is found when | 445 // Verifies that the correct containing-block shifting ancestor is found when |
431 // computing the sticky constraints, in the case where the overflow ancestor is | 446 // computing the sticky constraints, in the case where the overflow ancestor is |
432 // the page itself. This is a special-case version of the test above, as we | 447 // the page itself. This is a special-case version of the test above, as we |
433 // often treat the root page as special when it comes to scroll logic. It should | 448 // often treat the root page as special when it comes to scroll logic. It should |
434 // not make a difference for containing-block shifting ancestor calculations. | 449 // not make a difference for containing-block shifting ancestor calculations. |
435 TEST_F(LayoutBoxModelObjectTest, | 450 TEST_F(LayoutBoxModelObjectTest, |
436 StickyPositionFindsCorrectContainingBlockShiftingAncestorRoot) { | 451 StickyPositionFindsCorrectContainingBlockShiftingAncestorRoot) { |
437 setBodyInnerHTML( | 452 setBodyInnerHTML( |
438 "<style>#stickyParent { position: sticky; }" | 453 "<style>#stickyParent { position: sticky; top: 0;}" |
439 "#stickyGrandchild { position: sticky; }</style>" | 454 "#stickyGrandchild { position: sticky; top: 0;}</style>" |
440 "<div id='stickyParent'><div><div id='stickyGrandchild'></div></div>" | 455 "<div id='stickyParent'><div><div id='stickyGrandchild'></div></div>" |
441 "</div>"); | 456 "</div>"); |
442 | 457 |
443 LayoutBoxModelObject* stickyParent = | 458 LayoutBoxModelObject* stickyParent = |
444 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyParent")); | 459 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyParent")); |
445 LayoutBoxModelObject* stickyGrandchild = | 460 LayoutBoxModelObject* stickyGrandchild = |
446 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyGrandchild")); | 461 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyGrandchild")); |
447 | 462 |
448 PaintLayerScrollableArea* scrollableArea = | 463 PaintLayerScrollableArea* scrollableArea = |
449 stickyParent->layer()->ancestorOverflowLayer()->getScrollableArea(); | 464 stickyParent->layer()->ancestorOverflowLayer()->getScrollableArea(); |
(...skipping 11 matching lines...) Expand all Loading... | |
461 } | 476 } |
462 | 477 |
463 // Verifies that the correct containing-block shifting ancestor is found when | 478 // Verifies that the correct containing-block shifting ancestor is found when |
464 // computing the sticky constraints, in the case of tables. Tables are unusual | 479 // computing the sticky constraints, in the case of tables. Tables are unusual |
465 // because the containing block for all table elements is the <table> itself, so | 480 // because the containing block for all table elements is the <table> itself, so |
466 // we have to skip over elements to find the correct ancestor. | 481 // we have to skip over elements to find the correct ancestor. |
467 TEST_F(LayoutBoxModelObjectTest, | 482 TEST_F(LayoutBoxModelObjectTest, |
468 StickyPositionFindsCorrectContainingBlockShiftingAncestorTable) { | 483 StickyPositionFindsCorrectContainingBlockShiftingAncestorTable) { |
469 setBodyInnerHTML( | 484 setBodyInnerHTML( |
470 "<style>#scroller { overflow-y: scroll; }" | 485 "<style>#scroller { overflow-y: scroll; }" |
471 "#stickyOuter { position: sticky; }" | 486 "#stickyOuter { position: sticky; top: 0;}" |
472 "#stickyTh { position: sticky; }</style>" | 487 "#stickyTh { position: sticky; top: 0;}</style>" |
473 "<div id='scroller'><div id='stickyOuter'><table><thead><tr>" | 488 "<div id='scroller'><div id='stickyOuter'><table><thead><tr>" |
474 "<th id='stickyTh'></th></tr></thead></table></div></div>"); | 489 "<th id='stickyTh'></th></tr></thead></table></div></div>"); |
475 | 490 |
476 LayoutBoxModelObject* scroller = | 491 LayoutBoxModelObject* scroller = |
477 toLayoutBoxModelObject(getLayoutObjectByElementId("scroller")); | 492 toLayoutBoxModelObject(getLayoutObjectByElementId("scroller")); |
478 LayoutBoxModelObject* stickyOuter = | 493 LayoutBoxModelObject* stickyOuter = |
479 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyOuter")); | 494 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyOuter")); |
480 LayoutBoxModelObject* stickyTh = | 495 LayoutBoxModelObject* stickyTh = |
481 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyTh")); | 496 toLayoutBoxModelObject(getLayoutObjectByElementId("stickyTh")); |
482 | 497 |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
836 EXPECT_EQ(LayoutSize(0, 25), innerStickyTh->stickyPositionOffset()); | 851 EXPECT_EQ(LayoutSize(0, 25), innerStickyTh->stickyPositionOffset()); |
837 } | 852 } |
838 | 853 |
839 // Verifies that the calculated position:sticky offsets are correct in the case | 854 // Verifies that the calculated position:sticky offsets are correct in the case |
840 // of nested inline elements. | 855 // of nested inline elements. |
841 TEST_F(LayoutBoxModelObjectTest, StickyPositionNestedInlineElements) { | 856 TEST_F(LayoutBoxModelObjectTest, StickyPositionNestedInlineElements) { |
842 setBodyInnerHTML( | 857 setBodyInnerHTML( |
843 "<style>#scroller { width: 100px; height: 100px; overflow-y: scroll; }" | 858 "<style>#scroller { width: 100px; height: 100px; overflow-y: scroll; }" |
844 "#paddingBefore { height: 50px; }" | 859 "#paddingBefore { height: 50px; }" |
845 "#outerInline { display: inline; position: sticky; top: 0; }" | 860 "#outerInline { display: inline; position: sticky; top: 0; }" |
861 "#unanchoredSticky { position: sticky; display: inline; }" | |
846 "#innerInline { display: inline; position: sticky; top: 25px; }" | 862 "#innerInline { display: inline; position: sticky; top: 25px; }" |
847 "#paddingAfter { height: 200px; }</style>" | 863 "#paddingAfter { height: 200px; }</style>" |
848 "<div id='scroller'><div id='paddingBefore'></div><div id='outerInline'>" | 864 "<div id='scroller'>" |
849 "<div id='innerInline'></div></div><div id='paddingAfter'></div></div>"); | 865 " <div id='paddingBefore'></div>" |
866 " <div id='outerInline'>" | |
867 " <div id='unanchoredSticky'>" | |
868 " <div id='innerInline'></div>" | |
869 " </div>" | |
870 " </div>" | |
871 " <div id='paddingAfter'></div>" | |
872 "</div>"); | |
850 | 873 |
851 LayoutBoxModelObject* outerInline = | 874 LayoutBoxModelObject* outerInline = |
852 toLayoutBoxModelObject(getLayoutObjectByElementId("outerInline")); | 875 toLayoutBoxModelObject(getLayoutObjectByElementId("outerInline")); |
853 LayoutBoxModelObject* innerInline = | 876 LayoutBoxModelObject* innerInline = |
854 toLayoutBoxModelObject(getLayoutObjectByElementId("innerInline")); | 877 toLayoutBoxModelObject(getLayoutObjectByElementId("innerInline")); |
855 | 878 |
856 // Scroll the page down. | 879 // Scroll the page down. |
857 LayoutBoxModelObject* scroller = | 880 LayoutBoxModelObject* scroller = |
858 toLayoutBoxModelObject(getLayoutObjectByElementId("scroller")); | 881 toLayoutBoxModelObject(getLayoutObjectByElementId("scroller")); |
859 PaintLayerScrollableArea* scrollableArea = scroller->getScrollableArea(); | 882 PaintLayerScrollableArea* scrollableArea = scroller->getScrollableArea(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
905 | 928 |
906 // TODO(smcgruer): Until http://crbug.com/686164 is fixed, we need to update | 929 // TODO(smcgruer): Until http://crbug.com/686164 is fixed, we need to update |
907 // the constraints here before calculations will be correct. | 930 // the constraints here before calculations will be correct. |
908 innerSticky->updateStickyPositionConstraints(); | 931 innerSticky->updateStickyPositionConstraints(); |
909 | 932 |
910 EXPECT_EQ(LayoutSize(0, 100), outerSticky->stickyPositionOffset()); | 933 EXPECT_EQ(LayoutSize(0, 100), outerSticky->stickyPositionOffset()); |
911 EXPECT_EQ(LayoutSize(0, 25), innerSticky->stickyPositionOffset()); | 934 EXPECT_EQ(LayoutSize(0, 25), innerSticky->stickyPositionOffset()); |
912 } | 935 } |
913 | 936 |
914 } // namespace blink | 937 } // namespace blink |
OLD | NEW |