TEST_F(VisualRectMappingTest, ContainerOverflowHidden) { setBodyInnerHTML( "<div id='container' style='position: absolute; top: 111px; left: 222px;" " border: 10px solid red; overflow: hidden; width: 50px; height: " "80px;'>" " <div id='target' style='box-shadow: 40px 20px black; width: 100px; " "height: 90px'></div>" "</div>"); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); EXPECT_EQ(LayoutUnit(), container->scrollTop()); EXPECT_EQ(LayoutUnit(), container->scrollLeft()); container->setScrollTop(LayoutUnit(27)); container->setScrollLeft(LayoutUnit(28)); document().view()->updateAllLifecyclePhases(); LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); LayoutRect targetVisualRect = target->localVisualRect(); // 140 = width(100) + box_shadow_offset_x(40) // 110 = height(90) + box_shadow_offset_y(20) EXPECT_EQ(LayoutRect(0, 0, 140, 110), targetVisualRect); LayoutRect rect = targetVisualRect; EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect)); EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect); rect = targetVisualRect; EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); // Rect is not clipped by container's overflow clip. EXPECT_EQ(LayoutRect(10, 10, 140, 110), rect); }
TEST_F(LayoutSVGRootTest, VisualRectMappingWithViewportClipAndBorder) { setBodyInnerHTML( "<svg id='root' style='border: 10px solid red; width: 200px; height: " "100px; overflow: hidden' viewBox='0 0 200 100'>" " <rect id='rect' x='80' y='80' width='100' height='100'/>" "</svg>"); const LayoutSVGRoot& root = *toLayoutSVGRoot(getLayoutObjectByElementId("root")); const LayoutSVGShape& svgRect = *toLayoutSVGShape(getLayoutObjectByElementId("rect")); LayoutRect rect = SVGLayoutSupport::visualRectInAncestorSpace(svgRect, root); // (80, 80, 100, 100) added by root's content rect offset from border rect, // clipped by (10, 10, 200, 100). EXPECT_EQ(LayoutRect(90, 90, 100, 20), rect); LayoutRect rootVisualRect = static_cast<const LayoutObject&>(root).localVisualRect(); // SVG root with overflow:hidden doesn't include overflow from children, just // border box rect. EXPECT_EQ(LayoutRect(0, 0, 220, 120), rootVisualRect); rect = rootVisualRect; EXPECT_TRUE(root.mapToVisualRectInAncestorSpace(&root, rect)); // LayoutSVGRoot should not apply overflow clip on its own rect. EXPECT_EQ(LayoutRect(0, 0, 220, 120), rect); }
TEST_F(LayoutSVGRootTest, VisualRectMappingWithViewportClipWithoutBorder) { setBodyInnerHTML( "<svg id='root' style='width: 200px; height: 100px; overflow: hidden' " "viewBox='0 0 200 100'>" " <rect id='rect' x='80' y='80' width='100' height='100'/>" "</svg>"); const LayoutSVGRoot& root = *toLayoutSVGRoot(getLayoutObjectByElementId("root")); const LayoutSVGShape& svgRect = *toLayoutSVGShape(getLayoutObjectByElementId("rect")); LayoutRect rect = SVGLayoutSupport::visualRectInAncestorSpace(svgRect, root); // (80, 80, 100, 100) clipped by (0, 0, 200, 100). EXPECT_EQ(LayoutRect(80, 80, 100, 20), rect); LayoutRect rootVisualRect = static_cast<const LayoutObject&>(root).localVisualRect(); // SVG root doesn't have box decoration background, so just use clipped // overflow of children. EXPECT_EQ(LayoutRect(80, 80, 100, 20), rootVisualRect); rect = rootVisualRect; EXPECT_TRUE(root.mapToVisualRectInAncestorSpace(&root, rect)); EXPECT_EQ(LayoutRect(80, 80, 100, 20), rect); }
TEST_F(LayoutSVGRootTest, VisualRectMappingWithoutViewportClipWithBorder) { setBodyInnerHTML( "<svg id='root' style='border: 10px solid red; width: 200px; height: " "100px; overflow: visible' viewBox='0 0 200 100'>" " <rect id='rect' x='80' y='80' width='100' height='100'/>" "</svg>"); const LayoutSVGRoot& root = *toLayoutSVGRoot(getLayoutObjectByElementId("root")); const LayoutSVGShape& svgRect = *toLayoutSVGShape(getLayoutObjectByElementId("rect")); LayoutRect rect = SVGLayoutSupport::visualRectInAncestorSpace(svgRect, root); // (80, 80, 100, 100) added by root's content rect offset from border rect, // not clipped. EXPECT_EQ(LayoutRect(90, 90, 100, 100), rect); LayoutRect rootVisualRect = static_cast<const LayoutObject&>(root).localVisualRect(); // SVG root's overflow includes overflow from descendants. EXPECT_EQ(LayoutRect(0, 0, 220, 190), rootVisualRect); rect = rootVisualRect; EXPECT_TRUE(root.mapToVisualRectInAncestorSpace(&root, rect)); EXPECT_EQ(LayoutRect(0, 0, 220, 190), rect); }
TEST_F(VisualRectMappingTest, ContainerFlippedWritingMode) { setBodyInnerHTML( "<div id='container' style='writing-mode: vertical-rl; position: " "absolute; top: 111px; left: 222px'>" " <div id='target' style='box-shadow: 40px 20px black; width: 100px; " "height: 90px'></div>" " <div style='width: 100px; height: 100px'></div>" "</div>"); LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); LayoutRect targetVisualRect = target->localVisualRect(); // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the // origin) // 140 = width(100) + box_shadow_offset_x(40) // 110 = height(90) + box_shadow_offset_y(20) EXPECT_EQ(LayoutRect(-40, 0, 140, 110), targetVisualRect); LayoutRect rect = targetVisualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect)); // This rect is in physical coordinates of target. EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); rect = targetVisualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); // 100 is the physical x location of target in container. EXPECT_EQ(LayoutRect(100, 0, 140, 110), rect); rect = targetVisualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(LayoutRect(322, 111, 140, 110), rect); checkPaintInvalidationStateRectMapping(rect, targetVisualRect, *target, layoutView(), layoutView()); LayoutRect containerVisualRect = container->localVisualRect(); EXPECT_EQ(LayoutRect(0, 0, 200, 100), containerVisualRect); rect = containerVisualRect; container->flipForWritingMode(rect); EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(container, rect)); EXPECT_EQ(LayoutRect(0, 0, 200, 100), rect); rect = containerVisualRect; container->flipForWritingMode(rect); EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(LayoutRect(222, 111, 200, 100), rect); checkPaintInvalidationStateRectMapping(rect, containerVisualRect, *container, layoutView(), layoutView()); }
TEST_F(LayoutObjectTest, PaintingLayerOfOverflowClipLayerUnderColumnSpanAll) { setBodyInnerHTML( "<div id='columns' style='columns: 3'>" " <div style='column-span: all'>" " <div id='overflow-clip-layer' style='height: 100px; overflow: " "hidden'></div>" " </div>" "</div>"); LayoutObject* overflowClipObject = getLayoutObjectByElementId("overflow-clip-layer"); LayoutBlock* columns = toLayoutBlock(getLayoutObjectByElementId("columns")); EXPECT_EQ(columns->layer(), overflowClipObject->paintingLayer()); }
TEST_F(VisualRectMappingTest, DifferentPaintInvalidaitionContainerForAbsolutePosition) { enableCompositing(); document().frame()->settings()->setPreferCompositingToLCDTextEnabled(true); setBodyInnerHTML( "<div id='stacking-context' style='opacity: 0.9; background: blue; " "will-change: transform'>" " <div id='scroller' style='overflow: scroll; width: 80px; height: " "80px'>" " <div id='absolute' style='position: absolute; top: 111px; left: " "222px; width: 50px; height: 50px; background: green'></div>" " <div id='normal-flow' style='width: 2000px; height: 2000px; " "background: yellow'></div>" " </div>" "</div>"); LayoutBlock* scroller = toLayoutBlock(getLayoutObjectByElementId("scroller")); scroller->setScrollTop(LayoutUnit(77)); scroller->setScrollLeft(LayoutUnit(88)); document().view()->updateAllLifecyclePhases(); LayoutBlock* normalFlow = toLayoutBlock(getLayoutObjectByElementId("normal-flow")); EXPECT_EQ(scroller, &normalFlow->containerForPaintInvalidation()); LayoutRect normalFlowVisualRect = normalFlow->localVisualRect(); EXPECT_EQ(LayoutRect(0, 0, 2000, 2000), normalFlowVisualRect); LayoutRect rect = normalFlowVisualRect; EXPECT_TRUE(normalFlow->mapToVisualRectInAncestorSpace(scroller, rect)); EXPECT_EQ(LayoutRect(0, 0, 2000, 2000), rect); checkPaintInvalidationStateRectMapping(rect, normalFlowVisualRect, *normalFlow, layoutView(), *scroller); LayoutBlock* stackingContext = toLayoutBlock(getLayoutObjectByElementId("stacking-context")); LayoutBlock* absolute = toLayoutBlock(getLayoutObjectByElementId("absolute")); EXPECT_EQ(stackingContext, &absolute->containerForPaintInvalidation()); EXPECT_EQ(stackingContext, absolute->container()); LayoutRect absoluteVisualRect = absolute->localVisualRect(); EXPECT_EQ(LayoutRect(0, 0, 50, 50), absoluteVisualRect); rect = absoluteVisualRect; EXPECT_TRUE(absolute->mapToVisualRectInAncestorSpace(stackingContext, rect)); EXPECT_EQ(LayoutRect(222, 111, 50, 50), rect); checkPaintInvalidationStateRectMapping(rect, absoluteVisualRect, *absolute, layoutView(), *stackingContext); }
TEST_F(PaintLayerClipperTest, NestedContainPaintClip) { setBodyInnerHTML( "<div style='contain: paint; width: 200px; height: 200px; overflow: " "auto'>" " <div id='target' style='contain: paint; height: 400px'>" " </div>" "</div>"); LayoutRect infiniteRect(LayoutRect::infiniteIntRect()); PaintLayer* layer = toLayoutBoxModelObject(getLayoutObjectByElementId("target"))->layer(); ClipRectsContext context(layer->parent(), PaintingClipRectsIgnoringOverflowClip); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect; layer->clipper().calculateRects(context, infiniteRect, layerBounds, backgroundRect, foregroundRect); EXPECT_EQ(LayoutRect(0, 0, 200, 400), backgroundRect.rect()); EXPECT_EQ(LayoutRect(0, 0, 200, 400), foregroundRect.rect()); EXPECT_EQ(LayoutRect(0, 0, 200, 400), layerBounds); ClipRectsContext contextClip(layer->parent(), PaintingClipRects); layer->clipper().calculateRects(contextClip, infiniteRect, layerBounds, backgroundRect, foregroundRect); EXPECT_EQ(LayoutRect(0, 0, 200, 200), backgroundRect.rect()); EXPECT_EQ(LayoutRect(0, 0, 200, 200), foregroundRect.rect()); EXPECT_EQ(LayoutRect(0, 0, 200, 400), layerBounds); }
TEST_F(PaintControllerPaintTestForSlimmingPaintV2, CompositingFold) { setBodyInnerHTML( "<div id='div' style='width: 200px; height: 200px; opacity: 0.5'>" " <div style='width: 100px; height: 100px; background-color: " "blue'></div>" "</div>"); PaintLayer& htmlLayer = *toLayoutBoxModelObject(document().documentElement()->layoutObject()) ->layer(); LayoutBlock& div = *toLayoutBlock(getLayoutObjectByElementId("div")); LayoutObject& subDiv = *div.firstChild(); EXPECT_DISPLAY_LIST( rootPaintController().getDisplayItemList(), 8, TestDisplayItem(layoutView(), DisplayItem::kClipFrameToVisibleContentRect), TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence), TestDisplayItem(layoutView(), documentBackgroundType), TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), // The begin and end compositing display items have been folded into this // one. TestDisplayItem(subDiv, backgroundType), TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence), TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence), TestDisplayItem(layoutView(), DisplayItem::clipTypeToEndClipType( DisplayItem::kClipFrameToVisibleContentRect))); }
TEST_F(VisualRectMappingTest, LayoutInline) { document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com")); setBodyInnerHTML( "<style>body { margin: 0; }</style>" "<div id='container' style='overflow: scroll; width: 50px; height: 50px'>" " <span><img style='width: 20px; height: 100px'></span>" " <span id=leaf></span></div>"); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); LayoutObject* leaf = container->lastChild(); container->setScrollTop(LayoutUnit(50)); LayoutRect originalRect(0, 60, 20, 80); LayoutRect rect = originalRect; EXPECT_TRUE(leaf->mapToVisualRectInAncestorSpace(container, rect)); rect.move(-container->scrolledContentOffset()); EXPECT_EQ(rect, LayoutRect(0, 10, 20, 80)); rect = originalRect; EXPECT_TRUE(leaf->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(rect, LayoutRect(0, 10, 20, 40)); checkPaintInvalidationStateRectMapping(rect, originalRect, *leaf, layoutView(), layoutView()); rect = LayoutRect(0, 60, 80, 0); EXPECT_TRUE( leaf->mapToVisualRectInAncestorSpace(container, rect, EdgeInclusive)); rect.move(-container->scrolledContentOffset()); EXPECT_EQ(rect, LayoutRect(0, 10, 80, 0)); }
TEST_F(VisualRectMappingTest, LayoutText) { setBodyInnerHTML( "<style>body { margin: 0; }</style>" "<div id='container' style='overflow: scroll; width: 50px; height: 50px'>" " <span><img style='width: 20px; height: 100px'></span>" " text text text text text text text" "</div>"); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); LayoutText* text = toLayoutText(container->lastChild()); container->setScrollTop(LayoutUnit(50)); LayoutRect originalRect(0, 60, 20, 80); LayoutRect rect = originalRect; EXPECT_TRUE(text->mapToVisualRectInAncestorSpace(container, rect)); rect.move(-container->scrolledContentOffset()); EXPECT_EQ(rect, LayoutRect(0, 10, 20, 80)); rect = originalRect; EXPECT_TRUE(text->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(rect, LayoutRect(0, 10, 20, 40)); checkPaintInvalidationStateRectMapping(rect, originalRect, *text, layoutView(), layoutView()); rect = LayoutRect(0, 60, 80, 0); EXPECT_TRUE( text->mapToVisualRectInAncestorSpace(container, rect, EdgeInclusive)); rect.move(-container->scrolledContentOffset()); EXPECT_EQ(rect, LayoutRect(0, 10, 80, 0)); }
TEST_F(VisualRectMappingTest, SelfFlippedWritingMode) { setBodyInnerHTML( "<div id='target' style='writing-mode: vertical-rl; box-shadow: 40px " "20px black;" " width: 100px; height: 50px; position: absolute; top: 111px; left: " "222px'>" "</div>"); LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); LayoutRect visualRect = target->localVisualRect(); // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the // origin) // 140 = width(100) + box_shadow_offset_x(40) // 70 = height(50) + box_shadow_offset_y(20) EXPECT_EQ(LayoutRect(-40, 0, 140, 70), visualRect); LayoutRect rect = visualRect; // TODO(wkorman): The calls to flipForWritingMode() here and in other test // cases below are necessary because mapToVisualRectInAncestorSpace() // currently expects the input rect to be in "physical coordinates" (*not* // "physical coordinates with flipped block-flow direction"), see // LayoutBoxModelObject.h. target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect)); // This rect is in physical coordinates of target. EXPECT_EQ(LayoutRect(0, 0, 140, 70), rect); rect = visualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(LayoutRect(222, 111, 140, 70), rect); checkPaintInvalidationStateRectMapping(rect, visualRect, *target, layoutView(), layoutView()); }
TEST_F(VisualRectMappingTest, LayoutViewSubpixelRounding) { document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com")); setBodyInnerHTML( "<style>body { margin: 0; }</style>" "<div id=frameContainer style='position: relative; left: 0.5px'>" " <iframe style='position: relative; left: 0.5px' " "src='http://test.com' width='200' height='200' frameBorder='0'></iframe>" "</div>"); setChildFrameHTML( "<style>body { margin: 0; }</style><div id='target' style='position: " "relative; width: 100px; height: 100px; left: 0.5px'>"); document().view()->updateAllLifecyclePhases(); LayoutBlock* frameContainer = toLayoutBlock(getLayoutObjectByElementId("frameContainer")); LayoutObject* target = childDocument().getElementById("target")->layoutObject(); LayoutRect rect(0, 0, 100, 100); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(frameContainer, rect)); // When passing from the iframe to the parent frame, the rect of (0.5, 0, 100, // 100) is expanded to (0, 0, 100, 100), and then offset by the 0.5 offset of // frameContainer. EXPECT_EQ(LayoutRect(LayoutPoint(DoublePoint(0.5, 0)), LayoutSize(101, 100)), rect); }
TEST_F(LayoutBoxTest, BackgroundObscuredInRect) { setBodyInnerHTML("<style>.column { width: 295.4px; padding-left: 10.4px; } .white-background { background: red; position: relative; overflow: hidden; border-radius: 1px; }" ".black-background { height: 100px; background: black; color: white; } </style>" "<div class='column'> <div> <div id='target' class='white-background'> <div class='black-background'></div> </div> </div> </div>"); LayoutObject* layoutObject = getLayoutObjectByElementId("target"); ASSERT_TRUE(layoutObject); ASSERT_TRUE(layoutObject->boxDecorationBackgroundIsKnownToBeObscured()); }
TEST_F(VisualRectMappingTest, ContainerAndTargetDifferentFlippedWritingMode) { setBodyInnerHTML( "<div id='container' style='writing-mode: vertical-rl; position: " "absolute; top: 111px; left: 222px;" " border: solid red; border-width: 10px 20px 30px 40px;" " overflow: scroll; width: 50px; height: 80px'>" " <div id='target' style='writing-mode: vertical-lr; box-shadow: 40px " "20px black; width: 100px; height: 90px'></div>" " <div style='width: 100px; height: 100px'></div>" "</div>"); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); EXPECT_EQ(LayoutUnit(), container->scrollTop()); // The initial scroll offset is to the left-most because of flipped blocks // writing mode. // 150 = total_layout_overflow(100 + 100) - width(50) EXPECT_EQ(LayoutUnit(150), container->scrollLeft()); container->setScrollTop(LayoutUnit(7)); container->setScrollLeft( LayoutUnit(142)); // Scroll to the right by 8 pixels. document().view()->updateAllLifecyclePhases(); LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); LayoutRect targetVisualRect = target->localVisualRect(); // 140 = width(100) + box_shadow_offset_x(40) // 110 = height(90) + box_shadow_offset_y(20) EXPECT_EQ(LayoutRect(0, 0, 140, 110), targetVisualRect); LayoutRect rect = targetVisualRect; EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect)); // This rect is in physical coordinates of target. EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect); rect = targetVisualRect; EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); rect.move(-container->scrolledContentOffset()); // -2 = target_physical_x(100) + container_border_left(40) - scroll_left(142) // 3 = target_y(0) + container_border_top(10) - scroll_top(7) // Rect is not clipped by container's overflow clip. EXPECT_EQ(LayoutRect(-2, 3, 140, 110), rect); }
TEST_F(VisualRectMappingTest, ContainerFlippedWritingModeAndOverflowHidden) { setBodyInnerHTML( "<div id='container' style='writing-mode: vertical-rl; position: " "absolute; top: 111px; left: 222px;" " border: solid red; border-width: 10px 20px 30px 40px;" " overflow: hidden; width: 50px; height: 80px'>" " <div id='target' style='box-shadow: 40px 20px black; width: 100px; " "height: 90px'></div>" " <div style='width: 100px; height: 100px'></div>" "</div>"); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); EXPECT_EQ(LayoutUnit(), container->scrollTop()); // The initial scroll offset is to the left-most because of flipped blocks // writing mode. // 150 = total_layout_overflow(100 + 100) - width(50) EXPECT_EQ(LayoutUnit(150), container->scrollLeft()); container->setScrollTop(LayoutUnit(7)); container->setScrollLeft(LayoutUnit(82)); // Scroll to the right by 8 pixels. document().view()->updateAllLifecyclePhases(); LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); LayoutRect targetVisualRect = target->localVisualRect(); // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the // origin) // 140 = width(100) + box_shadow_offset_x(40) // 110 = height(90) + box_shadow_offset_y(20) EXPECT_EQ(LayoutRect(-40, 0, 140, 110), targetVisualRect); LayoutRect rect = targetVisualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect)); // This rect is in physical coordinates of target. EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect); rect = targetVisualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); // 58 = target_physical_x(100) + container_border_left(40) - scroll_left(58) EXPECT_EQ(LayoutRect(-10, 10, 140, 110), rect); }
TEST_F(PaintLayerTest, PaintingExtentReflectionWithTransform) { setBodyInnerHTML( "<div id='target' style='background-color: blue; position: absolute;" " width: 110px; height: 120px; top: 40px; left: 60px;" " -webkit-box-reflect: below 3px; transform: translateX(30px)'>" "</div>"); PaintLayer* layer = toLayoutBoxModelObject(getLayoutObjectByElementId("target"))->layer(); EXPECT_EQ( LayoutRect(90, 40, 110, 243), layer->paintingExtent(document().layoutView()->layer(), LayoutSize(), 0)); }
TEST_F(PaintLayerClipperTest, LocalClipRectFixedUnderTransform) { setBodyInnerHTML( "<div id='transformed'" " style='will-change: transform; width: 100px; height: 100px;" " overflow: hidden'>" " <div id='fixed' " " style='position: fixed; width: 100px; height: 100px;" " top: -50px'>" " </div>" "</div>"); LayoutRect infiniteRect(LayoutRect::infiniteIntRect()); PaintLayer* transformed = toLayoutBoxModelObject(getLayoutObjectByElementId("transformed")) ->layer(); PaintLayer* fixed = toLayoutBoxModelObject(getLayoutObjectByElementId("fixed"))->layer(); EXPECT_EQ(LayoutRect(0, 0, 100, 100), transformed->clipper().localClipRect(transformed)); EXPECT_EQ(LayoutRect(0, 50, 100, 100), fixed->clipper().localClipRect(transformed)); }
TEST_F(VisualRectMappingTest, ContainerOfAbsoluteAbovePaintInvalidationContainer) { enableCompositing(); document().frame()->settings()->setPreferCompositingToLCDTextEnabled(true); setBodyInnerHTML( "<div id='container' style='position: absolute; top: 88px; left: 99px'>" " <div style='height: 222px'></div>" // This div makes stacking-context composited. " <div style='position: absolute; width: 1px; height: 1px; " "background:yellow; will-change: transform'></div>" // This stacking context is paintInvalidationContainer of the absolute // child, but not a container of it. " <div id='stacking-context' style='opacity: 0.9'>" " <div id='absolute' style='position: absolute; top: 50px; left: " "50px; width: 50px; height: 50px; background: green'></div>" " </div>" "</div>"); LayoutBlock* stackingContext = toLayoutBlock(getLayoutObjectByElementId("stacking-context")); LayoutBlock* absolute = toLayoutBlock(getLayoutObjectByElementId("absolute")); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); EXPECT_EQ(stackingContext, &absolute->containerForPaintInvalidation()); EXPECT_EQ(container, absolute->container()); LayoutRect absoluteVisualRect = absolute->localVisualRect(); EXPECT_EQ(LayoutRect(0, 0, 50, 50), absoluteVisualRect); LayoutRect rect = absoluteVisualRect; EXPECT_TRUE(absolute->mapToVisualRectInAncestorSpace(stackingContext, rect)); // -172 = top(50) - y_offset_of_stacking_context(222) EXPECT_EQ(LayoutRect(50, -172, 50, 50), rect); checkPaintInvalidationStateRectMapping(rect, absoluteVisualRect, *absolute, layoutView(), *stackingContext); }
TEST_F(PaintControllerPaintTestForSlimmingPaintV2, ChunkIdClientCacheFlag) { setBodyInnerHTML( "<div id='div' style='width: 200px; height: 200px; opacity: 0.5'>" " <div style='width: 100px; height: 100px; background-color: " "blue'></div>" " <div style='width: 100px; height: 100px; background-color: " "blue'></div>" "</div>"); PaintLayer& htmlLayer = *toLayoutBoxModelObject(document().documentElement()->layoutObject()) ->layer(); LayoutBlock& div = *toLayoutBlock(getLayoutObjectByElementId("div")); LayoutObject& subDiv = *div.firstChild(); LayoutObject& subDiv2 = *subDiv.nextSibling(); EXPECT_DISPLAY_LIST( rootPaintController().getDisplayItemList(), 11, TestDisplayItem(layoutView(), DisplayItem::kClipFrameToVisibleContentRect), TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence), TestDisplayItem(layoutView(), documentBackgroundType), TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), TestDisplayItem(div, DisplayItem::kBeginCompositing), TestDisplayItem(subDiv, backgroundType), TestDisplayItem(subDiv2, backgroundType), TestDisplayItem(div, DisplayItem::kEndCompositing), TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence), TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence), TestDisplayItem(layoutView(), DisplayItem::clipTypeToEndClipType( DisplayItem::kClipFrameToVisibleContentRect))); const PaintChunk& backgroundChunk = rootPaintController().paintChunks()[0]; EXPECT_TRUE(backgroundChunk.properties.scroll->isRoot()); const EffectPaintPropertyNode* effectNode = div.paintProperties()->effect(); EXPECT_EQ(0.5f, effectNode->opacity()); const PaintChunk& chunk = rootPaintController().paintChunks()[1]; EXPECT_EQ(*div.layer(), chunk.id->client); EXPECT_EQ(effectNode, chunk.properties.effect.get()); EXPECT_FALSE(div.layer()->isJustCreated()); // Client used by only paint chunks and non-cachaeable display items but not // by any cacheable display items won't be marked as validly cached. EXPECT_FALSE(rootPaintController().clientCacheIsValid(*div.layer())); EXPECT_FALSE(rootPaintController().clientCacheIsValid(div)); EXPECT_TRUE(rootPaintController().clientCacheIsValid(subDiv)); }
TEST_F(VisualRectMappingTest, ContainPaint) { setBodyInnerHTML( "<div id='container' style='position: absolute; top: 0px; left: 0px; " "width: 200px; height: 200px; contain: paint'>" " <div id='target' style='width: 400px; height: 400px'></div>" " </div>" "</div>"); LayoutBox* target = toLayoutBox(getLayoutObjectByElementId("target")); LayoutRect targetVisualRect = target->localVisualRect(); EXPECT_EQ(LayoutRect(0, 0, 400, 400), targetVisualRect); LayoutRect rect = targetVisualRect; EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(LayoutRect(0, 0, 200, 200), rect); checkPaintInvalidationStateRectMapping(rect, targetVisualRect, *target, layoutView(), layoutView()); }
TEST_F(VisualRectMappingTest, LayoutView) { document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com")); setBodyInnerHTML( "<style>body { margin: 0; }</style>" "<div id=frameContainer>" " <iframe src='http://test.com' width='50' height='50' " "frameBorder='0'></iframe>" "</div>"); setChildFrameHTML( "<style>body { margin: 0; }</style><span><img style='width: 20px; " "height: 100px'></span>text text text"); document().view()->updateAllLifecyclePhases(); LayoutBlock* frameContainer = toLayoutBlock(getLayoutObjectByElementId("frameContainer")); LayoutBlock* frameBody = toLayoutBlock(childDocument().body()->layoutObject()); LayoutText* frameText = toLayoutText(frameBody->lastChild()); // This case involves clipping: frame height is 50, y-coordinate of result // rect is 13, so height should be clipped to (50 - 13) == 37. childDocument().view()->setScrollOffset(ScrollOffset(0, 47), ProgrammaticScroll); LayoutRect originalRect(4, 60, 20, 80); LayoutRect rect = originalRect; EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(frameContainer, rect)); EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37)); rect = originalRect; EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37)); checkPaintInvalidationStateRectMapping(rect, originalRect, *frameText, layoutView(), layoutView()); rect = LayoutRect(4, 60, 0, 80); EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(frameContainer, rect, EdgeInclusive)); EXPECT_EQ(rect, LayoutRect(4, 13, 0, 37)); }
TEST_F(VisualRectMappingTest, LayoutViewDisplayNone) { document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com")); setBodyInnerHTML( "<style>body { margin: 0; }</style>" "<div id=frameContainer>" " <iframe id='frame' src='http://test.com' width='50' height='50' " "frameBorder='0'></iframe>" "</div>"); setChildFrameHTML( "<style>body { margin: 0; }</style><div " "style='width:100px;height:100px;'></div>"); document().view()->updateAllLifecyclePhases(); LayoutBlock* frameContainer = toLayoutBlock(getLayoutObjectByElementId("frameContainer")); LayoutBlock* frameBody = toLayoutBlock(childDocument().body()->layoutObject()); LayoutBlock* frameDiv = toLayoutBlock(frameBody->lastChild()); // This part is copied from the LayoutView test, just to ensure that the // mapped rect is valid before display:none is set on the iframe. childDocument().view()->setScrollOffset(ScrollOffset(0, 47), ProgrammaticScroll); LayoutRect originalRect(4, 60, 20, 80); LayoutRect rect = originalRect; EXPECT_TRUE(frameDiv->mapToVisualRectInAncestorSpace(frameContainer, rect)); EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37)); Element* frameElement = document().getElementById("frame"); frameElement->setInlineStyleProperty(CSSPropertyDisplay, "none"); document().view()->updateAllLifecyclePhases(); rect = originalRect; EXPECT_FALSE(frameDiv->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(rect, LayoutRect()); }
TEST_F(VisualRectMappingTest, ContainerFlippedWritingModeAndOverflowScroll) { setBodyInnerHTML( "<div id='container' style='writing-mode: vertical-rl; position: " "absolute; top: 111px; left: 222px;" " border: solid red; border-width: 10px 20px 30px 40px;" " overflow: scroll; width: 50px; height: 80px'>" " <div id='target' style='box-shadow: 40px 20px black; width: 100px; " "height: 90px'></div>" " <div style='width: 100px; height: 100px'></div>" "</div>"); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); EXPECT_EQ(LayoutUnit(), container->scrollTop()); // The initial scroll offset is to the left-most because of flipped blocks // writing mode. // 150 = total_layout_overflow(100 + 100) - width(50) EXPECT_EQ(LayoutUnit(150), container->scrollLeft()); container->setScrollTop(LayoutUnit(7)); container->setScrollLeft( LayoutUnit(142)); // Scroll to the right by 8 pixels. document().view()->updateAllLifecyclePhases(); LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); LayoutRect targetVisualRect = target->localVisualRect(); // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the // origin) // 140 = width(100) + box_shadow_offset_x(40) // 110 = height(90) + box_shadow_offset_y(20) EXPECT_EQ(LayoutRect(-40, 0, 140, 110), targetVisualRect); LayoutRect rect = targetVisualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect)); // This rect is in physical coordinates of target. EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect); rect = targetVisualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); rect.move(-container->scrolledContentOffset()); // -2 = target_physical_x(100) + container_border_left(40) - scroll_left(142) // 3 = target_y(0) + container_border_top(10) - scroll_top(7) // Rect is clipped by container's overflow clip because of overflow:scroll. EXPECT_EQ(LayoutRect(-2, 3, 140, 110), rect); rect = targetVisualRect; target->flipForWritingMode(rect); EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); // (-2, 3, 140, 100) is first clipped by container's overflow clip, to // (40, 10, 50, 80), then is added by container's offset in LayoutView // (111, 222). // TODO(crbug.com/600039): rect.x() should be 262 (left + border-left), but is // offset // by extra horizontal border-widths because of layout error. EXPECT_EQ(LayoutRect(322, 121, 50, 80), rect); checkPaintInvalidationStateRectMapping(rect, targetVisualRect, *target, layoutView(), layoutView()); LayoutRect containerVisualRect = container->localVisualRect(); // Because container has overflow clip, its visual overflow doesn't include // overflow from children. // 110 = width(50) + border_left_width(40) + border_right_width(20) // 120 = height(80) + border_top_width(10) + border_bottom_width(30) EXPECT_EQ(LayoutRect(0, 0, 110, 120), containerVisualRect); rect = containerVisualRect; container->flipForWritingMode(rect); EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(container, rect)); EXPECT_EQ(LayoutRect(0, 0, 110, 120), rect); rect = containerVisualRect; container->flipForWritingMode(rect); EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(&layoutView(), rect)); // TODO(crbug.com/600039): rect.x() should be 222 (left), but is offset by // extra horizontal // border-widths because of layout error. EXPECT_EQ(LayoutRect(282, 111, 110, 120), rect); checkPaintInvalidationStateRectMapping(rect, containerVisualRect, *container, layoutView(), layoutView()); }
TEST_F(VisualRectMappingTest, ContainerOverflowScroll) { setBodyInnerHTML( "<div id='container' style='position: absolute; top: 111px; left: 222px;" " border: 10px solid red; overflow: scroll; width: 50px; height: " "80px;'>" " <div id='target' style='box-shadow: 40px 20px black; width: 100px; " "height: 90px'></div>" "</div>"); LayoutBlock* container = toLayoutBlock(getLayoutObjectByElementId("container")); EXPECT_EQ(LayoutUnit(), container->scrollTop()); EXPECT_EQ(LayoutUnit(), container->scrollLeft()); container->setScrollTop(LayoutUnit(7)); container->setScrollLeft(LayoutUnit(8)); document().view()->updateAllLifecyclePhases(); LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target")); LayoutRect targetVisualRect = target->localVisualRect(); // 140 = width(100) + box_shadow_offset_x(40) // 110 = height(90) + box_shadow_offset_y(20) EXPECT_EQ(LayoutRect(0, 0, 140, 110), targetVisualRect); LayoutRect rect = targetVisualRect; EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect)); EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect); rect = targetVisualRect; EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect)); rect.move(-container->scrolledContentOffset()); // 2 = target_x(0) + container_border_left(10) - scroll_left(8) // 3 = target_y(0) + container_border_top(10) - scroll_top(7) // Rect is not clipped by container's overflow clip because of // overflow:scroll. EXPECT_EQ(LayoutRect(2, 3, 140, 110), rect); rect = targetVisualRect; EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); // (2, 3, 140, 100) is first clipped by container's overflow clip, to // (10, 10, 50, 80), then is by added container's offset in LayoutView // (111, 222). EXPECT_EQ(LayoutRect(232, 121, 50, 80), rect); checkPaintInvalidationStateRectMapping(rect, targetVisualRect, *target, layoutView(), layoutView()); LayoutRect containerVisualRect = container->localVisualRect(); // Because container has overflow clip, its visual overflow doesn't include // overflow from children. // 70 = width(50) + border_left_width(10) + border_right_width(10) // 100 = height(80) + border_top_width(10) + border_bottom_width(10) EXPECT_EQ(LayoutRect(0, 0, 70, 100), containerVisualRect); rect = containerVisualRect; EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(container, rect)); // Container should not apply overflow clip on its own overflow rect. EXPECT_EQ(LayoutRect(0, 0, 70, 100), rect); rect = containerVisualRect; EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(LayoutRect(222, 111, 70, 100), rect); checkPaintInvalidationStateRectMapping(rect, containerVisualRect, *container, layoutView(), layoutView()); }
bool canPaintBackgroundOntoScrollingContentsLayer(const char* elementId) { PaintLayer* paintLayer = toLayoutBlock(getLayoutObjectByElementId(elementId))->layer(); return paintLayer->canPaintBackgroundOntoScrollingContentsLayer(); }