| Index: Source/core/rendering/RenderLayer.cpp
|
| diff --git a/Source/core/rendering/RenderLayer.cpp b/Source/core/rendering/RenderLayer.cpp
|
| index 6ccee938b4b7e369a31ece346e302db2bdbe3592..b2d250529845cf1ee63b2354a47b5e325573faa7 100644
|
| --- a/Source/core/rendering/RenderLayer.cpp
|
| +++ b/Source/core/rendering/RenderLayer.cpp
|
| @@ -132,6 +132,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_repaintStatus(NeedsNormalRepaint)
|
| , m_visibleContentStatusDirty(true)
|
| @@ -823,9 +825,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 (backing())
|
| backing()->setBlendMode(newBlendMode);
|
| }
|
| @@ -1058,6 +1066,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");
|
| @@ -1117,6 +1152,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;
|
| @@ -1692,18 +1741,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));
|
| @@ -1758,6 +1811,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
|
| @@ -1819,6 +1875,9 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
|
| if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
|
| dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
|
|
|
| + if (oldChild->hasBlendMode() || oldChild->childLayerHasBlendMode())
|
| + dirtyAncestorChainBlendedDescendantStatus();
|
| +
|
| return oldChild;
|
| }
|
|
|
| @@ -3218,6 +3277,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()) {
|
| @@ -3339,7 +3404,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;
|
| @@ -3524,7 +3589,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) {
|
| @@ -3548,7 +3613,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()) {
|
| @@ -5630,12 +5695,12 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
|
|
|
| updateResizerStyle();
|
|
|
| - updateDescendantDependentFlags();
|
| - updateTransform();
|
| -
|
| if (RuntimeEnabledFeatures::cssCompositingEnabled())
|
| updateBlendMode();
|
|
|
| + updateDescendantDependentFlags();
|
| + updateTransform();
|
| +
|
| bool didPaintWithFilters = false;
|
|
|
| if (paintsWithFilters())
|
|
|