| Index: Source/core/rendering/RenderLayer.cpp
|
| diff --git a/Source/core/rendering/RenderLayer.cpp b/Source/core/rendering/RenderLayer.cpp
|
| index 3db81e33e92bb8b428490476965e92164f5d84e0..1feec46b424d2956b68ab716aee7ee2903ef5b06 100644
|
| --- a/Source/core/rendering/RenderLayer.cpp
|
| +++ b/Source/core/rendering/RenderLayer.cpp
|
| @@ -121,6 +121,8 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer)
|
| , m_canBePromotedToStackingContainerDirty(true)
|
| , m_isRootLayer(renderer->isRenderView())
|
| , m_usedTransparency(false)
|
| + , m_childLayerHasBlendMode(false)
|
| + , m_childLayerHasBlendModeStatusDirty(false)
|
| , m_paintingInsideReflection(false)
|
| , m_visibleContentStatusDirty(true)
|
| , m_hasVisibleContent(false)
|
| @@ -725,9 +727,15 @@ void RenderLayer::updateBlendMode()
|
| if (!RuntimeEnabledFeatures::cssCompositingEnabled())
|
| return;
|
|
|
| + bool hadBlendMode = m_blendMode != BlendModeNormal;
|
| BlendMode newBlendMode = renderer()->style()->blendMode();
|
| if (newBlendMode != m_blendMode) {
|
| m_blendMode = newBlendMode;
|
| +
|
| + // Only update the flag if a blend mode is set or unset.
|
| + if (!hadBlendMode || !hasBlendMode())
|
| + dirtyAncestorChainBlendedDescendantStatus();
|
| +
|
| if (compositedLayerMapping())
|
| compositedLayerMapping()->setBlendMode(newBlendMode);
|
| }
|
| @@ -960,6 +968,33 @@ void RenderLayer::setAncestorChainHasVisibleDescendant()
|
| }
|
| }
|
|
|
| +void RenderLayer::dirtyAncestorChainBlendedDescendantStatus()
|
| +{
|
| + for (RenderLayer* layer = this; layer; layer = layer->parent()) {
|
| + if (layer->m_childLayerHasBlendModeStatusDirty)
|
| + break;
|
| +
|
| + layer->m_childLayerHasBlendModeStatusDirty = true;
|
| +
|
| + if (layer->isStackingContext())
|
| + break;
|
| + }
|
| +}
|
| +
|
| +void RenderLayer::setAncestorChainBlendedDescendant()
|
| +{
|
| + for (RenderLayer* layer = this; layer; layer = layer->parent()) {
|
| + if (!layer->m_childLayerHasBlendModeStatusDirty && layer->childLayerHasBlendMode())
|
| + break;
|
| +
|
| + layer->m_childLayerHasBlendMode = true;
|
| + layer->m_childLayerHasBlendModeStatusDirty = false;
|
| +
|
| + if (layer->isStackingContext())
|
| + break;
|
| + }
|
| +}
|
| +
|
| void RenderLayer::updateHasUnclippedDescendant()
|
| {
|
| TRACE_EVENT0("blink_rendering", "RenderLayer::updateHasUnclippedDescendant");
|
| @@ -1019,6 +1054,20 @@ void RenderLayer::updateDescendantDependentFlags()
|
| m_hasOutOfFlowPositionedDescendantDirty = false;
|
| }
|
|
|
| + if (m_childLayerHasBlendModeStatusDirty) {
|
| + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
|
| + if (!child->isStackingContext())
|
| + child->updateDescendantDependentFlags();
|
| +
|
| + bool childLayerHasBlendMode = child->hasBlendMode() || (child->m_childLayerHasBlendMode && !child->isStackingContext());
|
| + m_childLayerHasBlendMode |= childLayerHasBlendMode;
|
| +
|
| + if (m_childLayerHasBlendMode)
|
| + break;
|
| + }
|
| + m_childLayerHasBlendModeStatusDirty = false;
|
| + }
|
| +
|
| if (m_visibleContentStatusDirty) {
|
| if (renderer()->style()->visibility() == VISIBLE)
|
| m_hasVisibleContent = true;
|
| @@ -1547,18 +1596,22 @@ LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const Layou
|
|
|
| void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
|
| {
|
| - if (context->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
|
| + bool createTransparencyLayerForBlendMode = isStackingContext() && m_childLayerHasBlendMode;
|
| + if (context->paintingDisabled() || ((paintsWithTransparency(paintBehavior) || hasBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency))
|
| return;
|
|
|
| RenderLayer* ancestor = transparentPaintingAncestor();
|
| if (ancestor)
|
| ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
|
|
|
| - if (paintsWithTransparency(paintBehavior)) {
|
| + if (paintsWithTransparency(paintBehavior) || hasBlendMode() || createTransparencyLayerForBlendMode) {
|
| m_usedTransparency = true;
|
| context->save();
|
| LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior);
|
| context->clip(clipRect);
|
| + if (hasBlendMode())
|
| + context->setCompositeOperation(context->compositeOperation(), m_blendMode);
|
| +
|
| context->beginTransparencyLayer(renderer()->opacity());
|
| #ifdef REVEAL_TRANSPARENCY_LAYERS
|
| context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
|
| @@ -1613,6 +1666,9 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
|
| if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
|
| setAncestorChainHasSelfPaintingLayerDescendant();
|
|
|
| + if (child->hasBlendMode() || child->childLayerHasBlendMode())
|
| + setAncestorChainBlendedDescendant();
|
| +
|
| if (subtreeContainsOutOfFlowPositionedLayer(child)) {
|
| // Now that the out of flow positioned descendant is in the tree, we
|
| // need to tell the compositor to reevaluate the compositing
|
| @@ -1671,6 +1727,9 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
|
| if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
|
| dirtyAncestorChainVisibleDescendantStatus();
|
|
|
| + if (oldChild->hasBlendMode() || oldChild->childLayerHasBlendMode())
|
| + dirtyAncestorChainBlendedDescendantStatus();
|
| +
|
| if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
|
| dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
|
|
|
| @@ -2689,6 +2748,12 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
|
| }
|
| }
|
|
|
| + // Blending operations must be performed only with the nearest ancestor stacking context.
|
| + bool createTransparencyLayerForBlendMode = isStackingContext() && m_childLayerHasBlendMode;
|
| +
|
| + if (createTransparencyLayerForBlendMode)
|
| + beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
|
| +
|
| LayerPaintingInfo localPaintingInfo(paintingInfo);
|
| FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters());
|
| if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) {
|
| @@ -2810,7 +2875,7 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
|
| }
|
|
|
| // End our transparency layer
|
| - if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
|
| + if ((haveTransparency || hasBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency && !m_paintingInsideReflection) {
|
| context->endLayer();
|
| context->restore();
|
| m_usedTransparency = false;
|
| @@ -2995,7 +3060,7 @@ void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragmen
|
| continue;
|
|
|
| // Begin transparency layers lazily now that we know we have to paint something.
|
| - if (haveTransparency)
|
| + if (haveTransparency || hasBlendMode())
|
| beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior);
|
|
|
| if (localPaintingInfo.clipToDirtyRect) {
|
| @@ -3019,7 +3084,7 @@ void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragmen
|
| RenderObject* paintingRootForRenderer, bool selectionOnly, bool forceBlackText)
|
| {
|
| // Begin transparency if we have something to paint.
|
| - if (haveTransparency) {
|
| + if (haveTransparency || hasBlendMode()) {
|
| for (size_t i = 0; i < layerFragments.size(); ++i) {
|
| const LayerFragment& fragment = layerFragments.at(i);
|
| if (fragment.shouldPaintContent && !fragment.foregroundRect.isEmpty()) {
|
| @@ -5074,12 +5139,12 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
|
| updateReflectionStyle();
|
| }
|
|
|
| - updateDescendantDependentFlags();
|
| - updateTransform();
|
| -
|
| if (RuntimeEnabledFeatures::cssCompositingEnabled())
|
| updateBlendMode();
|
|
|
| + updateDescendantDependentFlags();
|
| + updateTransform();
|
| +
|
| bool didPaintWithFilters = false;
|
|
|
| if (paintsWithFilters())
|
|
|