summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorrosca@adobe.com <rosca@adobe.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-26 10:27:22 +0000
committerrosca@adobe.com <rosca@adobe.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-26 10:27:22 +0000
commit7bbeaf4e5b9ad540bf6d3496470778ed74737766 (patch)
tree63d6549481b2a660eb39e3bfef8e0c42d28b75f1 /cc
parentcc6a5a0804b5138079708e5c2a32081e078af605 (diff)
downloadchromium_src-7bbeaf4e5b9ad540bf6d3496470778ed74737766.zip
chromium_src-7bbeaf4e5b9ad540bf6d3496470778ed74737766.tar.gz
chromium_src-7bbeaf4e5b9ad540bf6d3496470778ed74737766.tar.bz2
The blink part of this implementation is uploaded at https://codereview.chromium.org/23511004/
The spec for mix-blend-mode is http://dev.w3.org/fxtf/compositing-1/#mix-blend-mode BUG=243223 Review URL: https://codereview.chromium.org/23455060 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237295 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r--cc/cc_tests.gyp1
-rw-r--r--cc/layers/compositing_reasons.h2
-rw-r--r--cc/layers/delegated_renderer_layer.cc11
-rw-r--r--cc/layers/delegated_renderer_layer_impl_unittest.cc45
-rw-r--r--cc/layers/layer.cc80
-rw-r--r--cc/layers/layer.h22
-rw-r--r--cc/layers/layer_impl.cc25
-rw-r--r--cc/layers/layer_impl.h13
-rw-r--r--cc/layers/layer_impl_unittest.cc33
-rw-r--r--cc/layers/layer_unittest.cc2
-rw-r--r--cc/layers/render_surface_impl.cc3
-rw-r--r--cc/output/gl_renderer.cc194
-rw-r--r--cc/output/gl_renderer.h5
-rw-r--r--cc/output/renderer_pixeltest.cc8
-rw-r--r--cc/output/software_renderer_unittest.cc27
-rw-r--r--cc/quads/draw_quad_unittest.cc9
-rw-r--r--cc/quads/render_pass_unittest.cc72
-rw-r--r--cc/quads/shared_quad_state.cc19
-rw-r--r--cc/quads/shared_quad_state.h5
-rw-r--r--cc/test/data/blending_and_filter.pngbin0 -> 909 bytes
-rw-r--r--cc/test/data/blending_transparent.pngbin0 -> 919 bytes
-rw-r--r--cc/test/data/blending_with_root.pngbin0 -> 889 bytes
-rw-r--r--cc/test/render_pass_test_common.cc11
-rw-r--r--cc/test/render_pass_test_utils.cc37
-rw-r--r--cc/trees/layer_tree_host_common.cc36
-rw-r--r--cc/trees/layer_tree_host_impl.cc3
-rw-r--r--cc/trees/layer_tree_host_pixeltest_blending.cc120
-rw-r--r--cc/trees/layer_tree_host_unittest_occlusion.cc68
-rw-r--r--cc/trees/occlusion_tracker.cc7
29 files changed, 743 insertions, 115 deletions
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 1699577..5b318fa27 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -84,6 +84,7 @@
'trees/layer_sorter_unittest.cc',
'trees/layer_tree_host_common_unittest.cc',
'trees/layer_tree_host_impl_unittest.cc',
+ 'trees/layer_tree_host_pixeltest_blending.cc',
'trees/layer_tree_host_pixeltest_filters.cc',
'trees/layer_tree_host_pixeltest_masks.cc',
'trees/layer_tree_host_pixeltest_on_demand_raster.cc',
diff --git a/cc/layers/compositing_reasons.h b/cc/layers/compositing_reasons.h
index 02354a0..6331a90 100644
--- a/cc/layers/compositing_reasons.h
+++ b/cc/layers/compositing_reasons.h
@@ -53,6 +53,8 @@ const uint64 kCompositingReasonLayerForBackground = GG_UINT64_C(1) << 30;
const uint64 kCompositingReasonLayerForMask = GG_UINT64_C(1) << 31;
const uint64 kCompositingReasonOverflowScrollingParent = GG_UINT64_C(1) << 32;
const uint64 kCompositingReasonOutOfFlowClipping = GG_UINT64_C(1) << 33;
+const uint64 kCompositingReasonIsolateCompositedDescendants =
+ GG_UINT64_C(1) << 35;
typedef uint64 CompositingReasons;
diff --git a/cc/layers/delegated_renderer_layer.cc b/cc/layers/delegated_renderer_layer.cc
index a92b701..a940903 100644
--- a/cc/layers/delegated_renderer_layer.cc
+++ b/cc/layers/delegated_renderer_layer.cc
@@ -107,10 +107,13 @@ void DelegatedRendererLayer::SetDisplaySize(gfx::Size size) {
SetNeedsCommit();
}
-static bool FrameDataHasFilter(DelegatedFrameData* frame) {
+static bool FrameDataRequiresFilterContext(const DelegatedFrameData* frame) {
for (size_t i = 0; i < frame->render_pass_list.size(); ++i) {
const QuadList& quad_list = frame->render_pass_list[i]->quad_list;
for (size_t j = 0; j < quad_list.size(); ++j) {
+ if (quad_list[j]->shared_quad_state->blend_mode !=
+ SkXfermode::kSrcOver_Mode)
+ return true;
if (quad_list[j]->material != DrawQuad::RENDER_PASS)
continue;
const RenderPassDrawQuad* render_pass_quad =
@@ -133,9 +136,9 @@ bool DelegatedRendererLayer::Update(ResourceUpdateQueue* queue,
frame_provider_->GetFrameDataAndRefResources(this, &frame_damage_);
should_collect_new_frame_ = false;
- // If any quad has a filter operation, then we need a filter context to draw
- // this layer's content.
- if (FrameDataHasFilter(frame_data_) && layer_tree_host())
+ // If any quad has a filter operation or a blend mode other than normal,
+ // then we need an offscreen context to draw this layer's content.
+ if (FrameDataRequiresFilterContext(frame_data_))
layer_tree_host()->set_needs_filter_context();
return true;
diff --git a/cc/layers/delegated_renderer_layer_impl_unittest.cc b/cc/layers/delegated_renderer_layer_impl_unittest.cc
index c8811a2..8cb0f3e 100644
--- a/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -529,13 +529,13 @@ class DelegatedRendererLayerImplTestTransform
AppendQuadsData data(pass->id);
SharedQuadState* shared_quad_state = quad_sink.UseSharedQuadState(
SharedQuadState::Create());
- shared_quad_state->SetAll(
- child_pass_transform,
- child_pass_content_bounds,
- child_pass_rect,
- child_pass_clip_rect,
- child_pass_clipped,
- 1.f);
+ shared_quad_state->SetAll(child_pass_transform,
+ child_pass_content_bounds,
+ child_pass_rect,
+ child_pass_clip_rect,
+ child_pass_clipped,
+ 1.f,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<SolidColorDrawQuad> color_quad;
color_quad = SolidColorDrawQuad::Create();
@@ -564,13 +564,13 @@ class DelegatedRendererLayerImplTestTransform
AppendQuadsData data(pass->id);
SharedQuadState* shared_quad_state =
quad_sink.UseSharedQuadState(SharedQuadState::Create());
- shared_quad_state->SetAll(
- root_pass_transform,
- root_pass_content_bounds,
- root_pass_rect,
- root_pass_clip_rect,
- root_pass_clipped,
- 1.f);
+ shared_quad_state->SetAll(root_pass_transform,
+ root_pass_content_bounds,
+ root_pass_rect,
+ root_pass_clip_rect,
+ root_pass_clipped,
+ 1.f,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<RenderPassDrawQuad> render_pass_quad =
RenderPassDrawQuad::Create();
@@ -933,13 +933,13 @@ class DelegatedRendererLayerImplTestClip
AppendQuadsData data(pass->id);
SharedQuadState* shared_quad_state =
quad_sink.UseSharedQuadState(SharedQuadState::Create());
- shared_quad_state->SetAll(
- child_pass_transform,
- child_pass_content_bounds,
- child_pass_rect,
- child_pass_clip_rect,
- child_pass_clipped,
- 1.f);
+ shared_quad_state->SetAll(child_pass_transform,
+ child_pass_content_bounds,
+ child_pass_rect,
+ child_pass_clip_rect,
+ child_pass_clipped,
+ 1.f,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<SolidColorDrawQuad> color_quad;
color_quad = SolidColorDrawQuad::Create();
@@ -971,7 +971,8 @@ class DelegatedRendererLayerImplTestClip
root_pass_rect,
root_pass_clip_rect,
root_pass_clipped,
- 1.f);
+ 1.f,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<RenderPassDrawQuad> render_pass_quad =
RenderPassDrawQuad::Create();
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index e0ffb5c..7790719 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -47,6 +47,8 @@ Layer::Layer()
background_color_(0),
compositing_reasons_(kCompositingReasonUnknown),
opacity_(1.f),
+ blend_mode_(SkXfermode::kSrcOver_Mode),
+ is_root_for_isolated_group_(false),
anchor_point_z_(0.f),
is_container_for_fixed_position_layers_(false),
is_drawable_(false),
@@ -125,8 +127,7 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) {
if (host && layer_animation_controller_->has_any_animation())
host->SetNeedsCommit();
- if (host && (!filters_.IsEmpty() || !background_filters_.IsEmpty()))
- layer_tree_host_->set_needs_filter_context();
+ SetNeedsFilterContextIfNeeded();
}
void Layer::SetNeedsUpdate() {
@@ -160,6 +161,15 @@ void Layer::SetNextCommitWaitsForActivation() {
layer_tree_host_->SetNextCommitWaitsForActivation();
}
+void Layer::SetNeedsFilterContextIfNeeded() {
+ if (!layer_tree_host_)
+ return;
+
+ if (!filters_.IsEmpty() || !background_filters_.IsEmpty() ||
+ !uses_default_blend_mode())
+ layer_tree_host_->set_needs_filter_context();
+}
+
void Layer::SetNeedsPushProperties() {
if (needs_push_properties_)
return;
@@ -471,8 +481,7 @@ void Layer::SetFilters(const FilterOperations& filters) {
return;
filters_ = filters;
SetNeedsCommit();
- if (!filters.IsEmpty() && layer_tree_host_)
- layer_tree_host_->set_needs_filter_context();
+ SetNeedsFilterContextIfNeeded();
}
bool Layer::FilterIsAnimating() const {
@@ -485,8 +494,7 @@ void Layer::SetBackgroundFilters(const FilterOperations& filters) {
return;
background_filters_ = filters;
SetNeedsCommit();
- if (!filters.IsEmpty() && layer_tree_host_)
- layer_tree_host_->set_needs_filter_context();
+ SetNeedsFilterContextIfNeeded();
}
void Layer::SetOpacity(float opacity) {
@@ -505,6 +513,64 @@ bool Layer::OpacityCanAnimateOnImplThread() const {
return false;
}
+void Layer::SetBlendMode(SkXfermode::Mode blend_mode) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (blend_mode_ == blend_mode)
+ return;
+
+ // Allowing only blend modes that are defined in the CSS Compositing standard:
+ // http://dev.w3.org/fxtf/compositing-1/#blending
+ switch (blend_mode) {
+ case SkXfermode::kSrcOver_Mode:
+ case SkXfermode::kScreen_Mode:
+ case SkXfermode::kOverlay_Mode:
+ case SkXfermode::kDarken_Mode:
+ case SkXfermode::kLighten_Mode:
+ case SkXfermode::kColorDodge_Mode:
+ case SkXfermode::kColorBurn_Mode:
+ case SkXfermode::kHardLight_Mode:
+ case SkXfermode::kSoftLight_Mode:
+ case SkXfermode::kDifference_Mode:
+ case SkXfermode::kExclusion_Mode:
+ case SkXfermode::kMultiply_Mode:
+ case SkXfermode::kHue_Mode:
+ case SkXfermode::kSaturation_Mode:
+ case SkXfermode::kColor_Mode:
+ case SkXfermode::kLuminosity_Mode:
+ // supported blend modes
+ break;
+ case SkXfermode::kClear_Mode:
+ case SkXfermode::kSrc_Mode:
+ case SkXfermode::kDst_Mode:
+ case SkXfermode::kDstOver_Mode:
+ case SkXfermode::kSrcIn_Mode:
+ case SkXfermode::kDstIn_Mode:
+ case SkXfermode::kSrcOut_Mode:
+ case SkXfermode::kDstOut_Mode:
+ case SkXfermode::kSrcATop_Mode:
+ case SkXfermode::kDstATop_Mode:
+ case SkXfermode::kXor_Mode:
+ case SkXfermode::kPlus_Mode:
+ case SkXfermode::kModulate_Mode:
+ // Porter Duff Compositing Operators are not yet supported
+ // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators
+ NOTREACHED();
+ return;
+ }
+
+ blend_mode_ = blend_mode;
+ SetNeedsCommit();
+ SetNeedsFilterContextIfNeeded();
+}
+
+void Layer::SetIsRootForIsolatedGroup(bool root) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (is_root_for_isolated_group_ == root)
+ return;
+ is_root_for_isolated_group_ = root;
+ SetNeedsCommit();
+}
+
void Layer::SetContentsOpaque(bool opaque) {
DCHECK(IsPropertyChangeAllowed());
if (contents_opaque_ == opaque)
@@ -832,6 +898,8 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
if (!layer->OpacityIsAnimatingOnImplOnly() && !OpacityIsAnimating())
layer->SetOpacity(opacity_);
DCHECK(!(OpacityIsAnimating() && layer->OpacityIsAnimatingOnImplOnly()));
+ layer->SetBlendMode(blend_mode_);
+ layer->SetIsRootForIsolatedGroup(is_root_for_isolated_group_);
layer->SetPosition(position_);
layer->SetIsContainerForFixedPositionLayers(
IsContainerForFixedPositionLayers());
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index b552a35..9af3dea 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -29,6 +29,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_f.h"
#include "ui/gfx/transform.h"
@@ -126,6 +127,22 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
bool OpacityIsAnimating() const;
virtual bool OpacityCanAnimateOnImplThread() const;
+ void SetBlendMode(SkXfermode::Mode blend_mode);
+ SkXfermode::Mode blend_mode() const { return blend_mode_; }
+
+ bool uses_default_blend_mode() const {
+ return blend_mode_ == SkXfermode::kSrcOver_Mode;
+ }
+
+ // A layer is root for an isolated group when it and all its descendants are
+ // drawn over a black and fully transparent background, creating an isolated
+ // group. It should be used along with SetBlendMode(), in order to restrict
+ // layers within the group to blend with layers outside this group.
+ void SetIsRootForIsolatedGroup(bool root);
+ bool is_root_for_isolated_group() const {
+ return is_root_for_isolated_group_;
+ }
+
void SetFilters(const FilterOperations& filters);
const FilterOperations& filters() const { return filters_; }
bool FilterIsAnimating() const;
@@ -459,6 +476,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// unused resources on the impl thread are returned before commit completes.
void SetNextCommitWaitsForActivation();
+ // Called when the blend mode or filters have been changed.
+ void SetNeedsFilterContextIfNeeded();
+
void SetNeedsPushProperties();
void AddDependentNeedsPushProperties();
void RemoveDependentNeedsPushProperties();
@@ -552,6 +572,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
SkColor background_color_;
CompositingReasons compositing_reasons_;
float opacity_;
+ SkXfermode::Mode blend_mode_;
+ bool is_root_for_isolated_group_;
FilterOperations filters_;
FilterOperations background_filters_;
float anchor_point_z_;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 99f9502..f8882291 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -53,6 +53,8 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
masks_to_bounds_(false),
contents_opaque_(false),
opacity_(1.0),
+ blend_mode_(SkXfermode::kSrcOver_Mode),
+ is_root_for_isolated_group_(false),
preserves_3d_(false),
use_parent_backface_visibility_(false),
draw_checkerboard_for_missing_tiles_(false),
@@ -246,7 +248,8 @@ scoped_ptr<SharedQuadState> LayerImpl::CreateSharedQuadState() const {
draw_properties_.visible_content_rect,
draw_properties_.clip_rect,
draw_properties_.is_clipped,
- draw_properties_.opacity);
+ draw_properties_.opacity,
+ blend_mode_);
return state.Pass();
}
@@ -524,6 +527,8 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->SetTouchEventHandlerRegion(touch_event_handler_region_);
layer->SetContentsOpaque(contents_opaque_);
layer->SetOpacity(opacity_);
+ layer->SetBlendMode(blend_mode_);
+ layer->SetIsRootForIsolatedGroup(is_root_for_isolated_group_);
layer->SetPosition(position_);
layer->SetIsContainerForFixedPositionLayers(
is_container_for_fixed_position_layers_);
@@ -880,6 +885,21 @@ bool LayerImpl::OpacityIsAnimatingOnImplOnly() const {
return opacity_animation && opacity_animation->is_impl_only();
}
+void LayerImpl::SetBlendMode(SkXfermode::Mode blend_mode) {
+ if (blend_mode_ == blend_mode)
+ return;
+
+ blend_mode_ = blend_mode;
+ NoteLayerPropertyChangedForSubtree();
+}
+
+void LayerImpl::SetIsRootForIsolatedGroup(bool root) {
+ if (is_root_for_isolated_group_ == root)
+ return;
+
+ is_root_for_isolated_group_ = root;
+}
+
void LayerImpl::SetPosition(gfx::PointF position) {
if (position_ == position)
return;
@@ -1281,6 +1301,9 @@ CompositingReasonsAsValue(CompositingReasons reasons) {
if (reasons & kCompositingReasonOutOfFlowClipping)
reason_list->AppendString("Has clipping ancestor");
+ if (reasons & kCompositingReasonIsolateCompositedDescendants)
+ reason_list->AppendString("Should isolate composited descendants");
+
return reason_list.PassAs<base::Value>();
}
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 6d06b6d2..1969b74 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -213,6 +213,17 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
bool OpacityIsAnimating() const;
bool OpacityIsAnimatingOnImplOnly() const;
+ void SetBlendMode(SkXfermode::Mode);
+ SkXfermode::Mode blend_mode() const { return blend_mode_; }
+ bool uses_default_blend_mode() const {
+ return blend_mode_ == SkXfermode::kSrcOver_Mode;
+ }
+
+ void SetIsRootForIsolatedGroup(bool root);
+ bool is_root_for_isolated_group() const {
+ return is_root_for_isolated_group_;
+ }
+
void SetPosition(gfx::PointF position);
gfx::PointF position() const { return position_; }
@@ -571,6 +582,8 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
bool masks_to_bounds_;
bool contents_opaque_;
float opacity_;
+ SkXfermode::Mode blend_mode_;
+ bool is_root_for_isolated_group_;
gfx::PointF position_;
bool preserves_3d_;
bool use_parent_backface_visibility_;
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc
index 2d3305c..c43adff 100644
--- a/cc/layers/layer_impl_unittest.cc
+++ b/cc/layers/layer_impl_unittest.cc
@@ -40,6 +40,13 @@ namespace {
EXPECT_FALSE(child->LayerPropertyChanged()); \
EXPECT_FALSE(grand_child->LayerPropertyChanged());
+#define EXECUTE_AND_VERIFY_ONLY_DESCENDANTS_CHANGED(code_to_test) \
+ root->ResetAllChangeTrackingForSubtree(); \
+ code_to_test; \
+ EXPECT_FALSE(root->LayerPropertyChanged()); \
+ EXPECT_TRUE(child->LayerPropertyChanged()); \
+ EXPECT_TRUE(grand_child->LayerPropertyChanged());
+
#define VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(code_to_test) \
root->ResetAllChangeTrackingForSubtree(); \
host_impl.ForcePrepareToDraw(); \
@@ -91,6 +98,7 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f);
FilterOperations arbitrary_filters;
arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
+ SkXfermode::Mode arbitrary_blend_mode = SkXfermode::kMultiply_Mode;
// These properties are internal, and should not be considered "change" when
// they are used.
@@ -119,6 +127,7 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetScrollOffset(arbitrary_vector2d));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetHideLayerAndSubtree(true));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetOpacity(arbitrary_number));
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBlendMode(arbitrary_blend_mode));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetTransform(arbitrary_transform));
// Changing these properties only affects the layer itself.
@@ -131,13 +140,10 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(
root->SetBackgroundFilters(arbitrary_filters));
- // Special case: check that sublayer transform changes all layer's
- // descendants, but not the layer itself.
- root->ResetAllChangeTrackingForSubtree();
- root->SetSublayerTransform(arbitrary_transform);
- EXPECT_FALSE(root->LayerPropertyChanged());
- EXPECT_TRUE(child->LayerPropertyChanged());
- EXPECT_TRUE(grand_child->LayerPropertyChanged());
+ // Changing these properties affects all layer's descendants,
+ // but not the layer itself.
+ EXECUTE_AND_VERIFY_ONLY_DESCENDANTS_CHANGED(
+ root->SetSublayerTransform(arbitrary_transform));
// Special case: check that SetBounds changes behavior depending on
// masksToBounds.
@@ -148,6 +154,9 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
// changed.
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBounds(arbitrary_size));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ root->SetIsRootForIsolatedGroup(true));
+
// After setting all these properties already, setting to the exact same
// values again should not cause any change.
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
@@ -172,6 +181,10 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
root->SetContentsScale(arbitrary_number, arbitrary_number));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetContentsOpaque(true));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetOpacity(arbitrary_number));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ root->SetBlendMode(arbitrary_blend_mode));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ root->SetIsRootForIsolatedGroup(true));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetDrawsContent(true));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
root->SetSublayerTransform(arbitrary_transform));
@@ -199,6 +212,7 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f);
FilterOperations arbitrary_filters;
arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
+ SkXfermode::Mode arbitrary_blend_mode = SkXfermode::kMultiply_Mode;
// Related filter functions.
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters));
@@ -243,6 +257,7 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
root->SetBackgroundFilters(arbitrary_filters));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetOpacity(arbitrary_number));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetBlendMode(arbitrary_blend_mode));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetTransform(arbitrary_transform));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
root->SetSublayerTransform(arbitrary_transform));
@@ -251,6 +266,7 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
// Unrelated functions, set to the same values, no needs update.
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
root->SetAnchorPointZ(arbitrary_number));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetIsRootForIsolatedGroup(true));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetMasksToBounds(true));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetContentsOpaque(true));
@@ -269,6 +285,9 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
root->SetBackgroundFilters(arbitrary_filters));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetOpacity(arbitrary_number));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
+ root->SetBlendMode(arbitrary_blend_mode));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetIsRootForIsolatedGroup(true));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
root->SetTransform(arbitrary_transform));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
root->SetSublayerTransform(arbitrary_transform));
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 0414acb..a77a5fb 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -545,6 +545,8 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBackgroundColor(SK_ColorLTGRAY));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetMasksToBounds(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendMode(SkXfermode::kHue_Mode));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsRootForIsolatedGroup(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetContentsOpaque(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPosition(gfx::PointF(4.f, 9.f)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetSublayerTransform(
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index 660f5e4..53e60c7 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -156,7 +156,8 @@ void RenderSurfaceImpl::AppendQuads(QuadSink* quad_sink,
content_rect_,
clip_rect_,
is_clipped_,
- draw_opacity_);
+ draw_opacity_,
+ owning_layer_->blend_mode());
if (owning_layer_->ShowDebugBorders()) {
SkColor color = for_replica ?
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index c0cf138..cc9a752 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -576,11 +576,129 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer,
return device.accessBitmap(false);
}
-scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
+static SkBitmap ApplyBlendModeWithBackdrop(
+ GLRenderer* renderer,
+ ContextProvider* offscreen_contexts,
+ SkBitmap source_bitmap_with_filters,
+ ScopedResource* source_texture_resource,
+ ScopedResource* background_texture_resource,
+ SkXfermode::Mode blend_mode) {
+ if (!offscreen_contexts || !offscreen_contexts->GrContext())
+ return source_bitmap_with_filters;
+
+ DCHECK(background_texture_resource);
+ DCHECK(source_texture_resource);
+
+ gfx::Size source_size = source_texture_resource->size();
+ gfx::Size background_size = background_texture_resource->size();
+
+ DCHECK_LE(background_size.width(), source_size.width());
+ DCHECK_LE(background_size.height(), source_size.height());
+
+ int source_texture_with_filters_id;
+ scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
+ if (source_bitmap_with_filters.getTexture()) {
+ DCHECK_EQ(source_size.width(), source_bitmap_with_filters.width());
+ DCHECK_EQ(source_size.height(), source_bitmap_with_filters.height());
+ GrTexture* texture =
+ reinterpret_cast<GrTexture*>(source_bitmap_with_filters.getTexture());
+ source_texture_with_filters_id = texture->getTextureHandle();
+ } else {
+ lock.reset(new ResourceProvider::ScopedReadLockGL(
+ renderer->resource_provider(), source_texture_resource->id()));
+ source_texture_with_filters_id = lock->texture_id();
+ }
+
+ ResourceProvider::ScopedReadLockGL lock_background(
+ renderer->resource_provider(), background_texture_resource->id());
+
+ // Flush the compositor context to ensure that textures there are available
+ // in the shared context. Do this after locking/creating the compositor
+ // texture.
+ renderer->resource_provider()->Flush();
+
+ // Make sure skia uses the correct GL context.
+ offscreen_contexts->Context3d()->makeContextCurrent();
+
+ // Wrap the source texture in a Ganesh platform texture.
+ GrBackendTextureDesc backend_texture_description;
+ backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
+ backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
+
+ backend_texture_description.fWidth = source_size.width();
+ backend_texture_description.fHeight = source_size.height();
+ backend_texture_description.fTextureHandle = source_texture_with_filters_id;
+ skia::RefPtr<GrTexture> source_texture =
+ skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
+ backend_texture_description));
+
+ backend_texture_description.fWidth = background_size.width();
+ backend_texture_description.fHeight = background_size.height();
+ backend_texture_description.fTextureHandle = lock_background.texture_id();
+ skia::RefPtr<GrTexture> background_texture =
+ skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
+ backend_texture_description));
+
+ // Place the platform texture inside an SkBitmap.
+ SkBitmap source;
+ source.setConfig(
+ SkBitmap::kARGB_8888_Config, source_size.width(), source_size.height());
+ skia::RefPtr<SkGrPixelRef> source_pixel_ref =
+ skia::AdoptRef(new SkGrPixelRef(source_texture.get()));
+ source.setPixelRef(source_pixel_ref.get());
+
+ SkBitmap background;
+ background.setConfig(SkBitmap::kARGB_8888_Config,
+ background_size.width(),
+ background_size.height());
+ skia::RefPtr<SkGrPixelRef> background_pixel_ref =
+ skia::AdoptRef(new SkGrPixelRef(background_texture.get()));
+ background.setPixelRef(background_pixel_ref.get());
+
+ // Create a scratch texture for backing store.
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ desc.fSampleCnt = 0;
+ desc.fWidth = source.width();
+ desc.fHeight = source.height();
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
+ GrAutoScratchTexture scratch_texture(
+ offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
+ skia::RefPtr<GrTexture> backing_store =
+ skia::AdoptRef(scratch_texture.detach());
+
+ // Create a device and canvas using that backing store.
+ SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
+ SkCanvas canvas(&device);
+
+ // Draw the source bitmap through the filter to the canvas.
+ canvas.clear(SK_ColorTRANSPARENT);
+ canvas.drawSprite(background, 0, 0);
+ SkPaint paint;
+ paint.setXfermodeMode(blend_mode);
+ canvas.drawSprite(source, 0, 0, &paint);
+
+ // Flush skia context so that all the rendered stuff appears on the
+ // texture.
+ offscreen_contexts->GrContext()->flush();
+
+ // Flush the GL context so rendering results from this context are
+ // visible in the compositor's context.
+ offscreen_contexts->Context3d()->flush();
+
+ // Use the compositor's GL context again.
+ renderer->Context()->makeContextCurrent();
+
+ return device.accessBitmap(false);
+}
+
+scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform,
- const gfx::Transform& contents_device_transform_inverse) {
+ const gfx::Transform& contents_device_transform_inverse,
+ bool* background_changed) {
// This method draws a background filter, which applies a filter to any pixels
// behind the quad and seen through its background. The algorithm works as
// follows:
@@ -607,14 +725,14 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
// TODO(danakj): We only allow background filters on an opaque render surface
// because other surfaces may contain translucent pixels, and the contents
// behind those translucent pixels wouldn't have the filter applied.
- if (frame->current_render_pass->has_transparent_background)
- return scoped_ptr<ScopedResource>();
+ bool apply_background_filters =
+ !frame->current_render_pass->has_transparent_background;
DCHECK(!frame->current_texture);
// TODO(ajuma): Add support for reference filters once
// FilterOperations::GetOutsets supports reference filters.
- if (quad->background_filters.HasReferenceFilter())
- return scoped_ptr<ScopedResource>();
+ if (apply_background_filters && quad->background_filters.HasReferenceFilter())
+ apply_background_filters = false;
// TODO(danakj): Do a single readback for both the surface and replica and
// cache the filtered results (once filter textures are not reused).
@@ -649,18 +767,28 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
quad->background_filters, device_background_texture->size());
- SkBitmap filtered_device_background =
- ApplyImageFilter(this,
- frame->offscreen_context_provider,
- quad->rect.origin(),
- filter.get(),
- device_background_texture.get());
- if (!filtered_device_background.getTexture())
- return scoped_ptr<ScopedResource>();
+ SkBitmap filtered_device_background;
+ if (apply_background_filters) {
+ filtered_device_background =
+ ApplyImageFilter(this,
+ frame->offscreen_context_provider,
+ quad->rect.origin(),
+ filter.get(),
+ device_background_texture.get());
+ }
+ *background_changed = (filtered_device_background.getTexture() != NULL);
- GrTexture* texture =
- reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
- int filtered_device_background_texture_id = texture->getTextureHandle();
+ int filtered_device_background_texture_id = 0;
+ scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
+ if (filtered_device_background.getTexture()) {
+ GrTexture* texture =
+ reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
+ filtered_device_background_texture_id = texture->getTextureHandle();
+ } else {
+ lock.reset(new ResourceProvider::ScopedReadLockGL(
+ resource_provider_, device_background_texture->id()));
+ filtered_device_background_texture_id = lock->texture_id();
+ }
scoped_ptr<ScopedResource> background_texture =
ScopedResource::create(resource_provider_);
@@ -731,19 +859,24 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
return;
+ bool need_background_texture =
+ quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode ||
+ !quad->background_filters.IsEmpty();
+ bool background_changed = false;
scoped_ptr<ScopedResource> background_texture;
- if (!quad->background_filters.IsEmpty()) {
+ if (need_background_texture) {
// The pixels from the filtered background should completely replace the
// current pixel values.
bool disable_blending = blend_enabled();
if (disable_blending)
SetBlendEnabled(false);
- background_texture = DrawBackgroundFilters(
- frame,
- quad,
- contents_device_transform,
- contents_device_transform_inverse);
+ background_texture =
+ GetBackgroundWithFilters(frame,
+ quad,
+ contents_device_transform,
+ contents_device_transform_inverse,
+ &background_changed);
if (disable_blending)
SetBlendEnabled(true);
@@ -782,8 +915,19 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
}
}
- // Draw the background texture if there is one.
- if (background_texture) {
+ if (quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode &&
+ background_texture) {
+ filter_bitmap =
+ ApplyBlendModeWithBackdrop(this,
+ frame->offscreen_context_provider,
+ filter_bitmap,
+ contents_texture,
+ background_texture.get(),
+ quad->shared_quad_state->blend_mode);
+ }
+
+ // Draw the background texture if it has some filters applied.
+ if (background_texture && background_changed) {
DCHECK(background_texture->size() == quad->rect.size());
ResourceProvider::ScopedReadLockGL lock(resource_provider_,
background_texture->id());
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index def9a25..d582769 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -151,11 +151,12 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
const CheckerboardDrawQuad* quad);
void DrawDebugBorderQuad(const DrawingFrame* frame,
const DebugBorderDrawQuad* quad);
- scoped_ptr<ScopedResource> DrawBackgroundFilters(
+ scoped_ptr<ScopedResource> GetBackgroundWithFilters(
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform,
- const gfx::Transform& contents_device_transformInverse);
+ const gfx::Transform& contents_device_transformInverse,
+ bool* background_changed);
void DrawRenderPassQuad(DrawingFrame* frame, const RenderPassDrawQuad* quad);
void DrawSolidColorQuad(const DrawingFrame* frame,
const SolidColorDrawQuad* quad);
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index 3de12ac..2bf5152 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -50,13 +50,15 @@ scoped_ptr<SharedQuadState> CreateTestSharedQuadState(
const gfx::Rect clip_rect = rect;
const bool is_clipped = false;
const float opacity = 1.0f;
+ const SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create();
shared_state->SetAll(content_to_target_transform,
content_bounds,
visible_content_rect,
clip_rect,
is_clipped,
- opacity);
+ opacity,
+ blend_mode);
return shared_state.Pass();
}
@@ -68,13 +70,15 @@ scoped_ptr<SharedQuadState> CreateTestSharedQuadStateClipped(
const gfx::Rect visible_content_rect = clip_rect;
const bool is_clipped = true;
const float opacity = 1.0f;
+ const SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create();
shared_state->SetAll(content_to_target_transform,
content_bounds,
visible_content_rect,
clip_rect,
is_clipped,
- opacity);
+ opacity,
+ blend_mode);
return shared_state.Pass();
}
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index ef9f43f..33e311a 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -79,8 +79,13 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) {
InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
- shared_quad_state->SetAll(
- gfx::Transform(), outer_size, outer_rect, outer_rect, false, 1.0);
+ shared_quad_state->SetAll(gfx::Transform(),
+ outer_size,
+ outer_rect,
+ outer_rect,
+ false,
+ 1.0,
+ SkXfermode::kSrcOver_Mode);
RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
root_render_pass->SetNew(
@@ -162,8 +167,13 @@ TEST_F(SoftwareRendererTest, TileQuad) {
gfx::Rect root_rect = DeviceViewport();
scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
- shared_quad_state->SetAll(
- gfx::Transform(), outer_size, outer_rect, outer_rect, false, 1.0);
+ shared_quad_state->SetAll(gfx::Transform(),
+ outer_size,
+ outer_rect,
+ outer_rect,
+ false,
+ 1.0,
+ SkXfermode::kSrcOver_Mode);
RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
root_render_pass->SetNew(
@@ -241,8 +251,13 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
gfx::Rect root_rect = DeviceViewport();
scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
- shared_quad_state->SetAll(
- gfx::Transform(), tile_size, tile_rect, tile_rect, false, 1.0);
+ shared_quad_state->SetAll(gfx::Transform(),
+ tile_size,
+ tile_rect,
+ tile_rect,
+ false,
+ 1.0,
+ SkXfermode::kSrcOver_Mode);
RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
root_render_pass->SetNew(
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index 8180898..1a99184 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -36,6 +36,7 @@ TEST(DrawQuadTest, CopySharedQuadState) {
gfx::Rect clip_rect(19, 21, 23, 25);
bool is_clipped = true;
float opacity = 0.25f;
+ SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode;
scoped_ptr<SharedQuadState> state(SharedQuadState::Create());
state->SetAll(quad_transform,
@@ -43,7 +44,8 @@ TEST(DrawQuadTest, CopySharedQuadState) {
visible_content_rect,
clip_rect,
is_clipped,
- opacity);
+ opacity,
+ blend_mode);
scoped_ptr<SharedQuadState> copy(state->Copy());
EXPECT_EQ(quad_transform, copy->content_to_target_transform);
@@ -51,6 +53,7 @@ TEST(DrawQuadTest, CopySharedQuadState) {
EXPECT_EQ(opacity, copy->opacity);
EXPECT_RECT_EQ(clip_rect, copy->clip_rect);
EXPECT_EQ(is_clipped, copy->is_clipped);
+ EXPECT_EQ(blend_mode, copy->blend_mode);
}
scoped_ptr<SharedQuadState> CreateSharedQuadState() {
@@ -60,6 +63,7 @@ scoped_ptr<SharedQuadState> CreateSharedQuadState() {
gfx::Rect clip_rect(19, 21, 23, 25);
bool is_clipped = false;
float opacity = 1.f;
+ SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
scoped_ptr<SharedQuadState> state(SharedQuadState::Create());
state->SetAll(quad_transform,
@@ -67,7 +71,8 @@ scoped_ptr<SharedQuadState> CreateSharedQuadState() {
visible_content_rect,
clip_rect,
is_clipped,
- opacity);
+ opacity,
+ blend_mode);
return state.Pass();
}
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc
index 394a3ec..e70a33dd 100644
--- a/cc/quads/render_pass_unittest.cc
+++ b/cc/quads/render_pass_unittest.cc
@@ -80,8 +80,13 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) {
// Stick a quad in the pass, this should not get copied.
scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create();
- shared_state->SetAll(
- gfx::Transform(), gfx::Size(), gfx::Rect(), gfx::Rect(), false, 1);
+ shared_state->SetAll(gfx::Transform(),
+ gfx::Size(),
+ gfx::Rect(),
+ gfx::Rect(),
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
pass->AppendSharedQuadState(shared_state.Pass());
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
@@ -126,8 +131,13 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
// Two quads using one shared state.
scoped_ptr<SharedQuadState> shared_state1 = SharedQuadState::Create();
- shared_state1->SetAll(
- gfx::Transform(), gfx::Size(1, 1), gfx::Rect(), gfx::Rect(), false, 1);
+ shared_state1->SetAll(gfx::Transform(),
+ gfx::Size(1, 1),
+ gfx::Rect(),
+ gfx::Rect(),
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
pass->AppendSharedQuadState(shared_state1.Pass());
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad1 =
@@ -144,8 +154,13 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
// And two quads using another shared state.
scoped_ptr<SharedQuadState> shared_state2 = SharedQuadState::Create();
- shared_state2->SetAll(
- gfx::Transform(), gfx::Size(2, 2), gfx::Rect(), gfx::Rect(), false, 1);
+ shared_state2->SetAll(gfx::Transform(),
+ gfx::Size(2, 2),
+ gfx::Rect(),
+ gfx::Rect(),
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
pass->AppendSharedQuadState(shared_state2.Pass());
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad3 =
@@ -176,8 +191,13 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
contrib_has_transparent_background);
scoped_ptr<SharedQuadState> contrib_shared_state = SharedQuadState::Create();
- contrib_shared_state->SetAll(
- gfx::Transform(), gfx::Size(2, 2), gfx::Rect(), gfx::Rect(), false, 1);
+ contrib_shared_state->SetAll(gfx::Transform(),
+ gfx::Size(2, 2),
+ gfx::Rect(),
+ gfx::Rect(),
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
contrib->AppendSharedQuadState(contrib_shared_state.Pass());
scoped_ptr<CheckerboardDrawQuad> contrib_quad =
@@ -228,8 +248,13 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) {
// A shared state with a quad.
scoped_ptr<SharedQuadState> shared_state1 = SharedQuadState::Create();
- shared_state1->SetAll(
- gfx::Transform(), gfx::Size(1, 1), gfx::Rect(), gfx::Rect(), false, 1);
+ shared_state1->SetAll(gfx::Transform(),
+ gfx::Size(1, 1),
+ gfx::Rect(),
+ gfx::Rect(),
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
pass->AppendSharedQuadState(shared_state1.Pass());
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad1 =
@@ -240,20 +265,35 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) {
// A shared state with no quads, they were culled.
scoped_ptr<SharedQuadState> shared_state2 = SharedQuadState::Create();
- shared_state2->SetAll(
- gfx::Transform(), gfx::Size(2, 2), gfx::Rect(), gfx::Rect(), false, 1);
+ shared_state2->SetAll(gfx::Transform(),
+ gfx::Size(2, 2),
+ gfx::Rect(),
+ gfx::Rect(),
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
pass->AppendSharedQuadState(shared_state2.Pass());
// A second shared state with no quads.
scoped_ptr<SharedQuadState> shared_state3 = SharedQuadState::Create();
- shared_state3->SetAll(
- gfx::Transform(), gfx::Size(2, 2), gfx::Rect(), gfx::Rect(), false, 1);
+ shared_state3->SetAll(gfx::Transform(),
+ gfx::Size(2, 2),
+ gfx::Rect(),
+ gfx::Rect(),
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
pass->AppendSharedQuadState(shared_state3.Pass());
// A last shared state with a quad again.
scoped_ptr<SharedQuadState> shared_state4 = SharedQuadState::Create();
- shared_state4->SetAll(
- gfx::Transform(), gfx::Size(2, 2), gfx::Rect(), gfx::Rect(), false, 1);
+ shared_state4->SetAll(gfx::Transform(),
+ gfx::Size(2, 2),
+ gfx::Rect(),
+ gfx::Rect(),
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
pass->AppendSharedQuadState(shared_state4.Pass());
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad2 =
diff --git a/cc/quads/shared_quad_state.cc b/cc/quads/shared_quad_state.cc
index 6a53d9f..56584577 100644
--- a/cc/quads/shared_quad_state.cc
+++ b/cc/quads/shared_quad_state.cc
@@ -10,7 +10,8 @@
namespace cc {
-SharedQuadState::SharedQuadState() : is_clipped(false), opacity(0.f) {}
+SharedQuadState::SharedQuadState()
+ : is_clipped(false), opacity(0.f), blend_mode(SkXfermode::kSrcOver_Mode) {}
SharedQuadState::~SharedQuadState() {
TRACE_EVENT_OBJECT_DELETED_WITH_ID(
@@ -26,19 +27,20 @@ scoped_ptr<SharedQuadState> SharedQuadState::Copy() const {
return make_scoped_ptr(new SharedQuadState(*this));
}
-void SharedQuadState::SetAll(
- const gfx::Transform& content_to_target_transform,
- gfx::Size content_bounds,
- gfx::Rect visible_content_rect,
- gfx::Rect clip_rect,
- bool is_clipped,
- float opacity) {
+void SharedQuadState::SetAll(const gfx::Transform& content_to_target_transform,
+ gfx::Size content_bounds,
+ gfx::Rect visible_content_rect,
+ gfx::Rect clip_rect,
+ bool is_clipped,
+ float opacity,
+ SkXfermode::Mode blend_mode) {
this->content_to_target_transform = content_to_target_transform;
this->content_bounds = content_bounds;
this->visible_content_rect = visible_content_rect;
this->clip_rect = clip_rect;
this->is_clipped = is_clipped;
this->opacity = opacity;
+ this->blend_mode = blend_mode;
}
scoped_ptr<base::Value> SharedQuadState::AsValue() const {
@@ -52,6 +54,7 @@ scoped_ptr<base::Value> SharedQuadState::AsValue() const {
value->SetBoolean("is_clipped", is_clipped);
value->Set("clip_rect", MathUtil::AsValue(clip_rect).release());
value->SetDouble("opacity", opacity);
+ value->SetString("blend_mode", SkXfermode::ModeName(blend_mode));
TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"),
value.get(), "cc::SharedQuadState", this);
diff --git a/cc/quads/shared_quad_state.h b/cc/quads/shared_quad_state.h
index 79bd09b..b70d4a1 100644
--- a/cc/quads/shared_quad_state.h
+++ b/cc/quads/shared_quad_state.h
@@ -7,6 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
+#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
@@ -28,7 +29,8 @@ class CC_EXPORT SharedQuadState {
gfx::Rect visible_content_rect,
gfx::Rect clip_rect,
bool is_clipped,
- float opacity);
+ float opacity,
+ SkXfermode::Mode blend_mode);
scoped_ptr<base::Value> AsValue() const;
// Transforms from quad's original content space to its target content space.
@@ -41,6 +43,7 @@ class CC_EXPORT SharedQuadState {
gfx::Rect clip_rect;
bool is_clipped;
float opacity;
+ SkXfermode::Mode blend_mode;
private:
SharedQuadState();
diff --git a/cc/test/data/blending_and_filter.png b/cc/test/data/blending_and_filter.png
new file mode 100644
index 0000000..07e7fea
--- /dev/null
+++ b/cc/test/data/blending_and_filter.png
Binary files differ
diff --git a/cc/test/data/blending_transparent.png b/cc/test/data/blending_transparent.png
new file mode 100644
index 0000000..dc20808
--- /dev/null
+++ b/cc/test/data/blending_transparent.png
Binary files differ
diff --git a/cc/test/data/blending_with_root.png b/cc/test/data/blending_with_root.png
new file mode 100644
index 0000000..519c642
--- /dev/null
+++ b/cc/test/data/blending_with_root.png
Binary files differ
diff --git a/cc/test/render_pass_test_common.cc b/cc/test/render_pass_test_common.cc
index 35bc561..4b69a7e 100644
--- a/cc/test/render_pass_test_common.cc
+++ b/cc/test/render_pass_test_common.cc
@@ -90,7 +90,8 @@ void TestRenderPass::AppendOneOfEveryQuadType(
rect,
rect,
false,
- 1);
+ 1,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<cc::CheckerboardDrawQuad> checkerboard_quad =
cc::CheckerboardDrawQuad::Create();
@@ -204,7 +205,13 @@ void TestRenderPass::AppendOneOfEveryQuadType(
AppendQuad(transformed_tile_quad.PassAs<DrawQuad>());
scoped_ptr<cc::SharedQuadState> shared_state2 = cc::SharedQuadState::Create();
- shared_state->SetAll(gfx::Transform(), rect.size(), rect, rect, false, 1);
+ shared_state->SetAll(gfx::Transform(),
+ rect.size(),
+ rect,
+ rect,
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<cc::TileDrawQuad> tile_quad = cc::TileDrawQuad::Create();
tile_quad->SetNew(shared_state2.get(),
diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc
index b2045d7..32e6f48 100644
--- a/cc/test/render_pass_test_utils.cc
+++ b/cc/test/render_pass_test_utils.cc
@@ -36,7 +36,13 @@ SolidColorDrawQuad* AddQuad(TestRenderPass* pass,
AppendQuadsData data(pass->id);
SharedQuadState* shared_state =
quad_sink.UseSharedQuadState(SharedQuadState::Create());
- shared_state->SetAll(gfx::Transform(), rect.size(), rect, rect, false, 1);
+ shared_state->SetAll(gfx::Transform(),
+ rect.size(),
+ rect,
+ rect,
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
quad->SetNew(shared_state, rect, color, false);
SolidColorDrawQuad* quad_ptr = quad.get();
@@ -51,7 +57,13 @@ SolidColorDrawQuad* AddClippedQuad(TestRenderPass* pass,
AppendQuadsData data(pass->id);
SharedQuadState* shared_state =
quad_sink.UseSharedQuadState(SharedQuadState::Create());
- shared_state->SetAll(gfx::Transform(), rect.size(), rect, rect, true, 1);
+ shared_state->SetAll(gfx::Transform(),
+ rect.size(),
+ rect,
+ rect,
+ true,
+ 1,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
quad->SetNew(shared_state, rect, color, false);
SolidColorDrawQuad* quad_ptr = quad.get();
@@ -67,7 +79,8 @@ SolidColorDrawQuad* AddTransformedQuad(TestRenderPass* pass,
AppendQuadsData data(pass->id);
SharedQuadState* shared_state =
quad_sink.UseSharedQuadState(SharedQuadState::Create());
- shared_state->SetAll(transform, rect.size(), rect, rect, false, 1);
+ shared_state->SetAll(
+ transform, rect.size(), rect, rect, false, 1, SkXfermode::kSrcOver_Mode);
scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
quad->SetNew(shared_state, rect, color, false);
SolidColorDrawQuad* quad_ptr = quad.get();
@@ -83,8 +96,13 @@ void AddRenderPassQuad(TestRenderPass* to_pass,
gfx::Rect output_rect = contributing_pass->output_rect;
SharedQuadState* shared_state =
quad_sink.UseSharedQuadState(SharedQuadState::Create());
- shared_state->SetAll(
- gfx::Transform(), output_rect.size(), output_rect, output_rect, false, 1);
+ shared_state->SetAll(gfx::Transform(),
+ output_rect.size(),
+ output_rect,
+ output_rect,
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
quad->SetNew(shared_state, output_rect, contributing_pass->id, false, 0,
output_rect, gfx::RectF(), FilterOperations(),
@@ -103,8 +121,13 @@ void AddRenderPassQuad(TestRenderPass* to_pass,
gfx::Rect output_rect = contributing_pass->output_rect;
SharedQuadState* shared_state =
quad_sink.UseSharedQuadState(SharedQuadState::Create());
- shared_state->SetAll(
- transform, output_rect.size(), output_rect, output_rect, false, 1);
+ shared_state->SetAll(transform,
+ output_rect.size(),
+ output_rect,
+ output_rect,
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode);
scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
quad->SetNew(shared_state, output_rect, contributing_pass->id, false,
mask_resource_id, output_rect, gfx::RectF(), filters,
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 784b3db..453a6f3 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -587,6 +587,19 @@ static bool SubtreeShouldRenderToSeparateSurface(
return true;
}
+ // If the layer has blending.
+ // TODO(rosca): this is temporary, until blending is implemented for other
+ // types of quads than RenderPassDrawQuad. Layers having descendants that draw
+ // content will still create a separate rendering surface.
+ if (!layer->uses_default_blend_mode()) {
+ TRACE_EVENT_INSTANT0(
+ "cc",
+ "LayerTreeHostCommon::SubtreeShouldRenderToSeparateSurface blending",
+ TRACE_EVENT_SCOPE_THREAD);
+ DCHECK(!is_root);
+ return true;
+ }
+
// If the layer clips its descendants but it is not axis-aligned with respect
// to its parent.
bool layer_clips_external_content =
@@ -629,6 +642,19 @@ static bool SubtreeShouldRenderToSeparateSurface(
// be used as a contributing surface in order to apply correctly.
//
+ // If the layer has isolation.
+ // TODO(rosca): to be optimized - create separate rendering surface only when
+ // the blending descendants might have access to the content behind this layer
+ // (layer has transparent background or descendants overflow).
+ // https://code.google.com/p/chromium/issues/detail?id=301738
+ if (layer->is_root_for_isolated_group()) {
+ TRACE_EVENT_INSTANT0(
+ "cc",
+ "LayerTreeHostCommon::SubtreeShouldRenderToSeparateSurface isolation",
+ TRACE_EVENT_SCOPE_THREAD);
+ return true;
+ }
+
// If we force it.
if (layer->force_render_surface())
return true;
@@ -2034,6 +2060,16 @@ static void CalculateDrawPropertiesInternal(
return;
}
+ // Layers having a non-default blend mode will blend with the content
+ // inside its parent's render target. This render target should be
+ // either root_for_isolated_group, or the root of the layer tree.
+ // Otherwise, this layer will use an incomplete backdrop, limited to its
+ // render target and the blending result will be incorrect.
+ DCHECK(layer->uses_default_blend_mode() || IsRootLayer(layer) ||
+ !layer->parent()->render_target() ||
+ IsRootLayer(layer->parent()->render_target()) ||
+ layer->parent()->render_target()->is_root_for_isolated_group());
+
render_surface->SetContentRect(clipped_content_rect);
// The owning layer's screen_space_transform has a scale from content to
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 9485c72..8a01b80 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -626,7 +626,8 @@ static void AppendQuadsToFillScreen(
root_target_rect,
root_target_rect,
false,
- opacity);
+ opacity,
+ SkXfermode::kSrcOver_Mode);
AppendQuadsData append_quads_data;
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
new file mode 100644
index 0000000..7a492a1
--- /dev/null
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -0,0 +1,120 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/solid_color_layer.h"
+#include "cc/layers/texture_layer.h"
+#include "cc/test/layer_tree_pixel_test.h"
+
+#if !defined(OS_ANDROID)
+
+namespace cc {
+namespace {
+
+SkXfermode::Mode const kBlendModes[] = {
+ SkXfermode::kSrcOver_Mode, SkXfermode::kScreen_Mode,
+ SkXfermode::kOverlay_Mode, SkXfermode::kDarken_Mode,
+ SkXfermode::kLighten_Mode, SkXfermode::kColorDodge_Mode,
+ SkXfermode::kColorBurn_Mode, SkXfermode::kHardLight_Mode,
+ SkXfermode::kSoftLight_Mode, SkXfermode::kDifference_Mode,
+ SkXfermode::kExclusion_Mode, SkXfermode::kMultiply_Mode,
+ SkXfermode::kHue_Mode, SkXfermode::kSaturation_Mode,
+ SkXfermode::kColor_Mode, SkXfermode::kLuminosity_Mode};
+
+const int kBlendModesCount = arraysize(kBlendModes);
+
+class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
+ protected:
+ void RunBlendingWithRootPixelTestType(PixelTestType type) {
+ const int kLaneWidth = 15;
+ const int kLaneHeight = kBlendModesCount * kLaneWidth;
+ const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange);
+
+ // Orange child layers will blend with the green background
+ for (int i = 0; i < kBlendModesCount; ++i) {
+ gfx::Rect child_rect(
+ (i + 1) * kLaneWidth, kLaneWidth, kLaneWidth, kLaneHeight);
+ scoped_refptr<SolidColorLayer> green_lane =
+ CreateSolidColorLayer(child_rect, kCSSGreen);
+ background->AddChild(green_lane);
+ green_lane->SetBlendMode(kBlendModes[i]);
+ }
+
+ RunPixelTest(type,
+ background,
+ base::FilePath(FILE_PATH_LITERAL("blending_with_root.png")));
+ }
+
+ void RunBlendingWithTransparentPixelTestType(PixelTestType type) {
+ const int kLaneWidth = 15;
+ const int kLaneHeight = kBlendModesCount * kLaneWidth;
+ const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+
+ scoped_refptr<SolidColorLayer> root =
+ CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSBrown);
+
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(0, kLaneWidth * 2, kRootSize, kLaneWidth), kCSSOrange);
+
+ root->AddChild(background);
+ background->SetIsRootForIsolatedGroup(true);
+
+ // Orange child layers will blend with the green background
+ for (int i = 0; i < kBlendModesCount; ++i) {
+ gfx::Rect child_rect(
+ (i + 1) * kLaneWidth, -kLaneWidth, kLaneWidth, kLaneHeight);
+ scoped_refptr<SolidColorLayer> green_lane =
+ CreateSolidColorLayer(child_rect, kCSSGreen);
+ background->AddChild(green_lane);
+ green_lane->SetBlendMode(kBlendModes[i]);
+ }
+
+ RunPixelTest(type,
+ root,
+ base::FilePath(FILE_PATH_LITERAL("blending_transparent.png")));
+ }
+};
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) {
+ RunBlendingWithRootPixelTestType(GL_WITH_BITMAP);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) {
+ const int kLaneWidth = 15;
+ const int kLaneHeight = kBlendModesCount * kLaneWidth;
+ const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange);
+
+ // Orange child layers have a background filter set and they will blend with
+ // the green background
+ for (int i = 0; i < kBlendModesCount; ++i) {
+ gfx::Rect child_rect(
+ (i + 1) * kLaneWidth, kLaneWidth, kLaneWidth, kLaneHeight);
+ scoped_refptr<SolidColorLayer> green_lane =
+ CreateSolidColorLayer(child_rect, kCSSGreen);
+ background->AddChild(green_lane);
+
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateGrayscaleFilter(.75));
+ green_lane->SetBackgroundFilters(filters);
+ green_lane->SetBlendMode(kBlendModes[i]);
+ }
+
+ RunPixelTest(GL_WITH_BITMAP,
+ background,
+ base::FilePath(FILE_PATH_LITERAL("blending_and_filter.png")));
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_GL) {
+ RunBlendingWithTransparentPixelTestType(GL_WITH_BITMAP);
+}
+
+} // namespace
+} // namespace cc
+
+#endif // OS_ANDROID
diff --git a/cc/trees/layer_tree_host_unittest_occlusion.cc b/cc/trees/layer_tree_host_unittest_occlusion.cc
index 9300f30..621d23d 100644
--- a/cc/trees/layer_tree_host_unittest_occlusion.cc
+++ b/cc/trees/layer_tree_host_unittest_occlusion.cc
@@ -346,6 +346,74 @@ class LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion);
+class LayerTreeHostOcclusionTestOcclusionBlending
+ : public LayerTreeHostOcclusionTest {
+ public:
+ virtual void SetupTree() OVERRIDE {
+ // If the child layer has a blend mode, then it shouldn't
+ // contribute to occlusion on stuff below it
+ SetLayerPropertiesForTesting(
+ root_.get(), NULL, identity_matrix_,
+ gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
+ SetLayerPropertiesForTesting(
+ child2_.get(), root_.get(), identity_matrix_,
+ gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
+ SetLayerPropertiesForTesting(
+ child_.get(), root_.get(), identity_matrix_,
+ gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
+ SetLayerPropertiesForTesting(
+ grand_child_.get(), child_.get(), identity_matrix_,
+ gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
+
+ child_->SetMasksToBounds(true);
+ child_->SetBlendMode(SkXfermode::kMultiply_Mode);
+ child_->SetForceRenderSurface(true);
+
+ child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
+ root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
+
+ layer_tree_host()->SetRootLayer(root_);
+ LayerTreeTest::SetupTree();
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionBlending);
+
+class LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion
+ : public LayerTreeHostOcclusionTest {
+ public:
+ virtual void SetupTree() OVERRIDE {
+ // If the child layer with a blend mode is below child2, then
+ // child2 should contribute to occlusion on everything, and child shouldn't
+ // contribute to the root_.
+ SetLayerPropertiesForTesting(
+ root_.get(), NULL, identity_matrix_,
+ gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
+ SetLayerPropertiesForTesting(
+ child_.get(), root_.get(), identity_matrix_,
+ gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
+ SetLayerPropertiesForTesting(
+ grand_child_.get(), child_.get(), identity_matrix_,
+ gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
+ SetLayerPropertiesForTesting(
+ child2_.get(), root_.get(), identity_matrix_,
+ gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
+
+ child_->SetMasksToBounds(true);
+ child_->SetBlendMode(SkXfermode::kMultiply_Mode);
+
+ grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
+ child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
+ root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
+
+ layer_tree_host()->SetRootLayer(root_);
+ LayerTreeTest::SetupTree();
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion);
+
class LayerTreeHostOcclusionTestOcclusionOpacityFilter
: public LayerTreeHostOcclusionTest {
public:
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc
index 09fc114..1c6c8a0 100644
--- a/cc/trees/occlusion_tracker.cc
+++ b/cc/trees/occlusion_tracker.cc
@@ -224,9 +224,9 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget(
// If the occlusion within the surface can not be applied to things outside of
// the surface's subtree, then clear the occlusion here so it won't be used.
- if (finished_target->mask_layer() ||
- !SurfaceOpacityKnown(surface) ||
+ if (finished_target->mask_layer() || !SurfaceOpacityKnown(surface) ||
surface->draw_opacity() < 1 ||
+ !finished_target->uses_default_blend_mode() ||
target_is_only_for_copy_request ||
finished_target->filters().HasFilterThatAffectsOpacity()) {
stack_.back().occlusion_from_outside_target.Clear();
@@ -405,6 +405,9 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::
if (!LayerOpacityKnown(layer) || layer->draw_opacity() < 1)
return;
+ if (!layer->uses_default_blend_mode())
+ return;
+
if (LayerIsInUnsorted3dRenderingContext(layer))
return;