TEST_F(DocumentMarkerControllerTest, NodeWillBeRemovedBySetInnerHTML) { setBodyInnerHTML("<b><i>foo</i></b>"); { RefPtrWillBeRawPtr<Element> parent = toElement(document().body()->firstChild()->firstChild()); markNodeContents(parent); EXPECT_EQ(1u, markerController().markers().size()); setBodyInnerHTML(""); } // No more reference to marked node. Heap::collectAllGarbage(); EXPECT_EQ(0u, markerController().markers().size()); }
TEST_P(PaintPropertyTreePrinterTest, SimpleClipTree) { setBodyInnerHTML("hello world"); String clipTreeAsString = clipPropertyTreeAsString(*document().view()); EXPECT_THAT(clipTreeAsString.ascii().data(), testing::MatchesRegex("root .*" " .*Clip \\(.*\\) .*")); }
TEST_F(PaintPropertyTreeBuilderTest, NestedOpacityEffect) { setBodyInnerHTML( "<div id='nodeWithoutOpacity'>" " <div id='childWithOpacity' style='opacity: 0.5'>" " <div id='grandChildWithoutOpacity'>" " <div id='greatGrandChildWithOpacity' style='opacity: 0.2'/>" " </div>" " </div" "</div>"); LayoutObject& nodeWithoutOpacity = *document().getElementById("nodeWithoutOpacity")->layoutObject(); ObjectPaintProperties* nodeWithoutOpacityProperties = nodeWithoutOpacity.objectPaintProperties(); EXPECT_EQ(nullptr, nodeWithoutOpacityProperties); LayoutObject& childWithOpacity = *document().getElementById("childWithOpacity")->layoutObject(); ObjectPaintProperties* childWithOpacityProperties = childWithOpacity.objectPaintProperties(); EXPECT_EQ(0.5f, childWithOpacityProperties->effect()->opacity()); // childWithOpacity is the root effect node. EXPECT_EQ(nullptr, childWithOpacityProperties->effect()->parent()); LayoutObject& grandChildWithoutOpacity = *document().getElementById("grandChildWithoutOpacity")->layoutObject(); EXPECT_EQ(nullptr, grandChildWithoutOpacity.objectPaintProperties()); LayoutObject& greatGrandChildWithOpacity = *document().getElementById("greatGrandChildWithOpacity")->layoutObject(); ObjectPaintProperties* greatGrandChildWithOpacityProperties = greatGrandChildWithOpacity.objectPaintProperties(); EXPECT_EQ(0.2f, greatGrandChildWithOpacityProperties->effect()->opacity()); EXPECT_EQ(childWithOpacityProperties->effect(), greatGrandChildWithOpacityProperties->effect()->parent()); }
TEST_F(LayoutObjectTest, ContainingBlockStaticLayoutObjectShouldBeParent) { setBodyInnerHTML("<foo style='position:static'></foo>"); LayoutObject* bodyLayoutObject = document().body()->layoutObject(); LayoutObject* layoutObject = bodyLayoutObject->slowFirstChild(); EXPECT_EQ(layoutObject->containingBlock(), bodyLayoutObject); }
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(ImageQualityControllerTest, ImageRenderingPixelated) { setBodyInnerHTML("<img src='myimage' style='image-rendering: pixelated'></img>"); LayoutObject* obj = document().body()->firstChild()->layoutObject(); EXPECT_EQ(InterpolationNone, controller()->chooseInterpolationQuality(*obj, nullptr, nullptr, LayoutSize())); }
// TODO(wangxianzhu): Create a version for slimming paint v2 when it supports interest rect TEST_F(TableCellPainterTest, TableCellBackgroundInterestRect) { setBodyInnerHTML( "<style>" " td { width: 200px; height: 200px; border: none; }" " tr { background-color: blue; }" " table { border: none; border-spacing: 0; border-collapse: collapse; }" "</style>" "<table>" " <tr><td id='cell1'></td></tr>" " <tr><td id='cell2'></td></tr>" "</table>"); LayoutView& layoutView = *document().layoutView(); PaintLayer& rootLayer = *layoutView.layer(); LayoutObject& cell1 = *document().getElementById("cell1")->layoutObject(); LayoutObject& cell2 = *document().getElementById("cell2")->layoutObject(); GraphicsContext context(&rootDisplayItemList()); PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 200, 200), GlobalPaintNormalPhase, LayoutSize()); PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases); rootDisplayItemList().commitNewDisplayItems(); EXPECT_DISPLAY_LIST(rootDisplayItemList().displayItems(), 2, TestDisplayItem(layoutView, DisplayItem::BoxDecorationBackground), TestDisplayItem(cell1, DisplayItem::TableCellBackgroundFromRow)); PaintLayerPaintingInfo paintingInfo1(&rootLayer, LayoutRect(0, 300, 200, 200), GlobalPaintNormalPhase, LayoutSize()); PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo1, PaintLayerPaintingCompositingAllPhases); rootDisplayItemList().commitNewDisplayItems(); EXPECT_DISPLAY_LIST(rootDisplayItemList().displayItems(), 2, TestDisplayItem(layoutView, DisplayItem::BoxDecorationBackground), TestDisplayItem(cell2, DisplayItem::TableCellBackgroundFromRow)); }
TEST_F(PrintContextFrameTest, WithScrolledSubframe) { MockCanvas canvas; document().setBaseURLOverride(KURL(ParsedURLString, "http://a.com/")); setBodyInnerHTML("<style>::-webkit-scrollbar { display: none }</style>" "<iframe id='frame' src='http://b.com/' width='500' height='500'" " style='border-width: 5px; margin: 5px; position: absolute; top: 90px; left: 90px'></iframe>"); Document& frameDocument = setupChildIframe("frame", absoluteBlockHtmlForLink(10, 10, 20, 20, "http://invisible.com") + absoluteBlockHtmlForLink(50, 60, 70, 80, "http://partly.visible.com") + absoluteBlockHtmlForLink(150, 160, 170, 180, "http://www.google.com") + absoluteBlockHtmlForLink(250, 260, 270, 280, "http://www.google.com#fragment") + absoluteBlockHtmlForLink(850, 860, 70, 80, "http://another.invisible.com")); frameDocument.domWindow()->scrollTo(100, 100); printSinglePage(canvas); const Vector<MockCanvas::Operation>& operations = canvas.recordedOperations(); ASSERT_EQ(3u, operations.size()); EXPECT_EQ(MockCanvas::DrawRect, operations[0].type); EXPECT_SKRECT_EQ(50, 60, 70, 80, operations[0].rect); // FIXME: the rect should be clipped. EXPECT_EQ(MockCanvas::DrawRect, operations[1].type); EXPECT_SKRECT_EQ(150, 160, 170, 180, operations[1].rect); EXPECT_EQ(MockCanvas::DrawRect, operations[2].type); EXPECT_SKRECT_EQ(250, 260, 270, 280, operations[2].rect); }
TEST_F(PaintPropertyTreeBuilderTest, EffectNodesAcrossSVGHTMLBoundary) { setBodyInnerHTML( "<svg id='svgRootWithOpacity' style='opacity: 0.3;'>" " <foreignObject id='foreignObjectWithOpacity' opacity='0.4'>" " <body>" " <span id='spanWithOpacity' style='opacity: 0.5'/>" " </body>" " </foreignObject>" "</svg>"); LayoutObject& svgRootWithOpacity = *document().getElementById("svgRootWithOpacity")->layoutObject(); ObjectPaintProperties* svgRootWithOpacityProperties = svgRootWithOpacity.objectPaintProperties(); EXPECT_EQ(0.3f, svgRootWithOpacityProperties->effect()->opacity()); EXPECT_EQ(nullptr, svgRootWithOpacityProperties->effect()->parent()); LayoutObject& foreignObjectWithOpacity = *document().getElementById("foreignObjectWithOpacity")->layoutObject(); ObjectPaintProperties* foreignObjectWithOpacityProperties = foreignObjectWithOpacity.objectPaintProperties(); EXPECT_EQ(0.4f, foreignObjectWithOpacityProperties->effect()->opacity()); EXPECT_EQ(svgRootWithOpacityProperties->effect(), foreignObjectWithOpacityProperties->effect()->parent()); LayoutObject& spanWithOpacity = *document().getElementById("spanWithOpacity")->layoutObject(); ObjectPaintProperties* spanWithOpacityProperties = spanWithOpacity.objectPaintProperties(); EXPECT_EQ(0.5f, spanWithOpacityProperties->effect()->opacity()); EXPECT_EQ(foreignObjectWithOpacityProperties->effect(), spanWithOpacityProperties->effect()->parent()); }
TEST_F(PaintPropertyTreeBuilderTest, FixedTransformAncestorAcrossSVGHTMLBoundary) { setBodyInnerHTML( "<style> body { margin: 0px; } </style>" "<svg id='svg' style='transform: translate3d(1px, 2px, 3px);'>" " <g id='container' transform='translate(20 30)'>" " <foreignObject>" " <body>" " <div id='fixed' style='position: fixed; left: 200px; top: 150px;'></div>" " </body>" " </foreignObject>" " </g>" "</svg>"); LayoutObject& svg = *document().getElementById("svg")->layoutObject(); ObjectPaintProperties* svgProperties = svg.objectPaintProperties(); EXPECT_EQ(TransformationMatrix().translate3d(1, 2, 3), svgProperties->transform()->matrix()); LayoutObject& container = *document().getElementById("container")->layoutObject(); ObjectPaintProperties* containerProperties = container.objectPaintProperties(); EXPECT_EQ(TransformationMatrix().translate(20, 30), containerProperties->transform()->matrix()); EXPECT_EQ(svgProperties->transform(), containerProperties->transform()->parent()); Element* fixed = document().getElementById("fixed"); ObjectPaintProperties* fixedProperties = fixed->layoutObject()->objectPaintProperties(); EXPECT_EQ(TransformationMatrix().translate(200, 150), fixedProperties->paintOffsetTranslation()->matrix()); // Ensure the fixed position element is rooted at the nearest transform container. EXPECT_EQ(containerProperties->transform(), fixedProperties->paintOffsetTranslation()->parent()); }
void SetUp() override { RenderingTest::SetUp(); enableCompositing(); setBodyInnerHTML( "<style>" " body {" " margin: 0;" " height: 0;" " }" " ::-webkit-scrollbar { display: none }" " #target {" " width: 50px;" " height: 100px;" " transform-origin: 0 0;" " }" " .border {" " border-width: 20px 10px;" " border-style: solid;" " border-color: red;" " }" " .local-background {" " background-attachment: local;" " overflow: scroll;" " }" " .gradient {" " background-image: linear-gradient(blue, yellow)" " }" "</style>" "<div id='target' class='border'></div>"); }
TEST_P(PaintPropertyTreePrinterTest, SimpleScrollTree) { setBodyInnerHTML("<div style='height: 4000px;'>hello world</div>"); String scrollTreeAsString = scrollPropertyTreeAsString(*document().view()); EXPECT_THAT(scrollTreeAsString.ascii().data(), testing::MatchesRegex("root .*" " Scroll \\(.*\\) .*")); }
TEST_P(PaintPropertyTreePrinterTest, SimpleEffectTree) { setBodyInnerHTML("<div style='opacity: 0.9;'>hello world</div>"); String effectTreeAsString = effectPropertyTreeAsString(*document().view()); EXPECT_THAT(effectTreeAsString.ascii().data(), testing::MatchesRegex("root .*" " Effect \\(LayoutBlockFlow DIV\\) .*")); }
TEST_F(ImageQualityControllerTest, DontKickTheAnimationTimerWhenPaintingAtTheSameSize) { MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::highQualityRepaintTimerFired); controller()->setTimer(mockTimer); setBodyInnerHTML("<img src='myimage'></img>"); LayoutImage* img = toLayoutImage(document().body()->firstChild()->layoutObject()); RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); // Paint once. This will kick off a timer to see if we resize it during that timer's execution. EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img, testImage.get(), testImage.get(), LayoutSize(2, 2))); // Go into low-quality mode now that the size changed. EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, testImage.get(), testImage.get(), LayoutSize(3, 3))); // Stay in low-quality mode since the size changed again. EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, testImage.get(), testImage.get(), LayoutSize(4, 4))); mockTimer->stop(); EXPECT_FALSE(mockTimer->isActive()); // Painted at the same size, so even though timer is still executing, don't go to low quality. EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, testImage.get(), testImage.get(), LayoutSize(4, 4))); // Check that the timer was not kicked. It should not have been, since the image was painted at the same size as last time. EXPECT_FALSE(mockTimer->isActive()); }
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(ImageQualityControllerTest, RegularImage) { setBodyInnerHTML("<img src='myimage'></img>"); LayoutObject* obj = document().body()->firstChild()->layoutObject(); EXPECT_EQ(InterpolationDefault, controller()->chooseInterpolationQuality(*obj, nullptr, nullptr, LayoutSize())); }
TEST_F(PrintContextTest, LinkTargetComplex) { MockCanvas canvas; setBodyInnerHTML("<div>" // Link in anonymous block before a block. + inlineHtmlForLink("http://www.google.com", "<img style='width: 111; height: 10'>") + "<div> " + inlineHtmlForLink("http://www.google1.com", "<img style='width: 122; height: 20'>") + "</div>" // Link in anonymous block after a block, containing another block + inlineHtmlForLink("http://www.google2.com", "<div style='width:133; height: 30'>BLOCK</div>") // Link embedded in inlines + "<span><b><i><img style='width: 40px; height: 40px'><br>" + inlineHtmlForLink("http://www.google3.com", "<img style='width: 144px; height: 40px'>") + "</i></b></span>" // Link embedded in relatively positioned inline + "<span style='position: relative; top: 50px; left: 50px'><b><i><img style='width: 1px; height: 40px'><br>" + inlineHtmlForLink("http://www.google3.com", "<img style='width: 155px; height: 50px'>") + "</i></b></span>" + "</div>"); printSinglePage(canvas); const Vector<MockCanvas::Operation>& operations = canvas.recordedOperations(); ASSERT_EQ(4u, operations.size()); EXPECT_EQ(MockCanvas::DrawRect, operations[0].type); EXPECT_SKRECT_EQ(0, 0, 111, 10, operations[0].rect); EXPECT_EQ(MockCanvas::DrawRect, operations[1].type); EXPECT_SKRECT_EQ(0, 10, 122, 20, operations[1].rect); EXPECT_EQ(MockCanvas::DrawRect, operations[2].type); EXPECT_SKRECT_EQ(0, 100, 144, 40, operations[2].rect); EXPECT_EQ(MockCanvas::DrawRect, operations[3].type); EXPECT_SKRECT_EQ(50, 190, 155, 50, operations[3].rect); }
TEST_F(TextAutosizerTest, DISABLED_NestedTextSizeAdjust) { setBodyInnerHTML( "<meta name='viewport' content='width=800'>" "<style>" " html { font-size: 16px; }" " body { width: 800px; margin: 0; overflow-y: hidden; }" "</style>" "<div id='textSizeAdjustA' style='text-size-adjust: 47%;'>" " Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor" " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud" " exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure" " dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur." " Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt" " mollit anim id est laborum." " <div id='textSizeAdjustB' style='text-size-adjust: 53%;'>" " Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor" " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud" " exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute" " irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla" " pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui" " officia deserunt mollit anim id est laborum." " </div>" "</div>"); LayoutObject* textSizeAdjustA = document().getElementById("textSizeAdjustA")->layoutObject(); EXPECT_FLOAT_EQ(16.f, textSizeAdjustA->style()->specifiedFontSize()); // 16px * 47% = 7.52 EXPECT_FLOAT_EQ(7.52f, textSizeAdjustA->style()->computedFontSize()); LayoutObject* textSizeAdjustB = document().getElementById("textSizeAdjustB")->layoutObject(); EXPECT_FLOAT_EQ(16.f, textSizeAdjustB->style()->specifiedFontSize()); // 16px * 53% = 8.48 EXPECT_FLOAT_EQ(8.48f, textSizeAdjustB->style()->computedFontSize()); }
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(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(PaintLayerScrollableAreaTest, OpaqueLayersPromotedOnStyleChange) { RuntimeEnabledFeatures::setCompositeOpaqueScrollersEnabled(true); setBodyInnerHTML( "<style>" "#scroller { overflow: scroll; height: 200px; width: 200px; background: " "rgba(255,255,255,0.5) local content-box; }" "#scrolled { height: 300px; }" "</style>" "<div id=\"scroller\"><div id=\"scrolled\"></div></div>"); document().view()->updateAllLifecyclePhases(); EXPECT_TRUE(RuntimeEnabledFeatures::compositeOpaqueScrollersEnabled()); Element* scroller = document().getElementById("scroller"); PaintLayer* paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer(); ASSERT_TRUE(paintLayer); EXPECT_FALSE(paintLayer->needsCompositedScrolling()); // Change the background to transparent scroller->setAttribute(HTMLNames::styleAttr, "background: white local content-box;"); document().view()->updateAllLifecyclePhases(); paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer(); ASSERT_TRUE(paintLayer); EXPECT_TRUE(paintLayer->needsCompositedScrolling()); EXPECT_TRUE(paintLayer->graphicsLayerBacking()); ASSERT_TRUE(paintLayer->graphicsLayerBackingForScrolling()); EXPECT_TRUE(paintLayer->graphicsLayerBackingForScrolling()->contentsOpaque()); }
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(LayoutObjectTest, DisplayInlineBlockCreateObject) { setBodyInnerHTML("<foo style='display:inline-block'></foo>"); LayoutObject* layoutObject = document().body()->firstChild()->layoutObject(); EXPECT_NE(nullptr, layoutObject); EXPECT_TRUE(layoutObject->isLayoutBlockFlow()); EXPECT_TRUE(layoutObject->isInline()); }
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(LayoutObjectTest, ContainingBlockAbsoluteLayoutObjectShouldBeLayoutView) { setBodyInnerHTML("<foo style='position:absolute'></foo>"); LayoutObject* layoutObject = document().body()->layoutObject()->slowFirstChild(); EXPECT_EQ(layoutObject->containingBlock(), layoutView()); }
TEST_F(LayoutObjectTest, ContainingBlockAbsoluteLayoutObjectShouldBeNonStaticallyPositionedBlockAncestor) { setBodyInnerHTML("<div style='position:relative'><bar style='position:absolute'></bar></div>"); LayoutObject* containingBlocklayoutObject = document().body()->layoutObject()->slowFirstChild(); LayoutObject* layoutObject = containingBlocklayoutObject->slowFirstChild(); EXPECT_EQ(layoutObject->containingBlock(), containingBlocklayoutObject); }
TEST_F(ImageQualityControllerTest, LowQualityFilterForLiveResize) { MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::highQualityRepaintTimerFired); controller()->setTimer(mockTimer); setBodyInnerHTML("<img src='myimage'></img>"); LayoutImage* img = toLayoutImage(document().body()->firstChild()->layoutObject()); RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); // Start a resize document().frame()->view()->willStartLiveResize(); EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, testImage.get(), testImage.get(), LayoutSize(2, 2))); document().frame()->view()->willEndLiveResize(); // End of live resize, but timer has not fired. Therefore paint at non-low quality. EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img, testImage.get(), testImage.get(), LayoutSize(3, 3))); // Start another resize document().frame()->view()->willStartLiveResize(); EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, testImage.get(), testImage.get(), LayoutSize(3, 3))); // While still in resize, expire the timer. document().frame()->view()->willEndLiveResize(); mockTimer->fire(); // End of live resize, and timer has fired. Therefore paint at non-low quality, even though the size has changed. EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img, testImage.get(), testImage.get(), LayoutSize(4, 4))); }
TEST_F(PaintPropertyTreeBuilderTest, TransformNodeDoesNotAffectEffectNodes) { setBodyInnerHTML( "<div id='nodeWithOpacity' style='opacity: 0.6'>" " <div id='childWithTransform' style='transform: translate3d(10px, 10px, 0px);'>" " <div id='grandChildWithOpacity' style='opacity: 0.4'/>" " </div" "</div>"); LayoutObject& nodeWithOpacity = *document().getElementById("nodeWithOpacity")->layoutObject(); ObjectPaintProperties* nodeWithOpacityProperties = nodeWithOpacity.objectPaintProperties(); EXPECT_EQ(0.6f, nodeWithOpacityProperties->effect()->opacity()); EXPECT_EQ(nullptr, nodeWithOpacityProperties->effect()->parent()); EXPECT_EQ(nullptr, nodeWithOpacityProperties->transform()); LayoutObject& childWithTransform = *document().getElementById("childWithTransform")->layoutObject(); ObjectPaintProperties* childWithTransformProperties = childWithTransform.objectPaintProperties(); EXPECT_EQ(nullptr, childWithTransformProperties->effect()); EXPECT_EQ(TransformationMatrix().translate(10, 10), childWithTransformProperties->transform()->matrix()); LayoutObject& grandChildWithOpacity = *document().getElementById("grandChildWithOpacity")->layoutObject(); ObjectPaintProperties* grandChildWithOpacityProperties = grandChildWithOpacity.objectPaintProperties(); EXPECT_EQ(0.4f, grandChildWithOpacityProperties->effect()->opacity()); EXPECT_EQ(nodeWithOpacityProperties->effect(), grandChildWithOpacityProperties->effect()->parent()); EXPECT_EQ(nullptr, grandChildWithOpacityProperties->transform()); }
TEST_P(PrePaintTreeWalkTest, PropertyTreesRebuiltWithBorderInvalidation) { setBodyInnerHTML( "<style>" " body { margin: 0; }" " #transformed { transform: translate(100px, 100px); }" " .border { border: 10px solid black; }" "</style>" "<div id='transformed'></div>"); auto* transformedElement = document().getElementById("transformed"); const auto* transformedProperties = transformedElement->layoutObject()->paintProperties(); EXPECT_EQ(TransformationMatrix().translate(100, 100), transformedProperties->transform()->matrix()); // Artifically change the transform node. const_cast<ObjectPaintProperties*>(transformedProperties)->clearTransform(); EXPECT_EQ(nullptr, transformedProperties->transform()); // Cause a paint invalidation. transformedElement->setAttribute(HTMLNames::classAttr, "border"); document().view()->updateAllLifecyclePhases(); // Should have changed back. EXPECT_EQ(TransformationMatrix().translate(100, 100), transformedProperties->transform()->matrix()); }