Chromium Code Reviews| Index: Source/core/rendering/RenderLayer.cpp |
| diff --git a/Source/core/rendering/RenderLayer.cpp b/Source/core/rendering/RenderLayer.cpp |
| index 6ccee938b4b7e369a31ece346e302db2bdbe3592..e9a2aad4bd5a77a48351245c9393cd8881fb6ae5 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,14 @@ void RenderLayer::updateBlendMode() |
| if (!RuntimeEnabledFeatures::cssCompositingEnabled()) |
| return; |
| + bool hadBlendMode = m_blendMode != BlendModeNormal; |
|
Julien - ping for review
2013/09/30 17:59:11
Unused variable.
|
| + |
| BlendMode newBlendMode = renderer()->style()->blendMode(); |
| if (newBlendMode != m_blendMode) { |
| m_blendMode = newBlendMode; |
| + |
| + setAncestorChainBlendedDescendant(); |
|
Julien - ping for review
2013/09/30 17:59:11
I don't think this logic is right: you should only
mitica
2013/10/01 13:14:37
You are right, I missed this. The new approach wil
|
| + |
| if (backing()) |
| backing()->setBlendMode(newBlendMode); |
| } |
| @@ -1058,6 +1065,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->m_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 +1151,18 @@ void RenderLayer::updateDescendantDependentFlags() |
| m_hasOutOfFlowPositionedDescendantDirty = false; |
| } |
| + if (m_childLayerHasBlendModeStatusDirty) { |
| + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { |
| + child->updateDescendantDependentFlags(); |
| + if (child->hasBlendMode() || child->isStackingContext()) |
| + break; |
| + |
| + bool childLayerHasBlendMode = child->hasBlendMode() || child->m_childLayerHasBlendMode; |
| + m_childLayerHasBlendMode |= childLayerHasBlendMode; |
| + } |
| + m_childLayerHasBlendModeStatusDirty = false; |
| + } |
| + |
| if (m_visibleContentStatusDirty) { |
| if (renderer()->style()->visibility() == VISIBLE) |
| m_hasVisibleContent = true; |
| @@ -1692,18 +1738,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 +1808,9 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) |
| if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant()) |
| setAncestorChainHasSelfPaintingLayerDescendant(); |
| + if (child->hasBlendMode() || child->m_childLayerHasBlendMode) |
|
Julien - ping for review
2013/09/30 17:59:11
You can potentially check a dirty value here. You
mitica
2013/10/01 13:14:37
Indeed, thanks for pointing this out, I'll add the
|
| + 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 +1872,9 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) |
| if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant()) |
| dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); |
| + if (oldChild->hasBlendMode() || oldChild->m_childLayerHasBlendMode) |
|
Julien - ping for review
2013/09/30 17:59:11
Ditto.
|
| + dirtyAncestorChainBlendedDescendantStatus(); |
| + |
| return oldChild; |
| } |
| @@ -3218,6 +3274,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 +3401,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 +3586,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 +3610,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()) { |