Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(658)

Unified Diff: Source/core/rendering/RenderLayer.cpp

Issue 23503046: [CSS Blending] Implement mix-blend-mode in software. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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())

Powered by Google App Engine
This is Rietveld 408576698