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 ]
Bug(none) css1/ [ Skip ]
Bug(none) css2.1/ [ Skip ]
Bug(none) css3/ [ Skip ]
Bug(none) css3/blending [ Pass ]
Bug(none) cssom/ [ Skip ]
Bug(none) csspaint/ [ Skip ]
Bug(none) custom-elements/ [ Skip ]
......@@ -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-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:
#
# Rebaselined for small pixel differences.
......
......@@ -150,8 +150,11 @@ void LayoutSVGContainer::descendantIsolationRequirementsChanged(
m_hasNonIsolatedBlendingDescendantsDirty = true;
break;
}
if (SVGLayoutSupport::willIsolateBlendingDescendantsForObject(this))
if (SVGLayoutSupport::willIsolateBlendingDescendantsForObject(this)) {
if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled())
setNeedsPaintPropertyUpdate();
return;
}
if (parent())
parent()->descendantIsolationRequirementsChanged(state);
}
......
......@@ -305,6 +305,8 @@ void LayoutSVGRoot::descendantIsolationRequirementsChanged(
m_hasNonIsolatedBlendingDescendantsDirty = true;
break;
}
if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled())
setNeedsPaintPropertyUpdate();
}
void LayoutSVGRoot::insertedIntoTree() {
......
......@@ -699,6 +699,8 @@ void PaintLayer::updateScrollingStateAfterCompositingChange() {
void PaintLayer::updateDescendantDependentFlags() {
if (m_needsDescendantDependentFlagsUpdate) {
bool oldHasNonIsolatedDescendantWithBlendMode =
m_hasNonIsolatedDescendantWithBlendMode;
m_hasVisibleDescendant = false;
m_hasNonIsolatedDescendantWithBlendMode = false;
m_hasDescendantWithClipPath = false;
......@@ -727,6 +729,10 @@ void PaintLayer::updateDescendantDependentFlags() {
.rootScrollerPaintLayer());
}
if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() &&
oldHasNonIsolatedDescendantWithBlendMode !=
static_cast<bool>(m_hasNonIsolatedDescendantWithBlendMode))
layoutObject()->setNeedsPaintPropertyUpdate();
m_needsDescendantDependentFlagsUpdate = false;
}
......
......@@ -392,6 +392,9 @@ void PaintPropertyTreeBuilder::updateEffect(
PaintPropertyTreeBuilderContext& context) {
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 (object.needsPaintPropertyUpdate() || context.forceSubtreeUpdate) {
if (auto* properties = object.getMutableForPainting().paintProperties())
......@@ -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 blending children.
if (object.needsPaintPropertyUpdate() || context.forceSubtreeUpdate) {
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();
if (opacity != 1.0f)
effectNodeNeeded = true;
......@@ -449,7 +468,7 @@ void PaintPropertyTreeBuilder::updateEffect(
auto& properties = object.getMutableForPainting().ensurePaintProperties();
context.forceSubtreeUpdate |= properties.updateEffect(
context.currentEffect, context.current.transform, outputClip,
std::move(filter), opacity);
std::move(filter), opacity, blendMode);
} else {
if (auto* properties = object.getMutableForPainting().paintProperties())
context.forceSubtreeUpdate |= properties->clearEffect();
......
......@@ -718,6 +718,14 @@ void PropertyTreeManager::buildEffectNodesRecursively(
m_effectNodesConverted.add(nextEffect);
#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
// render surfaces. This should be removed once cc implements better support
// for freestanding property trees.
......@@ -732,17 +740,20 @@ void PropertyTreeManager::buildEffectNodesRecursively(
effectNode.clip_id = outputClipId;
// 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
// one compositing child. This is both for optimization and not introducing
// sub-pixel differences in layout tests.
// See PropertyTreeManager::switchToEffectNode() where we retrospectively
// enable render surface when more than one compositing child is detected.
// one compositing child with kSrcOver blend mode. This is both for
// optimization and not introducing sub-pixel differences in layout tests.
// See PropertyTreeManager::switchToEffectNode() and above where we
// 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
// decision until later phase of the pipeline. Remove premature optimization
// here once the work is ready.
if (!nextEffect->filter().isEmpty())
if (!nextEffect->filter().isEmpty() ||
nextEffect->blendMode() != SkBlendMode::kSrcOver)
effectNode.has_render_surface = true;
effectNode.opacity = nextEffect->opacity();
effectNode.filters = nextEffect->filter().asCcFilterOperations();
effectNode.blend_mode = nextEffect->blendMode();
m_propertyTrees.effect_id_to_index_map[effectNode.owner_id] = effectNode.id;
m_effectStack.append(BlinkEffectAndCcIdPair{nextEffect, effectNode.id});
......
......@@ -11,7 +11,8 @@ EffectPaintPropertyNode* EffectPaintPropertyNode::root() {
EffectPaintPropertyNode, root,
(EffectPaintPropertyNode::create(
nullptr, TransformPaintPropertyNode::root(),
ClipPaintPropertyNode::root(), CompositorFilterOperations(), 1.0)));
ClipPaintPropertyNode::root(), CompositorFilterOperations(), 1.0,
SkBlendMode::kSrcOver)));
return root;
}
......
......@@ -34,17 +34,19 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
PassRefPtr<const ClipPaintPropertyNode> outputClip,
CompositorFilterOperations filter,
float opacity) {
float opacity,
SkBlendMode blendMode) {
return adoptRef(new EffectPaintPropertyNode(
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,
PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
PassRefPtr<const ClipPaintPropertyNode> outputClip,
CompositorFilterOperations filter,
float opacity) {
float opacity,
SkBlendMode blendMode) {
DCHECK(!isRoot());
DCHECK(parent != this);
m_parent = parent;
......@@ -52,6 +54,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
m_outputClip = outputClip;
m_filter = std::move(filter);
m_opacity = opacity;
m_blendMode = blendMode;
}
const TransformPaintPropertyNode* localTransformSpace() const {
......@@ -59,6 +62,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
}
const ClipPaintPropertyNode* outputClip() const { return m_outputClip.get(); }
SkBlendMode blendMode() const { return m_blendMode; }
float opacity() const { return m_opacity; }
const CompositorFilterOperations& filter() const { return m_filter; }
......@@ -72,8 +76,9 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
// The clone function is used by FindPropertiesNeedingUpdate.h for recording
// an effect node before it has been updated, to later detect changes.
PassRefPtr<EffectPaintPropertyNode> clone() const {
return adoptRef(new EffectPaintPropertyNode(
m_parent, m_localTransformSpace, m_outputClip, m_filter, m_opacity));
return adoptRef(new EffectPaintPropertyNode(m_parent, m_localTransformSpace,
m_outputClip, m_filter,
m_opacity, m_blendMode));
}
// The equality operator is used by FindPropertiesNeedingUpdate.h for checking
......@@ -83,6 +88,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
return m_parent == o.m_parent &&
m_localTransformSpace == o.m_localTransformSpace &&
m_outputClip == o.m_outputClip && m_opacity == o.m_opacity &&
m_blendMode == o.m_blendMode &&
m_filter.equalsIgnoringReferenceFilters(o.m_filter);
}
#endif
......@@ -95,12 +101,14 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
PassRefPtr<const ClipPaintPropertyNode> outputClip,
CompositorFilterOperations filter,
float opacity)
float opacity,
SkBlendMode blendMode)
: m_parent(parent),
m_localTransformSpace(localTransformSpace),
m_outputClip(outputClip),
m_filter(std::move(filter)),
m_opacity(opacity) {}
m_opacity(opacity),
m_blendMode(blendMode) {}
RefPtr<const EffectPaintPropertyNode> m_parent;
// The local transform space serves two purposes:
......@@ -118,6 +126,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
// === Begin of effects ===
CompositorFilterOperations m_filter;
float m_opacity;
SkBlendMode m_blendMode;
// === End of effects ===
// TODO(trchen): Remove the dummy layer.
......
......@@ -20,7 +20,7 @@ static inline PassRefPtr<EffectPaintPropertyNode> createOpacityOnlyEffect(
const_cast<ClipPaintPropertyNode*>(parent->outputClip());
return EffectPaintPropertyNode::create(
std::move(parent), std::move(localTransformSpace), std::move(outputClip),
CompositorFilterOperations(), opacity);
CompositorFilterOperations(), opacity, SkBlendMode::kSrcOver);
}
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