OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/compositing/CompositedLayerMapping.h" | 5 #include "core/layout/compositing/CompositedLayerMapping.h" |
6 | 6 |
7 #include "core/frame/LocalFrameView.h" | 7 #include "core/frame/LocalFrameView.h" |
8 #include "core/layout/LayoutBoxModelObject.h" | 8 #include "core/layout/LayoutBoxModelObject.h" |
9 #include "core/layout/LayoutTestHelper.h" | 9 #include "core/layout/LayoutTestHelper.h" |
10 #include "core/layout/api/LayoutViewItem.h" | 10 #include "core/layout/api/LayoutViewItem.h" |
(...skipping 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1469 ToLayoutBoxModelObject(child->GetLayoutObject())->Layer(); | 1469 ToLayoutBoxModelObject(child->GetLayoutObject())->Layer(); |
1470 ASSERT_TRUE(child_paint_layer); | 1470 ASSERT_TRUE(child_paint_layer); |
1471 CompositedLayerMapping* child_mapping = | 1471 CompositedLayerMapping* child_mapping = |
1472 child_paint_layer->GetCompositedLayerMapping(); | 1472 child_paint_layer->GetCompositedLayerMapping(); |
1473 ASSERT_TRUE(child_mapping); | 1473 ASSERT_TRUE(child_mapping); |
1474 EXPECT_TRUE(child_mapping->AncestorClippingLayer()); | 1474 EXPECT_TRUE(child_mapping->AncestorClippingLayer()); |
1475 EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer()); | 1475 EXPECT_FALSE(child_mapping->AncestorClippingLayer()->MaskLayer()); |
1476 EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer()); | 1476 EXPECT_FALSE(child_mapping->AncestorClippingMaskLayer()); |
1477 } | 1477 } |
1478 | 1478 |
1479 TEST_P(CompositedLayerMappingTest, StickyPositionContentOffset) { | 1479 TEST_P(CompositedLayerMappingTest, StickyPositionMainThreadOffset) { |
1480 SetBodyInnerHTML( | |
1481 "<div style='width: 400px; height: 400px; overflow: auto; " | |
1482 "will-change: transform;' >" | |
1483 " <div id='sticky1' style='position: sticky; top: 0px; width: 100px; " | |
1484 "height: 100px; box-shadow: -5px -5px 5px 0 black; " | |
1485 "will-change: transform;'></div>" | |
1486 " <div style='height: 2000px;'></div>" | |
1487 "</div>" | |
1488 | |
1489 "<div style='width: 400px; height: 400px; overflow: auto; " | |
1490 "will-change: transform;' >" | |
1491 " <div id='sticky2' style='position: sticky; top: 0px; width: 100px; " | |
1492 "height: 100px; will-change: transform;'>" | |
1493 " <div style='position: absolute; top: -50px; left: -50px; " | |
1494 "width: 5px; height: 5px; background: red;'></div></div>" | |
1495 " <div style='height: 2000px;'></div>" | |
1496 "</div>"); | |
1497 GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(); | |
1498 | |
1499 CompositedLayerMapping* sticky1 = | |
1500 ToLayoutBlock(GetLayoutObjectByElementId("sticky1")) | |
1501 ->Layer() | |
1502 ->GetCompositedLayerMapping(); | |
1503 CompositedLayerMapping* sticky2 = | |
1504 ToLayoutBlock(GetLayoutObjectByElementId("sticky2")) | |
1505 ->Layer() | |
1506 ->GetCompositedLayerMapping(); | |
1507 | |
1508 // Box offsets the content by the combination of the shadow offset and blur | |
1509 // radius plus an additional pixel of anti-aliasing. | |
1510 ASSERT_TRUE(sticky1); | |
1511 WebLayerStickyPositionConstraint constraint1 = | |
1512 sticky1->MainGraphicsLayer() | |
1513 ->ContentLayer() | |
1514 ->Layer() | |
1515 ->StickyPositionConstraint(); | |
1516 EXPECT_EQ(IntPoint(-11, -11), | |
1517 IntPoint(constraint1.parent_relative_sticky_box_offset)); | |
1518 | |
1519 // Since the nested div will be squashed into the same composited layer the | |
1520 // sticky element is offset by the nested element's offset. | |
1521 ASSERT_TRUE(sticky2); | |
1522 WebLayerStickyPositionConstraint constraint2 = | |
1523 sticky2->MainGraphicsLayer() | |
1524 ->ContentLayer() | |
1525 ->Layer() | |
1526 ->StickyPositionConstraint(); | |
1527 EXPECT_EQ(IntPoint(-50, -50), | |
1528 IntPoint(constraint2.parent_relative_sticky_box_offset)); | |
1529 } | |
1530 | |
1531 TEST_P(CompositedLayerMappingTest, StickyPositionTableCellContentOffset) { | |
1532 SetBodyInnerHTML( | |
1533 "<style>body {height: 2000px; width: 2000px;} " | |
1534 "td, th { height: 50px; width: 50px; } " | |
1535 "table {border: none; }" | |
1536 "#scroller { overflow: auto; will-change: transform; height: 50px; }" | |
1537 "#sticky { position: sticky; left: 0; will-change: transform; }" | |
1538 "</style>" | |
1539 "<div id='scroller'><table cellspacing='0' cellpadding='0'>" | |
1540 " <thead><tr><td></td></tr></thead>" | |
1541 " <tr><td id='sticky'></td></tr>" | |
1542 "</table></div>"); | |
1543 GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(); | |
1544 | |
1545 CompositedLayerMapping* sticky = | |
1546 ToLayoutBlock(GetLayoutObjectByElementId("sticky")) | |
1547 ->Layer() | |
1548 ->GetCompositedLayerMapping(); | |
1549 | |
1550 ASSERT_TRUE(sticky); | |
1551 WebLayerStickyPositionConstraint constraint = | |
1552 sticky->MainGraphicsLayer() | |
1553 ->ContentLayer() | |
1554 ->Layer() | |
1555 ->StickyPositionConstraint(); | |
1556 EXPECT_EQ(IntPoint(0, 50), | |
1557 IntPoint(constraint.parent_relative_sticky_box_offset)); | |
1558 } | |
1559 | |
1560 TEST_P(CompositedLayerMappingTest, StickyPositionEnclosingLayersContentOffset) { | |
1561 // Using backface-visibility: hidden causes the scroller to become composited | |
1562 // without creating a stacking context. This is important as enclosing layer | |
1563 // scroll correction works differently depending on whether you are in a | |
1564 // stacking context or not. | |
1565 SetBodyInnerHTML( | 1480 SetBodyInnerHTML( |
1566 "<style>.composited { backface-visibility: hidden; }" | 1481 "<style>.composited { backface-visibility: hidden; }" |
1567 "#scroller { overflow: auto; height: 200px; width: 200px; }" | 1482 "#scroller { overflow: auto; height: 200px; width: 200px; }" |
1568 ".container { height: 500px; }" | 1483 ".container { height: 500px; }" |
1569 ".innerPadding { height: 10px; }" | 1484 ".innerPadding { height: 10px; }" |
1570 "#sticky { position: sticky; top: 25px; height: 50px; }</style>" | 1485 "#sticky { position: sticky; top: 25px; height: 50px; }</style>" |
1571 "<div id='scroller' class='composited'>" | 1486 "<div id='scroller' class='composited'>" |
1572 " <div class='composited container'>" | 1487 " <div class='composited container'>" |
1573 " <div class='composited container'>" | 1488 " <div class='composited container'>" |
1574 " <div class='innerPadding'></div>" | 1489 " <div class='innerPadding'></div>" |
1575 " <div id='sticky' class='composited'></div>" | 1490 " <div id='sticky' class='composited'></div>" |
1576 " </div></div></div>"); | 1491 " </div></div></div>"); |
1577 | 1492 |
1578 PaintLayer* sticky_layer = | 1493 PaintLayer* sticky_layer = |
1579 ToLayoutBox(GetLayoutObjectByElementId("sticky"))->Layer(); | 1494 ToLayoutBox(GetLayoutObjectByElementId("sticky"))->Layer(); |
1580 CompositedLayerMapping* sticky_mapping = | 1495 CompositedLayerMapping* sticky_mapping = |
1581 sticky_layer->GetCompositedLayerMapping(); | 1496 sticky_layer->GetCompositedLayerMapping(); |
1582 ASSERT_TRUE(sticky_mapping); | 1497 ASSERT_TRUE(sticky_mapping); |
| 1498 // Main thread offset for sticky should be "StickyTop - InnerPadding". |
| 1499 EXPECT_EQ(IntPoint(0, 15), IntPoint(sticky_mapping->MainGraphicsLayer() |
| 1500 ->ContentLayer() |
| 1501 ->Layer() |
| 1502 ->StickyMainThreadOffset())); |
1583 | 1503 |
1584 WebLayerStickyPositionConstraint constraint = | 1504 // Now scroll the page - this should increase the main thread offset. |
1585 sticky_mapping->MainGraphicsLayer() | |
1586 ->ContentLayer() | |
1587 ->Layer() | |
1588 ->StickyPositionConstraint(); | |
1589 EXPECT_EQ(IntPoint(0, 10), | |
1590 IntPoint(constraint.parent_relative_sticky_box_offset)); | |
1591 | |
1592 // Now scroll the page - this should not affect the parent-relative offset. | |
1593 LayoutBoxModelObject* scroller = | 1505 LayoutBoxModelObject* scroller = |
1594 ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller")); | 1506 ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller")); |
1595 PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea(); | 1507 PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea(); |
1596 scrollable_area->ScrollToAbsolutePosition( | 1508 scrollable_area->ScrollToAbsolutePosition( |
1597 FloatPoint(scrollable_area->ScrollPosition().X(), 100)); | 1509 FloatPoint(scrollable_area->ScrollPosition().X(), 100)); |
1598 ASSERT_EQ(100.0, scrollable_area->ScrollPosition().Y()); | 1510 ASSERT_EQ(100.0, scrollable_area->ScrollPosition().Y()); |
1599 | 1511 |
1600 sticky_layer->SetNeedsCompositingInputsUpdate(); | 1512 sticky_layer->SetNeedsCompositingInputsUpdate(); |
1601 EXPECT_TRUE(sticky_layer->NeedsCompositingInputsUpdate()); | 1513 EXPECT_TRUE(sticky_layer->NeedsCompositingInputsUpdate()); |
1602 GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(); | 1514 GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(); |
1603 EXPECT_FALSE(sticky_layer->NeedsCompositingInputsUpdate()); | 1515 EXPECT_FALSE(sticky_layer->NeedsCompositingInputsUpdate()); |
1604 | 1516 |
1605 constraint = sticky_mapping->MainGraphicsLayer() | 1517 EXPECT_EQ(IntPoint(0, 115), IntPoint(sticky_mapping->MainGraphicsLayer() |
1606 ->ContentLayer() | 1518 ->ContentLayer() |
1607 ->Layer() | 1519 ->Layer() |
1608 ->StickyPositionConstraint(); | 1520 ->StickyMainThreadOffset())); |
1609 EXPECT_EQ(IntPoint(0, 10), | |
1610 IntPoint(constraint.parent_relative_sticky_box_offset)); | |
1611 } | |
1612 | |
1613 TEST_P(CompositedLayerMappingTest, | |
1614 StickyPositionEnclosingLayersWithStackingContextContentOffset) { | |
1615 // Using will-change: transform causes the scroller to become a stacking | |
1616 // context. This changes how its descendant layers interact with it; they no | |
1617 // longer have a scrollParent and instead just refer to it only as their | |
1618 // ancestorOverflowLayer. | |
1619 SetBodyInnerHTML( | |
1620 "<style>.composited { will-change: transform; }" | |
1621 "#scroller { overflow: auto; height: 200px; width: 200px; }" | |
1622 ".container { height: 500px; }" | |
1623 ".innerPadding { height: 10px; }" | |
1624 "#sticky { position: sticky; top: 25px; height: 50px; }</style>" | |
1625 "<div id='scroller' class='composited'>" | |
1626 " <div class='composited container'>" | |
1627 " <div class='composited container'>" | |
1628 " <div class='innerPadding'></div>" | |
1629 " <div id='sticky' class='composited'></div>" | |
1630 " </div></div></div>"); | |
1631 | |
1632 PaintLayer* sticky_layer = | |
1633 ToLayoutBox(GetLayoutObjectByElementId("sticky"))->Layer(); | |
1634 CompositedLayerMapping* sticky_mapping = | |
1635 sticky_layer->GetCompositedLayerMapping(); | |
1636 ASSERT_TRUE(sticky_mapping); | |
1637 | |
1638 WebLayerStickyPositionConstraint constraint = | |
1639 sticky_mapping->MainGraphicsLayer() | |
1640 ->ContentLayer() | |
1641 ->Layer() | |
1642 ->StickyPositionConstraint(); | |
1643 EXPECT_EQ(IntPoint(0, 10), | |
1644 IntPoint(constraint.parent_relative_sticky_box_offset)); | |
1645 | |
1646 // Now scroll the page - this should not affect the parent-relative offset. | |
1647 LayoutBoxModelObject* scroller = | |
1648 ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller")); | |
1649 PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea(); | |
1650 scrollable_area->ScrollToAbsolutePosition( | |
1651 FloatPoint(scrollable_area->ScrollPosition().X(), 100)); | |
1652 ASSERT_EQ(100.0, scrollable_area->ScrollPosition().Y()); | |
1653 | |
1654 sticky_layer->SetNeedsCompositingInputsUpdate(); | |
1655 EXPECT_TRUE(sticky_layer->NeedsCompositingInputsUpdate()); | |
1656 GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(); | |
1657 EXPECT_FALSE(sticky_layer->NeedsCompositingInputsUpdate()); | |
1658 | |
1659 constraint = sticky_mapping->MainGraphicsLayer() | |
1660 ->ContentLayer() | |
1661 ->Layer() | |
1662 ->StickyPositionConstraint(); | |
1663 EXPECT_EQ(IntPoint(0, 10), | |
1664 IntPoint(constraint.parent_relative_sticky_box_offset)); | |
1665 } | 1521 } |
1666 | 1522 |
1667 TEST_P(CompositedLayerMappingTest, StickyPositionNotSquashed) { | 1523 TEST_P(CompositedLayerMappingTest, StickyPositionNotSquashed) { |
1668 SetBodyInnerHTML( | 1524 SetBodyInnerHTML( |
1669 "<style>" | 1525 "<style>" |
1670 "#scroller { overflow: auto; height: 200px; }" | 1526 "#scroller { overflow: auto; height: 200px; }" |
1671 "#sticky1, #sticky2, #sticky3 {position: sticky; top: 0; width: 50px;" | 1527 "#sticky1, #sticky2, #sticky3 {position: sticky; top: 0; width: 50px;" |
1672 " height: 50px; background: rgba(0, 128, 0, 0.5);}" | 1528 " height: 50px; background: rgba(0, 128, 0, 0.5);}" |
1673 "#sticky1 {backface-visibility: hidden;}" | 1529 "#sticky1 {backface-visibility: hidden;}" |
1674 ".spacer {height: 2000px;}" | 1530 ".spacer {height: 2000px;}" |
(...skipping 23 matching lines...) Expand all Loading... |
1698 GetDocument().View()->UpdateAllLifecyclePhases(); | 1554 GetDocument().View()->UpdateAllLifecyclePhases(); |
1699 | 1555 |
1700 // Now that sticky2 and sticky3 overlap sticky1 they will be promoted, but | 1556 // Now that sticky2 and sticky3 overlap sticky1 they will be promoted, but |
1701 // they should not be squashed into the same layer because they scroll with | 1557 // they should not be squashed into the same layer because they scroll with |
1702 // respect to each other. | 1558 // respect to each other. |
1703 EXPECT_EQ(kPaintsIntoOwnBacking, sticky1->GetCompositingState()); | 1559 EXPECT_EQ(kPaintsIntoOwnBacking, sticky1->GetCompositingState()); |
1704 EXPECT_EQ(kPaintsIntoOwnBacking, sticky2->GetCompositingState()); | 1560 EXPECT_EQ(kPaintsIntoOwnBacking, sticky2->GetCompositingState()); |
1705 EXPECT_EQ(kPaintsIntoOwnBacking, sticky3->GetCompositingState()); | 1561 EXPECT_EQ(kPaintsIntoOwnBacking, sticky3->GetCompositingState()); |
1706 } | 1562 } |
1707 | 1563 |
1708 TEST_P(CompositedLayerMappingTest, StickyPositionNestedStickyContentOffset) { | |
1709 SetBodyInnerHTML( | |
1710 "<style>.composited { will-change: transform; }" | |
1711 "#scroller { overflow: auto; height: 200px; width: 200px; }" | |
1712 ".container { height: 500px; }" | |
1713 "#outerSticky { position: sticky; top: 0; height: 100px; }" | |
1714 "#middleSticky { position: sticky; top: 10px; height: 50px; }" | |
1715 "#innerSticky { position: sticky; top: 25px; height: 25px; }</style>" | |
1716 "<div id='scroller' class='composited'>" | |
1717 " <div style='height: 50px'></div>" | |
1718 " <div class='composited container'>" | |
1719 " <div style='height: 10px;'></div>" | |
1720 " <div id='outerSticky' class='composited'>" | |
1721 " <div id='middleSticky' class='composited'>" | |
1722 " <div style='height: 5px;'></div>" | |
1723 " <div id='innerSticky' class='composited'></div>" | |
1724 " </div>" | |
1725 " </div>" | |
1726 " </div>" | |
1727 "</div>"); | |
1728 | |
1729 PaintLayer* outer_sticky = | |
1730 ToLayoutBox(GetLayoutObjectByElementId("outerSticky"))->Layer(); | |
1731 PaintLayer* middle_sticky = | |
1732 ToLayoutBox(GetLayoutObjectByElementId("middleSticky"))->Layer(); | |
1733 PaintLayer* inner_sticky = | |
1734 ToLayoutBox(GetLayoutObjectByElementId("innerSticky"))->Layer(); | |
1735 | |
1736 WebLayerStickyPositionConstraint outer_sticky_constraint = | |
1737 outer_sticky->GetCompositedLayerMapping() | |
1738 ->MainGraphicsLayer() | |
1739 ->ContentLayer() | |
1740 ->Layer() | |
1741 ->StickyPositionConstraint(); | |
1742 WebLayerStickyPositionConstraint middle_sticky_constraint = | |
1743 middle_sticky->GetCompositedLayerMapping() | |
1744 ->MainGraphicsLayer() | |
1745 ->ContentLayer() | |
1746 ->Layer() | |
1747 ->StickyPositionConstraint(); | |
1748 WebLayerStickyPositionConstraint inner_sticky_constraint = | |
1749 inner_sticky->GetCompositedLayerMapping() | |
1750 ->MainGraphicsLayer() | |
1751 ->ContentLayer() | |
1752 ->Layer() | |
1753 ->StickyPositionConstraint(); | |
1754 | |
1755 EXPECT_EQ( | |
1756 IntPoint(0, 10), | |
1757 IntPoint(outer_sticky_constraint.parent_relative_sticky_box_offset)); | |
1758 EXPECT_EQ( | |
1759 IntPoint(0, 0), | |
1760 IntPoint(middle_sticky_constraint.parent_relative_sticky_box_offset)); | |
1761 EXPECT_EQ( | |
1762 IntPoint(0, 5), | |
1763 IntPoint(inner_sticky_constraint.parent_relative_sticky_box_offset)); | |
1764 | |
1765 // Scroll the content to engage the sticky elements. | |
1766 LayoutBoxModelObject* scroller = | |
1767 ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller")); | |
1768 PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea(); | |
1769 scrollable_area->ScrollToAbsolutePosition( | |
1770 FloatPoint(scrollable_area->ScrollPosition().X(), 110)); | |
1771 ASSERT_EQ(110.0, scrollable_area->ScrollPosition().Y()); | |
1772 | |
1773 outer_sticky->SetNeedsCompositingInputsUpdate(); | |
1774 middle_sticky->SetNeedsCompositingInputsUpdate(); | |
1775 inner_sticky->SetNeedsCompositingInputsUpdate(); | |
1776 | |
1777 GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(); | |
1778 | |
1779 outer_sticky_constraint = outer_sticky->GetCompositedLayerMapping() | |
1780 ->MainGraphicsLayer() | |
1781 ->ContentLayer() | |
1782 ->Layer() | |
1783 ->StickyPositionConstraint(); | |
1784 middle_sticky_constraint = middle_sticky->GetCompositedLayerMapping() | |
1785 ->MainGraphicsLayer() | |
1786 ->ContentLayer() | |
1787 ->Layer() | |
1788 ->StickyPositionConstraint(); | |
1789 inner_sticky_constraint = inner_sticky->GetCompositedLayerMapping() | |
1790 ->MainGraphicsLayer() | |
1791 ->ContentLayer() | |
1792 ->Layer() | |
1793 ->StickyPositionConstraint(); | |
1794 | |
1795 // After scrolling and despite ancestor sticky changes, the offset relative to | |
1796 // the parent layer should remain constant. | |
1797 EXPECT_EQ( | |
1798 IntPoint(0, 10), | |
1799 IntPoint(outer_sticky_constraint.parent_relative_sticky_box_offset)); | |
1800 EXPECT_EQ( | |
1801 IntPoint(0, 0), | |
1802 IntPoint(middle_sticky_constraint.parent_relative_sticky_box_offset)); | |
1803 EXPECT_EQ( | |
1804 IntPoint(0, 5), | |
1805 IntPoint(inner_sticky_constraint.parent_relative_sticky_box_offset)); | |
1806 } | |
1807 | |
1808 } // namespace blink | 1564 } // namespace blink |
OLD | NEW |