Chromium Code Reviews| Index: cc/output/gl_renderer.cc |
| diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc |
| index acd7bf2c2d86a5679bd4f9584e35f4d7061ab350..b2502d9bcbc2086b0619b838c319f90fc17ad09a 100644 |
| --- a/cc/output/gl_renderer.cc |
| +++ b/cc/output/gl_renderer.cc |
| @@ -56,6 +56,7 @@ |
| #include "third_party/skia/include/gpu/gl/GrGLInterface.h" |
| #include "ui/gfx/geometry/quad_f.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| +#include "ui/gfx/skia_util.h" |
| using gpu::gles2::GLES2Interface; |
| @@ -601,7 +602,8 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame, |
| static skia::RefPtr<SkImage> ApplyImageFilter( |
| scoped_ptr<GLRenderer::ScopedUseGrContext> use_gr_context, |
| ResourceProvider* resource_provider, |
| - const gfx::Rect& rect, |
| + const gfx::RectF& src_rect, |
| + const gfx::RectF& dst_rect, |
| const gfx::Vector2dF& scale, |
| SkImageFilter* filter, |
| ScopedResource* source_texture_resource) { |
| @@ -634,7 +636,7 @@ static skia::RefPtr<SkImage> ApplyImageFilter( |
| // Create surface to draw into. |
| SkImageInfo dst_info = |
| - SkImageInfo::MakeN32Premul(srcImage->width(), srcImage->height()); |
| + SkImageInfo::MakeN32Premul(dst_rect.width(), dst_rect.height()); |
| skia::RefPtr<SkSurface> surface = skia::AdoptRef(SkSurface::NewRenderTarget( |
| use_gr_context->context(), SkSurface::kYes_Budgeted, dst_info, 0)); |
| if (!surface) { |
| @@ -647,17 +649,17 @@ static skia::RefPtr<SkImage> ApplyImageFilter( |
| // bottom-left, but the orientation is the same, so we must translate the |
| // filter so that it renders at the bottom of the texture to avoid |
| // misregistration. |
| - int y_translate = source_texture_resource->size().height() - rect.height() - |
| - rect.origin().y(); |
| - SkMatrix localM; |
| - localM.setTranslate(-rect.origin().x(), y_translate); |
| - localM.preScale(scale.x(), scale.y()); |
| - skia::RefPtr<SkImageFilter> localIMF = |
| - skia::AdoptRef(filter->newWithLocalMatrix(localM)); |
| + float y_offset = source_texture_resource->size().height() - src_rect.height(); |
| + SkMatrix local_matrix; |
| + local_matrix.setScale(scale.x(), scale.y()); |
| + skia::RefPtr<SkImageFilter> filter_with_local_scale = |
| + skia::AdoptRef(filter->newWithLocalMatrix(local_matrix)); |
| SkPaint paint; |
| - paint.setImageFilter(localIMF.get()); |
| - surface->getCanvas()->drawImage(srcImage.get(), 0, 0, &paint); |
| + paint.setImageFilter(filter_with_local_scale.get()); |
| + surface->getCanvas()->translate(-dst_rect.x(), -dst_rect.y()); |
| + surface->getCanvas()->drawImage(srcImage.get(), src_rect.x(), |
| + src_rect.y() - y_offset, &paint); |
| skia::RefPtr<SkImage> image = skia::AdoptRef(surface->newImageSnapshot()); |
| if (!image || !image->isTextureBacked()) { |
| @@ -822,6 +824,13 @@ gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad( |
| backdrop_rect.Inset(-kOutsetForAntialiasing, -kOutsetForAntialiasing); |
| } |
| + if (!quad->filters.IsEmpty()) { |
| + // If we have filters, grab an extra one-pixel border around the |
| + // background, so texture edge clamping gives us a transparent border |
| + // in case the filter expands the result. |
| + backdrop_rect.Inset(-1, -1, -1, -1); |
| + } |
| + |
| backdrop_rect.Intersect(MoveFromDrawToWindowSpace( |
| frame, frame->current_render_pass->output_rect)); |
| return backdrop_rect; |
| @@ -846,13 +855,14 @@ scoped_ptr<ScopedResource> GLRenderer::GetBackdropTexture( |
| skia::RefPtr<SkImage> GLRenderer::ApplyBackgroundFilters( |
| DrawingFrame* frame, |
| const RenderPassDrawQuad* quad, |
| - ScopedResource* background_texture) { |
| + ScopedResource* background_texture, |
| + const gfx::RectF& rect) { |
| DCHECK(ShouldApplyBackgroundFilters(quad)); |
| skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( |
| quad->background_filters, gfx::SizeF(background_texture->size())); |
| skia::RefPtr<SkImage> background_with_filters = ApplyImageFilter( |
| - ScopedUseGrContext::Create(this, frame), resource_provider_, quad->rect, |
| + ScopedUseGrContext::Create(this, frame), resource_provider_, rect, rect, |
| quad->filters_scale, filter.get(), background_texture); |
| return background_with_filters; |
| } |
| @@ -925,8 +935,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
| if (ShouldApplyBackgroundFilters(quad) && background_texture) { |
| // Apply the background filters to R, so that it is applied in the |
| // pixels' coordinate space. |
| - background_image = |
| - ApplyBackgroundFilters(frame, quad, background_texture.get()); |
| + background_image = ApplyBackgroundFilters( |
| + frame, quad, background_texture.get(), gfx::RectF(background_rect)); |
| if (background_image) |
| background_image_id = background_image->getTextureHandle(true); |
| DCHECK(background_image_id); |
| @@ -963,6 +973,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
| GLuint filter_image_id = 0; |
| SkScalar color_matrix[20]; |
| bool use_color_matrix = false; |
| + gfx::RectF rect = gfx::RectF(quad->rect); |
| if (!quad->filters.IsEmpty()) { |
| skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( |
| quad->filters, gfx::SizeF(contents_texture->size())); |
| @@ -980,9 +991,28 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
| // in the compositor. |
| use_color_matrix = true; |
| } else { |
| - filter_image = ApplyImageFilter( |
| - ScopedUseGrContext::Create(this, frame), resource_provider_, |
| - quad->rect, quad->filters_scale, filter.get(), contents_texture); |
| + gfx::RectF src_rect = rect; |
| + gfx::Vector2dF scale = quad->filters_scale; |
| + // Compute the destination rect for the filtered output. |
| + // Note that we leave the dest rect equal to the src rect when |
| + // a filter chain cannot compute its bounds. This is correct |
| + // behaviour, but Skia is a little conservative at the moment. |
| + // Once Skia makes the fast-bounds traversal crop-rect aware |
| + // (http://skbug.com/4627), this won't be a problem |
| + // for Chrome since Blink always sets a crop rect on the leaf nodes |
| + // of the DAG, making it always computable. |
| + // TODO(senorblanco): remove this comment when http://skbug.com/4627 |
|
enne (OOO)
2016/01/20 22:59:29
Thanks for this. :)
|
| + // is fixed. |
| + if (filter->canComputeFastBounds()) { |
| + SkRect result_rect; |
| + rect.Scale(1.0f / scale.x(), 1.0f / scale.y()); |
| + filter->computeFastBounds(gfx::RectFToSkRect(rect), &result_rect); |
| + rect = gfx::SkRectToRectF(result_rect); |
| + rect.Scale(scale.x(), scale.y()); |
| + } |
| + filter_image = ApplyImageFilter(ScopedUseGrContext::Create(this, frame), |
| + resource_provider_, src_rect, rect, |
| + scale, filter.get(), contents_texture); |
| if (filter_image) { |
| filter_image_id = filter_image->getTextureHandle(true); |
| DCHECK(filter_image_id); |
| @@ -1096,10 +1126,16 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
| program->fragment_shader().FillLocations(&locations); |
| gl_->Uniform1i(locations.sampler, 0); |
| } |
| - float tex_scale_x = |
| - quad->rect.width() / static_cast<float>(contents_texture->size().width()); |
| - float tex_scale_y = quad->rect.height() / |
| - static_cast<float>(contents_texture->size().height()); |
| + float tex_scale_x, tex_scale_y; |
| + if (filter_image) { |
| + // Skia filters always return SkImages with snug textures. |
| + tex_scale_x = tex_scale_y = 1.0f; |
| + } else { |
| + tex_scale_x = quad->rect.width() / |
| + static_cast<float>(contents_texture->size().width()); |
| + tex_scale_y = quad->rect.height() / |
| + static_cast<float>(contents_texture->size().height()); |
| + } |
| DCHECK_LE(tex_scale_x, 1.0f); |
| DCHECK_LE(tex_scale_y, 1.0f); |
| @@ -1197,7 +1233,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
| SetShaderOpacity(quad->shared_quad_state->opacity, locations.alpha); |
| SetShaderQuadF(surface_quad, locations.quad); |
| DrawQuadGeometry(frame, quad->shared_quad_state->quad_to_target_transform, |
| - gfx::RectF(quad->rect), locations.matrix); |
| + rect, locations.matrix); |
| // Flush the compositor context before the filter bitmap goes out of |
| // scope, so the draw gets processed before the filter texture gets deleted. |