Index: Source/core/rendering/RenderLayer.cpp |
diff --git a/Source/core/rendering/RenderLayer.cpp b/Source/core/rendering/RenderLayer.cpp |
index 6ccee938b4b7e369a31ece346e302db2bdbe3592..91f107cd2f7765b64c5aecf51de65904de685cdb 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,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; |
Julien - ping for review
2013/10/03 21:38:28
Normally we bail out if m_childLayerHasBlendMode b
mitica
2013/10/07 10:56:03
Good point, I've modified this function to break a
|
+ } |
+ m_childLayerHasBlendModeStatusDirty = false; |
+ } |
+ |
if (m_visibleContentStatusDirty) { |
if (renderer()->style()->visibility() == VISIBLE) |
m_hasVisibleContent = true; |
@@ -1692,18 +1739,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 +1809,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 +1873,9 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) |
if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant()) |
dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); |
+ if (oldChild->hasBlendMode() || oldChild->childLayerHasBlendMode()) |
+ dirtyAncestorChainBlendedDescendantStatus(); |
+ |
return oldChild; |
} |
@@ -3218,6 +3275,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 +3402,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 +3587,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 +3611,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 +5693,12 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) |
updateResizerStyle(); |
- updateDescendantDependentFlags(); |
- updateTransform(); |
- |
if (RuntimeEnabledFeatures::cssCompositingEnabled()) |
updateBlendMode(); |
+ updateDescendantDependentFlags(); |
+ updateTransform(); |
+ |
bool didPaintWithFilters = false; |
if (paintsWithFilters()) |