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. |