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 that opacity applied to the scroller or an ancestor will cause the // scrolling contents layer to not be promoted. TEST_F(PaintLayerScrollableAreaTest, OnlyOpaqueLayersPromoted) { ScopedCompositeOpaqueScrollersForTest compositeOpaqueScrollers(true); setBodyInnerHTML( "<style>" "#scroller { overflow: scroll; height: 200px; width: 200px; background: " "white local content-box; }" "#scrolled { height: 300px; }" "</style>" "<div id=\"parent\">" " <div id=\"scroller\"><div id=\"scrolled\"></div></div>" "</div>"); document().view()->updateAllLifecyclePhases(); EXPECT_TRUE(RuntimeEnabledFeatures::compositeOpaqueScrollersEnabled()); Element* parent = document().getElementById("parent"); Element* scroller = document().getElementById("scroller"); PaintLayer* 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()); // Change the parent to be partially translucent. parent->setAttribute(HTMLNames::styleAttr, "opacity: 0.5;"); document().view()->updateAllLifecyclePhases(); paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer(); ASSERT_TRUE(paintLayer); EXPECT_FALSE(paintLayer->needsCompositedScrolling()); EXPECT_FALSE(paintLayer->graphicsLayerBacking()); // Change the parent to be opaque again. parent->setAttribute(HTMLNames::styleAttr, "opacity: 1;"); 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()); // Make the scroller translucent. scroller->setAttribute(HTMLNames::styleAttr, "opacity: 0.5"); document().view()->updateAllLifecyclePhases(); paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer(); ASSERT_TRUE(paintLayer); EXPECT_FALSE(paintLayer->needsCompositedScrolling()); EXPECT_FALSE(paintLayer->graphicsLayerBacking()); }
ClipPathHelper(GraphicsContext* context, const PaintLayer& paintLayer, PaintLayerPaintingInfo& paintingInfo, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed, const LayoutPoint& offsetFromRoot, PaintLayerFlags paintFlags) : m_resourceClipper(0), m_paintLayer(paintLayer), m_context(context) { const ComputedStyle& style = paintLayer.layoutObject()->styleRef(); // Clip-path, like border radius, must not be applied to the contents of a composited-scrolling container. // It must, however, still be applied to the mask layer, so that the compositor can properly mask the // scrolling contents and scrollbars. if (!paintLayer.layoutObject()->hasClipPath() || (paintLayer.needsCompositedScrolling() && !(paintFlags & PaintLayerPaintingChildClippingMaskPhase))) return; m_clipperState = SVGClipPainter::ClipperNotApplied; paintingInfo.ancestorHasClipPathClipping = true; ASSERT(style.clipPath()); if (style.clipPath()->type() == ClipPathOperation::SHAPE) { ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style.clipPath()); if (clipPath->isValid()) { if (!rootRelativeBoundsComputed) { rootRelativeBounds = paintLayer.physicalBoundingBoxIncludingReflectionAndStackingChildren(offsetFromRoot); rootRelativeBoundsComputed = true; } m_clipPathRecorder.emplace(*context, *paintLayer.layoutObject(), clipPath->path(FloatRect(rootRelativeBounds))); } } else if (style.clipPath()->type() == ClipPathOperation::REFERENCE) { ReferenceClipPathOperation* referenceClipPathOperation = toReferenceClipPathOperation(style.clipPath()); Document& document = paintLayer.layoutObject()->document(); // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405) Element* element = document.getElementById(referenceClipPathOperation->fragment()); if (isSVGClipPathElement(element) && element->layoutObject()) { if (!rootRelativeBoundsComputed) { rootRelativeBounds = paintLayer.physicalBoundingBoxIncludingReflectionAndStackingChildren(offsetFromRoot); rootRelativeBoundsComputed = true; } m_resourceClipper = toLayoutSVGResourceClipper(toLayoutSVGResourceContainer(element->layoutObject())); if (!SVGClipPainter(*m_resourceClipper).prepareEffect(*paintLayer.layoutObject(), FloatRect(rootRelativeBounds), FloatRect(rootRelativeBounds), context, m_clipperState)) { // No need to post-apply the clipper if this failed. m_resourceClipper = 0; } } } }
TEST_F(PaintLayerScrollableAreaTest, TransparentLayersNotPromoted) { RuntimeEnabledFeatures::setCompositeOpaqueScrollersEnabled(true); setBodyInnerHTML( "<style>" "#scroller { overflow: scroll; height: 200px; width: 200px; background: " "rgba(0, 255, 0, 0.5) local content-box; border: 10px solid rgba(0, 255, " "0, 0.5); }" "#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()); EXPECT_FALSE(paintLayer->graphicsLayerBacking()); EXPECT_FALSE(paintLayer->graphicsLayerBackingForScrolling()); }
void LayerClipRecorder::collectRoundedRectClips(PaintLayer& paintLayer, const PaintLayerPaintingInfo& localPaintingInfo, GraphicsContext& context, const LayoutPoint& fragmentOffset, PaintLayerFlags paintFlags, BorderRadiusClippingRule rule, Vector<FloatRoundedRect>& roundedRectClips) { // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our // containing block chain so we check that also. for (PaintLayer* layer = rule == IncludeSelfForBorderRadius ? &paintLayer : paintLayer.parent(); layer; layer = layer->parent()) { // Composited scrolling layers handle border-radius clip in the compositor via a mask layer. We do not // want to apply a border-radius clip to the layer contents itself, because that would require re-rastering // every frame to update the clip. We only want to make sure that the mask layer is properly clipped so // that it can in turn clip the scrolled contents in the compositor. if (layer->needsCompositedScrolling() && !(paintFlags & PaintLayerPaintingChildClippingMaskPhase)) break; if (layer->layoutObject()->hasOverflowClip() && layer->layoutObject()->style()->hasBorderRadius() && inContainingBlockChain(&paintLayer, layer)) { LayoutPoint delta(fragmentOffset); layer->convertToLayerCoords(localPaintingInfo.rootLayer, delta); roundedRectClips.append(layer->layoutObject()->style()->getRoundedInnerBorderFor(LayoutRect(delta, LayoutSize(layer->size())))); } if (layer == localPaintingInfo.rootLayer) break; } }