Commit bdc8576b authored by trchen's avatar trchen Committed by Commit bot

[SPv2] Add CSS mix-blend-mode support

This CL adds blendMode field to EffectPaintPropertyNode, upgrades
PaintPropertyTreeBuilder to create effect nodes if CSS mix-blend-mode is
applied to an element and ensure propery isolation on the parent, and adds
corresponding conversion in PaintArtifactCompositor.

BUG=609937
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2

Review-Url: https://codereview.chromium.org/2564193002
Cr-Commit-Position: refs/heads/master@{#438775}
parent f341ad0c
...@@ -14,6 +14,7 @@ Bug(none) css-parser/ [ Skip ] ...@@ -14,6 +14,7 @@ Bug(none) css-parser/ [ Skip ]
Bug(none) css1/ [ Skip ] Bug(none) css1/ [ Skip ]
Bug(none) css2.1/ [ Skip ] Bug(none) css2.1/ [ Skip ]
Bug(none) css3/ [ Skip ] Bug(none) css3/ [ Skip ]
Bug(none) css3/blending [ Pass ]
Bug(none) cssom/ [ Skip ] Bug(none) cssom/ [ Skip ]
Bug(none) csspaint/ [ Skip ] Bug(none) csspaint/ [ Skip ]
Bug(none) custom-elements/ [ Skip ] Bug(none) custom-elements/ [ Skip ]
...@@ -2160,6 +2161,44 @@ Bug(none) fast/overflow/003.xml [ Failure ] ...@@ -2160,6 +2161,44 @@ Bug(none) fast/overflow/003.xml [ Failure ]
Bug(none) fast/overflow/overflow-float-stacking.html [ Failure ] Bug(none) fast/overflow/overflow-float-stacking.html [ Failure ]
Bug(none) fast/overflow/overflow-stacking.html [ Failure ] Bug(none) fast/overflow/overflow-stacking.html [ Failure ]
Bug(none) css3/blending/background-blend-mode-overlapping-accelerated-elements.html [ Failure ]
Bug(none) css3/blending/effect-background-blend-mode-stacking.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-2nd-stacking-context-composited.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-composited-layers.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-composited-reason-children.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-has-ancestor-clipping-layer.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-isolation-2-stacking-contexts.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-isolation-layer.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-isolation-remove.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-multiply.html [ Failure ]
Bug(none) css3/blending/mix-blend-mode-with-masking.html [ Failure ]
Bug(none) css3/blending/svg-blend-color-burn.html [ Failure ]
Bug(none) css3/blending/svg-blend-color-dodge.html [ Failure ]
Bug(none) css3/blending/svg-blend-color.html [ Failure ]
Bug(none) css3/blending/svg-blend-darken.html [ Failure ]
Bug(none) css3/blending/svg-blend-difference.html [ Failure ]
Bug(none) css3/blending/svg-blend-exclusion.html [ Failure ]
Bug(none) css3/blending/svg-blend-hard-light.html [ Failure ]
Bug(none) css3/blending/svg-blend-hue.html [ Failure ]
Bug(none) css3/blending/svg-blend-layer-mask.html [ Failure ]
Bug(none) css3/blending/svg-blend-lighten.html [ Failure ]
Bug(none) css3/blending/svg-blend-luminosity.html [ Failure ]
Bug(none) css3/blending/svg-blend-multiply-alpha.html [ Failure ]
Bug(none) css3/blending/svg-blend-multiply.html [ Failure ]
Bug(none) css3/blending/svg-blend-overlapping-elements.html [ Failure ]
Bug(none) css3/blending/svg-blend-overlay.html [ Failure ]
Bug(none) css3/blending/svg-blend-saturation.html [ Failure ]
Bug(none) css3/blending/svg-blend-screen.html [ Failure ]
Bug(none) css3/blending/svg-blend-soft-light.html [ Failure ]
Bug(none) css3/blending/svg-isolation-foreign-no-isolation.html [ Failure ]
# Failures due to rounding differences
crbug.com/589265 css3/blending/mix-blend-mode-isolated-group-1.html [ Failure ]
crbug.com/589265 css3/blending/mix-blend-mode-isolated-group-3.html [ Failure ]
# Failures due to frame scrollbars not painted
crbug.com/589279 css3/blending/background-blend-mode-data-uri-svg-image.html [ Failure ]
# Notes about rebaselined tests: # Notes about rebaselined tests:
# #
# Rebaselined for small pixel differences. # Rebaselined for small pixel differences.
......
...@@ -150,8 +150,11 @@ void LayoutSVGContainer::descendantIsolationRequirementsChanged( ...@@ -150,8 +150,11 @@ void LayoutSVGContainer::descendantIsolationRequirementsChanged(
m_hasNonIsolatedBlendingDescendantsDirty = true; m_hasNonIsolatedBlendingDescendantsDirty = true;
break; break;
} }
if (SVGLayoutSupport::willIsolateBlendingDescendantsForObject(this)) if (SVGLayoutSupport::willIsolateBlendingDescendantsForObject(this)) {
if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled())
setNeedsPaintPropertyUpdate();
return; return;
}
if (parent()) if (parent())
parent()->descendantIsolationRequirementsChanged(state); parent()->descendantIsolationRequirementsChanged(state);
} }
......
...@@ -305,6 +305,8 @@ void LayoutSVGRoot::descendantIsolationRequirementsChanged( ...@@ -305,6 +305,8 @@ void LayoutSVGRoot::descendantIsolationRequirementsChanged(
m_hasNonIsolatedBlendingDescendantsDirty = true; m_hasNonIsolatedBlendingDescendantsDirty = true;
break; break;
} }
if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled())
setNeedsPaintPropertyUpdate();
} }
void LayoutSVGRoot::insertedIntoTree() { void LayoutSVGRoot::insertedIntoTree() {
......
...@@ -699,6 +699,8 @@ void PaintLayer::updateScrollingStateAfterCompositingChange() { ...@@ -699,6 +699,8 @@ void PaintLayer::updateScrollingStateAfterCompositingChange() {
void PaintLayer::updateDescendantDependentFlags() { void PaintLayer::updateDescendantDependentFlags() {
if (m_needsDescendantDependentFlagsUpdate) { if (m_needsDescendantDependentFlagsUpdate) {
bool oldHasNonIsolatedDescendantWithBlendMode =
m_hasNonIsolatedDescendantWithBlendMode;
m_hasVisibleDescendant = false; m_hasVisibleDescendant = false;
m_hasNonIsolatedDescendantWithBlendMode = false; m_hasNonIsolatedDescendantWithBlendMode = false;
m_hasDescendantWithClipPath = false; m_hasDescendantWithClipPath = false;
...@@ -727,6 +729,10 @@ void PaintLayer::updateDescendantDependentFlags() { ...@@ -727,6 +729,10 @@ void PaintLayer::updateDescendantDependentFlags() {
.rootScrollerPaintLayer()); .rootScrollerPaintLayer());
} }
if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() &&
oldHasNonIsolatedDescendantWithBlendMode !=
static_cast<bool>(m_hasNonIsolatedDescendantWithBlendMode))
layoutObject()->setNeedsPaintPropertyUpdate();
m_needsDescendantDependentFlagsUpdate = false; m_needsDescendantDependentFlagsUpdate = false;
} }
......
...@@ -392,6 +392,9 @@ void PaintPropertyTreeBuilder::updateEffect( ...@@ -392,6 +392,9 @@ void PaintPropertyTreeBuilder::updateEffect(
PaintPropertyTreeBuilderContext& context) { PaintPropertyTreeBuilderContext& context) {
const ComputedStyle& style = object.styleRef(); const ComputedStyle& style = object.styleRef();
// TODO(crbug.com/673500): style.isStackingContext() is only meaningful for
// HTML elements. What we really want to ask is whether the element starts
// an isolated group, and SVGs use a different rule.
if (!style.isStackingContext()) { if (!style.isStackingContext()) {
if (object.needsPaintPropertyUpdate() || context.forceSubtreeUpdate) { if (object.needsPaintPropertyUpdate() || context.forceSubtreeUpdate) {
if (auto* properties = object.getMutableForPainting().paintProperties()) if (auto* properties = object.getMutableForPainting().paintProperties())
...@@ -401,10 +404,26 @@ void PaintPropertyTreeBuilder::updateEffect( ...@@ -401,10 +404,26 @@ void PaintPropertyTreeBuilder::updateEffect(
} }
// TODO(trchen): Can't omit effect node if we have 3D children. // TODO(trchen): Can't omit effect node if we have 3D children.
// TODO(trchen): Can't omit effect node if we have blending children.
if (object.needsPaintPropertyUpdate() || context.forceSubtreeUpdate) { if (object.needsPaintPropertyUpdate() || context.forceSubtreeUpdate) {
bool effectNodeNeeded = false; bool effectNodeNeeded = false;
// Can't omit effect node if we have paint children with exotic blending.
if (object.isSVG()) {
// Yes, including LayoutSVGRoot, because SVG layout objects don't create
// PaintLayer so PaintLayer::hasNonIsolatedDescendantWithBlendMode()
// doesn't catch SVG descendants.
if (object.hasNonIsolatedBlendingDescendants())
effectNodeNeeded = true;
} else if (PaintLayer* layer = toLayoutBoxModelObject(object).layer()) {
if (layer->hasNonIsolatedDescendantWithBlendMode())
effectNodeNeeded = true;
}
SkBlendMode blendMode =
WebCoreCompositeToSkiaComposite(CompositeSourceOver, style.blendMode());
if (blendMode != SkBlendMode::kSrcOver)
effectNodeNeeded = true;
float opacity = style.opacity(); float opacity = style.opacity();
if (opacity != 1.0f) if (opacity != 1.0f)
effectNodeNeeded = true; effectNodeNeeded = true;
...@@ -449,7 +468,7 @@ void PaintPropertyTreeBuilder::updateEffect( ...@@ -449,7 +468,7 @@ void PaintPropertyTreeBuilder::updateEffect(
auto& properties = object.getMutableForPainting().ensurePaintProperties(); auto& properties = object.getMutableForPainting().ensurePaintProperties();
context.forceSubtreeUpdate |= properties.updateEffect( context.forceSubtreeUpdate |= properties.updateEffect(
context.currentEffect, context.current.transform, outputClip, context.currentEffect, context.current.transform, outputClip,
std::move(filter), opacity); std::move(filter), opacity, blendMode);
} else { } else {
if (auto* properties = object.getMutableForPainting().paintProperties()) if (auto* properties = object.getMutableForPainting().paintProperties())
context.forceSubtreeUpdate |= properties->clearEffect(); context.forceSubtreeUpdate |= properties->clearEffect();
......
...@@ -718,6 +718,14 @@ void PropertyTreeManager::buildEffectNodesRecursively( ...@@ -718,6 +718,14 @@ void PropertyTreeManager::buildEffectNodesRecursively(
m_effectNodesConverted.add(nextEffect); m_effectNodesConverted.add(nextEffect);
#endif #endif
// An effect node can't omit render surface if it has child with exotic
// blending mode. See comments below for more detail.
// TODO(crbug.com/504464): Remove premature optimization here.
if (nextEffect->blendMode() != SkBlendMode::kSrcOver) {
effectTree().Node(compositorIdForCurrentEffectNode())->has_render_surface =
true;
}
// We currently create dummy layers to host effect nodes and corresponding // We currently create dummy layers to host effect nodes and corresponding
// render surfaces. This should be removed once cc implements better support // render surfaces. This should be removed once cc implements better support
// for freestanding property trees. // for freestanding property trees.
...@@ -732,17 +740,20 @@ void PropertyTreeManager::buildEffectNodesRecursively( ...@@ -732,17 +740,20 @@ void PropertyTreeManager::buildEffectNodesRecursively(
effectNode.clip_id = outputClipId; effectNode.clip_id = outputClipId;
// Every effect is supposed to have render surface enabled for grouping, // Every effect is supposed to have render surface enabled for grouping,
// but we can get away without one if the effect is opacity-only and has only // but we can get away without one if the effect is opacity-only and has only
// one compositing child. This is both for optimization and not introducing // one compositing child with kSrcOver blend mode. This is both for
// sub-pixel differences in layout tests. // optimization and not introducing sub-pixel differences in layout tests.
// See PropertyTreeManager::switchToEffectNode() where we retrospectively // See PropertyTreeManager::switchToEffectNode() and above where we
// enable render surface when more than one compositing child is detected. // retrospectively enable render surface when more than one compositing child
// or a child with exotic blend mode is detected.
// TODO(crbug.com/504464): There is ongoing work in cc to delay render surface // TODO(crbug.com/504464): There is ongoing work in cc to delay render surface
// decision until later phase of the pipeline. Remove premature optimization // decision until later phase of the pipeline. Remove premature optimization
// here once the work is ready. // here once the work is ready.
if (!nextEffect->filter().isEmpty()) if (!nextEffect->filter().isEmpty() ||
nextEffect->blendMode() != SkBlendMode::kSrcOver)
effectNode.has_render_surface = true; effectNode.has_render_surface = true;
effectNode.opacity = nextEffect->opacity(); effectNode.opacity = nextEffect->opacity();
effectNode.filters = nextEffect->filter().asCcFilterOperations(); effectNode.filters = nextEffect->filter().asCcFilterOperations();
effectNode.blend_mode = nextEffect->blendMode();
m_propertyTrees.effect_id_to_index_map[effectNode.owner_id] = effectNode.id; m_propertyTrees.effect_id_to_index_map[effectNode.owner_id] = effectNode.id;
m_effectStack.append(BlinkEffectAndCcIdPair{nextEffect, effectNode.id}); m_effectStack.append(BlinkEffectAndCcIdPair{nextEffect, effectNode.id});
......
...@@ -11,7 +11,8 @@ EffectPaintPropertyNode* EffectPaintPropertyNode::root() { ...@@ -11,7 +11,8 @@ EffectPaintPropertyNode* EffectPaintPropertyNode::root() {
EffectPaintPropertyNode, root, EffectPaintPropertyNode, root,
(EffectPaintPropertyNode::create( (EffectPaintPropertyNode::create(
nullptr, TransformPaintPropertyNode::root(), nullptr, TransformPaintPropertyNode::root(),
ClipPaintPropertyNode::root(), CompositorFilterOperations(), 1.0))); ClipPaintPropertyNode::root(), CompositorFilterOperations(), 1.0,
SkBlendMode::kSrcOver)));
return root; return root;
} }
......
...@@ -34,17 +34,19 @@ class PLATFORM_EXPORT EffectPaintPropertyNode ...@@ -34,17 +34,19 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
PassRefPtr<const TransformPaintPropertyNode> localTransformSpace, PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
PassRefPtr<const ClipPaintPropertyNode> outputClip, PassRefPtr<const ClipPaintPropertyNode> outputClip,
CompositorFilterOperations filter, CompositorFilterOperations filter,
float opacity) { float opacity,
SkBlendMode blendMode) {
return adoptRef(new EffectPaintPropertyNode( return adoptRef(new EffectPaintPropertyNode(
std::move(parent), std::move(localTransformSpace), std::move(parent), std::move(localTransformSpace),
std::move(outputClip), std::move(filter), opacity)); std::move(outputClip), std::move(filter), opacity, blendMode));
} }
void update(PassRefPtr<const EffectPaintPropertyNode> parent, void update(PassRefPtr<const EffectPaintPropertyNode> parent,
PassRefPtr<const TransformPaintPropertyNode> localTransformSpace, PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
PassRefPtr<const ClipPaintPropertyNode> outputClip, PassRefPtr<const ClipPaintPropertyNode> outputClip,
CompositorFilterOperations filter, CompositorFilterOperations filter,
float opacity) { float opacity,
SkBlendMode blendMode) {
DCHECK(!isRoot()); DCHECK(!isRoot());
DCHECK(parent != this); DCHECK(parent != this);
m_parent = parent; m_parent = parent;
...@@ -52,6 +54,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode ...@@ -52,6 +54,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
m_outputClip = outputClip; m_outputClip = outputClip;
m_filter = std::move(filter); m_filter = std::move(filter);
m_opacity = opacity; m_opacity = opacity;
m_blendMode = blendMode;
} }
const TransformPaintPropertyNode* localTransformSpace() const { const TransformPaintPropertyNode* localTransformSpace() const {
...@@ -59,6 +62,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode ...@@ -59,6 +62,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
} }
const ClipPaintPropertyNode* outputClip() const { return m_outputClip.get(); } const ClipPaintPropertyNode* outputClip() const { return m_outputClip.get(); }
SkBlendMode blendMode() const { return m_blendMode; }
float opacity() const { return m_opacity; } float opacity() const { return m_opacity; }
const CompositorFilterOperations& filter() const { return m_filter; } const CompositorFilterOperations& filter() const { return m_filter; }
...@@ -72,8 +76,9 @@ class PLATFORM_EXPORT EffectPaintPropertyNode ...@@ -72,8 +76,9 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
// The clone function is used by FindPropertiesNeedingUpdate.h for recording // The clone function is used by FindPropertiesNeedingUpdate.h for recording
// an effect node before it has been updated, to later detect changes. // an effect node before it has been updated, to later detect changes.
PassRefPtr<EffectPaintPropertyNode> clone() const { PassRefPtr<EffectPaintPropertyNode> clone() const {
return adoptRef(new EffectPaintPropertyNode( return adoptRef(new EffectPaintPropertyNode(m_parent, m_localTransformSpace,
m_parent, m_localTransformSpace, m_outputClip, m_filter, m_opacity)); m_outputClip, m_filter,
m_opacity, m_blendMode));
} }
// The equality operator is used by FindPropertiesNeedingUpdate.h for checking // The equality operator is used by FindPropertiesNeedingUpdate.h for checking
...@@ -83,6 +88,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode ...@@ -83,6 +88,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
return m_parent == o.m_parent && return m_parent == o.m_parent &&
m_localTransformSpace == o.m_localTransformSpace && m_localTransformSpace == o.m_localTransformSpace &&
m_outputClip == o.m_outputClip && m_opacity == o.m_opacity && m_outputClip == o.m_outputClip && m_opacity == o.m_opacity &&
m_blendMode == o.m_blendMode &&
m_filter.equalsIgnoringReferenceFilters(o.m_filter); m_filter.equalsIgnoringReferenceFilters(o.m_filter);
} }
#endif #endif
...@@ -95,12 +101,14 @@ class PLATFORM_EXPORT EffectPaintPropertyNode ...@@ -95,12 +101,14 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
PassRefPtr<const TransformPaintPropertyNode> localTransformSpace, PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
PassRefPtr<const ClipPaintPropertyNode> outputClip, PassRefPtr<const ClipPaintPropertyNode> outputClip,
CompositorFilterOperations filter, CompositorFilterOperations filter,
float opacity) float opacity,
SkBlendMode blendMode)
: m_parent(parent), : m_parent(parent),
m_localTransformSpace(localTransformSpace), m_localTransformSpace(localTransformSpace),
m_outputClip(outputClip), m_outputClip(outputClip),
m_filter(std::move(filter)), m_filter(std::move(filter)),
m_opacity(opacity) {} m_opacity(opacity),
m_blendMode(blendMode) {}
RefPtr<const EffectPaintPropertyNode> m_parent; RefPtr<const EffectPaintPropertyNode> m_parent;
// The local transform space serves two purposes: // The local transform space serves two purposes:
...@@ -118,6 +126,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode ...@@ -118,6 +126,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
// === Begin of effects === // === Begin of effects ===
CompositorFilterOperations m_filter; CompositorFilterOperations m_filter;
float m_opacity; float m_opacity;
SkBlendMode m_blendMode;
// === End of effects === // === End of effects ===
// TODO(trchen): Remove the dummy layer. // TODO(trchen): Remove the dummy layer.
......
...@@ -20,7 +20,7 @@ static inline PassRefPtr<EffectPaintPropertyNode> createOpacityOnlyEffect( ...@@ -20,7 +20,7 @@ static inline PassRefPtr<EffectPaintPropertyNode> createOpacityOnlyEffect(
const_cast<ClipPaintPropertyNode*>(parent->outputClip()); const_cast<ClipPaintPropertyNode*>(parent->outputClip());
return EffectPaintPropertyNode::create( return EffectPaintPropertyNode::create(
std::move(parent), std::move(localTransformSpace), std::move(outputClip), std::move(parent), std::move(localTransformSpace), std::move(outputClip),
CompositorFilterOperations(), opacity); CompositorFilterOperations(), opacity, SkBlendMode::kSrcOver);
} }
static inline PaintChunkProperties defaultPaintChunkProperties() { static inline PaintChunkProperties defaultPaintChunkProperties() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment