diff options
author | ajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-01 22:08:00 +0000 |
---|---|---|
committer | ajuma@chromium.org <ajuma@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-01 22:08:00 +0000 |
commit | 52844912b438f8c6609a25a42b9807f6a924e690 (patch) | |
tree | c68f195cf23fb4b4ef4fb8067ecab940797ea379 /cc | |
parent | 68d1dd345e06e259a086c2ccc186f7f260bbf0d0 (diff) | |
download | chromium_src-52844912b438f8c6609a25a42b9807f6a924e690.zip chromium_src-52844912b438f8c6609a25a42b9807f6a924e690.tar.gz chromium_src-52844912b438f8c6609a25a42b9807f6a924e690.tar.bz2 |
Enable general CSS filters in the software compositor
The software compositor has only supported filters that include a
reference filter. This CL enables support for filters that don't
include a reference filter.
BUG=160302
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=229569
Review URL: https://codereview.chromium.org/24090003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232476 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/output/renderer_pixeltest.cc | 159 | ||||
-rw-r--r-- | cc/output/software_renderer.cc | 46 | ||||
-rw-r--r-- | cc/test/data/blue_yellow_filter_chain.png | bin | 0 -> 598 bytes | |||
-rw-r--r-- | cc/trees/layer_tree_host_pixeltest_filters.cc | 95 |
4 files changed, 245 insertions, 55 deletions
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc index e321fab..45615c0 100644 --- a/cc/output/renderer_pixeltest.cc +++ b/cc/output/renderer_pixeltest.cc @@ -651,6 +651,165 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) { FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false))); } +TYPED_TEST(RendererPixelTest, FastPassSaturateFilter) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + shared_state->opacity = 0.5f; + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorBLUE, + false); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(0, + this->device_viewport_size_.height() / 2, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorYELLOW, + false); + + scoped_ptr<SharedQuadState> blank_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew(blank_state.get(), + viewport_rect, + SK_ColorWHITE, + false); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + + FilterOperations filters; + filters.Append(FilterOperation::CreateSaturateFilter(0.5f)); + + scoped_ptr<RenderPassDrawQuad> render_pass_quad = + RenderPassDrawQuad::Create(); + render_pass_quad->SetNew(pass_shared_state.get(), + pass_rect, + child_pass_id, + false, + 0, + pass_rect, + gfx::RectF(), + filters, + FilterOperations()); + + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + PixelTest::NoOffscreenContext, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")), + ExactPixelComparator(true))); +} + +TYPED_TEST(RendererPixelTest, FastPassFilterChain) { + gfx::Rect viewport_rect(this->device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(this->device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + shared_state->opacity = 0.5f; + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorBLUE, + false); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(0, + this->device_viewport_size_.height() / 2, + this->device_viewport_size_.width(), + this->device_viewport_size_.height() / 2), + SK_ColorYELLOW, + false); + + scoped_ptr<SharedQuadState> blank_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew(blank_state.get(), + viewport_rect, + SK_ColorWHITE, + false); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + + FilterOperations filters; + filters.Append(FilterOperation::CreateGrayscaleFilter(1.f)); + filters.Append(FilterOperation::CreateBrightnessFilter(0.5f)); + + scoped_ptr<RenderPassDrawQuad> render_pass_quad = + RenderPassDrawQuad::Create(); + render_pass_quad->SetNew(pass_shared_state.get(), + pass_rect, + child_pass_id, + false, + 0, + pass_rect, + gfx::RectF(), + filters, + FilterOperations()); + + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + EXPECT_TRUE(this->RunPixelTest( + &pass_list, + PixelTest::NoOffscreenContext, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")), + ExactPixelComparator(true))); +} + TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) { gfx::Rect viewport_rect(this->device_viewport_size_); diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index 9bc3cda..7a932cc 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc @@ -435,22 +435,46 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, SkMatrix::kFill_ScaleToFit); const SkBitmap* content = lock.sk_bitmap(); - skia::RefPtr<SkShader> shader = skia::AdoptRef( - SkShader::CreateBitmapShader(*content, - SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode)); - shader->setLocalMatrix(content_mat); - current_paint_.setShader(shader.get()); - // TODO(ajuma): Remove this condition once general CSS filters are working - // correctly (http://crbug.com/160302), and add corresponding pixel tests. - if (quad->filters.HasReferenceFilter()) { + SkBitmap filter_bitmap; + if (!quad->filters.IsEmpty()) { skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( quad->filters, content_texture->size()); - if (filter) - current_paint_.setImageFilter(filter.get()); + // TODO(ajuma): In addition origin translation, the canvas should also be + // scaled to accomodate device pixel ratio and pinch zoom. See + // crbug.com/281516 and crbug.com/281518. + // TODO(ajuma): Apply the filter in the same pass as the content where + // possible (e.g. when there's no origin offset). See crbug.com/308201. + if (filter) { + bool is_opaque = false; + skia::RefPtr<SkBaseDevice> device = + skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config, + content_texture->size().width(), + content_texture->size().height(), + is_opaque)); + SkCanvas canvas(device.get()); + SkPaint paint; + paint.setImageFilter(filter.get()); + canvas.clear(SK_ColorTRANSPARENT); + canvas.translate(SkIntToScalar(-quad->rect.origin().x()), + SkIntToScalar(-quad->rect.origin().y())); + canvas.drawSprite(*content, 0, 0, &paint); + bool will_change_pixels = false; + filter_bitmap = device->accessBitmap(will_change_pixels); + } } + skia::RefPtr<SkShader> shader; + if (filter_bitmap.isNull()) { + shader = skia::AdoptRef(SkShader::CreateBitmapShader( + *content, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)); + } else { + shader = skia::AdoptRef(SkShader::CreateBitmapShader( + filter_bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)); + } + shader->setLocalMatrix(content_mat); + current_paint_.setShader(shader.get()); + if (quad->mask_resource_id) { ResourceProvider::ScopedReadLockSoftware mask_lock(resource_provider_, quad->mask_resource_id); diff --git a/cc/test/data/blue_yellow_filter_chain.png b/cc/test/data/blue_yellow_filter_chain.png Binary files differnew file mode 100644 index 0000000..6ef1e90 --- /dev/null +++ b/cc/test/data/blue_yellow_filter_chain.png diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc index 604eabb..d2a6507f9 100644 --- a/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/cc/trees/layer_tree_host_pixeltest_filters.cc @@ -150,51 +150,58 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) { "background_filter_blur_off_axis.png"))); } -TEST_F(LayerTreeHostFiltersPixelTest, ImageFilterClipped) { - scoped_refptr<SolidColorLayer> root = CreateSolidColorLayer( - gfx::Rect(200, 200), SK_ColorBLACK); - - scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( - gfx::Rect(200, 200), SK_ColorYELLOW); - root->AddChild(background); - - scoped_refptr<SolidColorLayer> foreground = CreateSolidColorLayer( - gfx::Rect(200, 200), SK_ColorRED); - background->AddChild(foreground); - - SkScalar matrix[20]; - memset(matrix, 0, 20 * sizeof(matrix[0])); - // This filter does a red-blue swap, so the foreground becomes blue. - matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1; - skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef( - new SkColorMatrixFilter(matrix))); - // We filter only the bottom 200x100 pixels of the foreground. - SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100)); - skia::RefPtr<SkImageFilter> filter = - skia::AdoptRef(SkColorFilterImageFilter::Create( - colorFilter.get(), - NULL, - &crop_rect)); - FilterOperations filters; - filters.Append(FilterOperation::CreateReferenceFilter(filter)); - - // Make the foreground layer's render surface be clipped by the background - // layer. - background->SetMasksToBounds(true); - foreground->SetFilters(filters); - - // Then we translate the foreground up by 100 pixels in Y, so the cropped - // region is moved to to the top. This ensures that the crop rect is being - // correctly transformed in skia by the amount of clipping that the - // compositor performs. - gfx::Transform transform; - transform.Translate(0.0, -100.0); - foreground->SetTransform(transform); +class ImageFilterClippedPixelTest : public LayerTreeHostFiltersPixelTest { + protected: + void RunPixelTestType(PixelTestType test_type) { + scoped_refptr<SolidColorLayer> root = + CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK); + + scoped_refptr<SolidColorLayer> background = + CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorYELLOW); + root->AddChild(background); + + scoped_refptr<SolidColorLayer> foreground = + CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorRED); + background->AddChild(foreground); + + SkScalar matrix[20]; + memset(matrix, 0, 20 * sizeof(matrix[0])); + // This filter does a red-blue swap, so the foreground becomes blue. + matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1; + skia::RefPtr<SkColorFilter> colorFilter( + skia::AdoptRef(new SkColorMatrixFilter(matrix))); + // We filter only the bottom 200x100 pixels of the foreground. + SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100)); + skia::RefPtr<SkImageFilter> filter = skia::AdoptRef( + SkColorFilterImageFilter::Create(colorFilter.get(), NULL, &crop_rect)); + FilterOperations filters; + filters.Append(FilterOperation::CreateReferenceFilter(filter)); + + // Make the foreground layer's render surface be clipped by the background + // layer. + background->SetMasksToBounds(true); + foreground->SetFilters(filters); + + // Then we translate the foreground up by 100 pixels in Y, so the cropped + // region is moved to to the top. This ensures that the crop rect is being + // correctly transformed in skia by the amount of clipping that the + // compositor performs. + gfx::Transform transform; + transform.Translate(0.0, -100.0); + foreground->SetTransform(transform); + + RunPixelTest(test_type, + background, + base::FilePath(FILE_PATH_LITERAL("blue_yellow.png"))); + } +}; + +TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_GL) { + RunPixelTestType(GL_WITH_BITMAP); +} - RunPixelTest(GL_WITH_BITMAP, - background, - base::FilePath(FILE_PATH_LITERAL( - "blue_yellow.png"))); +TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_Software) { + RunPixelTestType(SOFTWARE_WITH_BITMAP); } } // namespace |