Chromium Code Reviews| Index: content/renderer/webplugin_delegate_proxy.cc |
| =================================================================== |
| --- content/renderer/webplugin_delegate_proxy.cc (revision 166499) |
| +++ content/renderer/webplugin_delegate_proxy.cc (working copy) |
| @@ -48,6 +48,7 @@ |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/native_widget_types.h" |
| #include "ui/gfx/size.h" |
| +#include "ui/gfx/skia_util.h" |
| #include "webkit/glue/webkit_glue.h" |
| #include "webkit/plugins/npapi/webplugin.h" |
| #include "webkit/plugins/plugin_constants.h" |
| @@ -402,6 +403,7 @@ |
| (silverlight && LowerCaseEqualsASCII(arg_names[i], "background") && |
| SilverlightColorIsTransparent(arg_values[i]))) { |
| transparent_ = true; |
| + RenderThread::Get()->RecordUserMetrics("Plugin_Transparent"); |
| } |
| } |
| params.load_manually = load_manually; |
| @@ -409,8 +411,7 @@ |
| plugin_ = plugin; |
| result = false; |
| - IPC::Message* msg = new PluginMsg_Init(instance_id_, params, &result); |
| - Send(msg); |
| + Send(new PluginMsg_Init(instance_id_, params, &result)); |
| if (!result) |
| LOG(ERROR) << "PluginMsg_Init returned false"; |
| @@ -668,6 +669,12 @@ |
| ResetWindowlessBitmaps(); |
| return; |
| } |
| + |
| + if (needs_background_store && |
| + render_view_->is_accelerated_compositing_active()) { |
| + // Better than grabage... |
| + background_store_.canvas->drawColor(SK_ColorWHITE); |
|
piman
2012/11/09 19:27:03
How about writing transparent pixels? If the plugi
jam
2012/11/09 22:50:24
Thanks, actually trying this out shows that NPAPI
|
| + } |
| } |
| } |
| } |
| @@ -762,40 +769,28 @@ |
| if (!front_buffer_canvas()) |
| return; |
| - // We're using the native OS APIs from here on out. |
| - if (!skia::SupportsPlatformPaint(canvas)) { |
| - // TODO(alokp): Implement this path. |
| - // This block will only get hit with --enable-accelerated-drawing flag. |
| - // With accelerated canvas, we do not have a bitmap that can be provided |
| - // to the plugin for compositing. We may have to implement a solution |
| - // described in crbug.com/12586. |
| - DLOG(WARNING) << "Could not paint plugin"; |
| - return; |
| - } |
| - skia::ScopedPlatformPaint scoped_platform_paint(canvas); |
| - gfx::NativeDrawingContext context = |
| - scoped_platform_paint.GetPlatformSurface(); |
| - |
| gfx::Rect offset_rect = rect; |
| offset_rect.Offset(-plugin_rect_.x(), -plugin_rect_.y()); |
| - gfx::Rect canvas_rect = offset_rect; |
| -#if defined(OS_MACOSX) |
| - // The canvases are flipped relative to the context, so flip the rect too. |
| - FlipRectVerticallyWithHeight(&canvas_rect, plugin_rect_.height()); |
| -#endif |
| bool background_changed = false; |
| - if (background_store_.canvas.get() && BackgroundChanged(context, rect)) { |
| + if (background_store_.canvas.get() && BackgroundChanged(canvas, rect) && |
| + // When accelerated compositing is used we don't have access to the |
| + // page data under the plugin. This might result in painting glitches, |
| + // but there's nothing we can do about that. This is mostly mitigiated |
|
piman
2012/11/09 19:27:03
typo: mitigated
|
| + // by the fact that this is only for NPAPI plugins, and for Flash we use |
| + // Pepper. |
| + !render_view_->is_accelerated_compositing_active()) { |
| background_changed = true; |
| - BlitContextToCanvas(background_store_.canvas.get(), canvas_rect, |
| - context, rect.origin()); |
| + SkIRect src_rect = gfx::RectToSkIRect(rect); |
| + background_store_.canvas->drawBitmapRect( |
| + canvas->getDevice()->accessBitmap(false), |
| + &src_rect, gfx::RectToSkRect(offset_rect)); |
|
jam
2012/11/09 19:02:25
btw I found that somehow this isn't working on Lin
piman
2012/11/09 19:27:03
I'm not sure specifically, but I was going to ment
|
| } |
| // transport_store_painted_ is really a bounding box, so in principle this |
| // check could falsely indicate that we don't need to paint offset_rect, but |
| // in practice it works fine. |
| - if (background_changed || |
| - !transport_store_painted_.Contains(offset_rect)) { |
| + if (background_changed || !transport_store_painted_.Contains(offset_rect)) { |
| Send(new PluginMsg_Paint(instance_id_, offset_rect)); |
| // Since the plugin is not blocked on the renderer in this context, there is |
| // a chance that it will begin repainting the back-buffer before we complete |
| @@ -805,20 +800,15 @@ |
| UpdateFrontBuffer(offset_rect, false); |
| } |
| -#if defined(OS_MACOSX) |
| - // The canvases are flipped relative to the context, so flip the context's |
| - // coordinate space so that the blit unflips the content. |
| - CGContextSaveGState(context); |
| - CGContextScaleCTM(context, 1, -1); |
| - rect.set_y(-rect.bottom()); |
| -#endif |
| - BlitCanvasToContext(context, |
| - rect, |
| - front_buffer_canvas(), |
| - offset_rect.origin()); |
| -#if defined(OS_MACOSX) |
| - CGContextRestoreGState(context); |
| -#endif |
| + const SkBitmap& bitmap = |
| + front_buffer_canvas()->getDevice()->accessBitmap(false); |
| + SkPaint paint; |
| + paint.setXfermodeMode(SkXfermode::kSrcATop_Mode); |
| + SkIRect src_rect = gfx::RectToSkIRect(offset_rect); |
| + canvas->drawBitmapRect(bitmap, |
| + &src_rect, |
| + gfx::RectToSkRect(rect), |
| + &paint); |
| if (invalidate_pending_) { |
| // Only send the PaintAck message if this paint is in response to an |
| @@ -829,154 +819,26 @@ |
| } |
| } |
| -bool WebPluginDelegateProxy::BackgroundChanged( |
| - gfx::NativeDrawingContext context, |
| - const gfx::Rect& rect) { |
| -#if defined(OS_ANDROID) |
| - NOTIMPLEMENTED(); |
| -#else |
| -#if defined(OS_WIN) |
|
piman
2012/11/09 19:27:03
Awesome thanks for removing this horrible per-plat
|
| - HBITMAP hbitmap = static_cast<HBITMAP>(GetCurrentObject(context, OBJ_BITMAP)); |
| - if (hbitmap == NULL) { |
| - NOTREACHED(); |
| - return true; |
| - } |
| +bool WebPluginDelegateProxy::BackgroundChanged(SkCanvas* canvas, |
| + const gfx::Rect& rect) { |
| + const SkMatrix& matrix = canvas->getTotalMatrix(); |
| + const SkBitmap& page = canvas->getDevice()->accessBitmap(false); |
| + const SkBitmap& background = |
| + background_store_.canvas->getDevice()->accessBitmap(false); |
| + CHECK(page.bytesPerPixel() == background.bytesPerPixel()); |
| + int row_byte_size = rect.width() * page.bytesPerPixel(); |
|
piman
2012/11/09 19:27:03
This can get tricky with CSS transforms, in partic
|
| + for (int y = rect.y(); y < rect.bottom(); y++) { |
| + SkPoint result; |
| + matrix.mapXY(SkIntToScalar(rect.x()), SkIntToScalar(y), &result); |
| + uint32_t* page_row_start = page.getAddr32(result.x(), result.y()); |
| - BITMAP bitmap = { 0 }; |
| - int result = GetObject(hbitmap, sizeof(bitmap), &bitmap); |
| - if (!result) { |
| - NOTREACHED(); |
| - return true; |
| - } |
| - |
| - XFORM xf; |
| - if (!GetWorldTransform(context, &xf)) { |
| - NOTREACHED(); |
| - return true; |
| - } |
| - |
| - // The damaged rect that we're given can be larger than the bitmap, so |
| - // intersect their rects first. |
| - gfx::Rect bitmap_rect(static_cast<int>(-xf.eDx), static_cast<int>(-xf.eDy), |
| - bitmap.bmWidth, bitmap.bmHeight); |
| - gfx::Rect check_rect = gfx::IntersectRects(rect, bitmap_rect); |
| - int row_byte_size = check_rect.width() * (bitmap.bmBitsPixel / 8); |
| - for (int y = check_rect.y(); y < check_rect.bottom(); y++) { |
| - char* hdc_row_start = static_cast<char*>(bitmap.bmBits) + |
| - (y + static_cast<int>(xf.eDy)) * bitmap.bmWidthBytes + |
| - (check_rect.x() + static_cast<int>(xf.eDx)) * (bitmap.bmBitsPixel / 8); |
| - |
| // getAddr32 doesn't use the translation units, so we have to subtract |
| // the plugin origin from the coordinates. |
| - uint32_t* canvas_row_start = |
| - background_store_.canvas->getDevice()->accessBitmap(true).getAddr32( |
| - check_rect.x() - plugin_rect_.x(), y - plugin_rect_.y()); |
| - if (memcmp(hdc_row_start, canvas_row_start, row_byte_size) != 0) |
| + uint32_t* background_row_start = background.getAddr32( |
| + rect.x() - plugin_rect_.x(), y - plugin_rect_.y()); |
| + if (memcmp(page_row_start, background_row_start, row_byte_size) != 0) |
| return true; |
| } |
| -#else |
| -#if defined(OS_MACOSX) |
| - // If there is a translation on the content area context, we need to account |
| - // for it; the context may be a subset of the full content area with a |
| - // transform that makes the coordinates work out. |
| - CGAffineTransform transform = CGContextGetCTM(context); |
| - bool flipped = fabs(transform.d + 1) < 0.0001; |
| - CGFloat context_offset_x = -transform.tx; |
| - CGFloat context_offset_y = flipped ? transform.ty - |
| - CGBitmapContextGetHeight(context) |
| - : -transform.ty; |
| - gfx::Rect full_content_rect(context_offset_x, context_offset_y, |
| - CGBitmapContextGetWidth(context), |
| - CGBitmapContextGetHeight(context)); |
| -#else |
| - cairo_surface_t* page_surface = cairo_get_target(context); |
| - DCHECK_EQ(cairo_surface_get_type(page_surface), CAIRO_SURFACE_TYPE_IMAGE); |
| - DCHECK_EQ(cairo_image_surface_get_format(page_surface), CAIRO_FORMAT_ARGB32); |
| - |
| - // Transform context coordinates into surface coordinates. |
| - double page_x_double = 0; |
| - double page_y_double = 0; |
| - cairo_device_to_user(context, &page_x_double, &page_y_double); |
| - gfx::Rect full_content_rect(static_cast<int>(page_x_double), |
| - static_cast<int>(page_y_double), |
| - cairo_image_surface_get_width(page_surface), |
| - cairo_image_surface_get_height(page_surface)); |
| -#endif |
| - // According to comments in the Windows code, the damage rect that we're given |
| - // may project outside the image, so intersect their rects. |
| - gfx::Rect content_rect = gfx::IntersectRects(rect, full_content_rect); |
| - |
| -#if defined(OS_MACOSX) |
| - const unsigned char* page_bytes = static_cast<const unsigned char*>( |
| - CGBitmapContextGetData(context)); |
| - int page_stride = CGBitmapContextGetBytesPerRow(context); |
| - int page_start_x = content_rect.x() - context_offset_x; |
| - int page_start_y = content_rect.y() - context_offset_y; |
| - |
| - skia::ScopedPlatformPaint scoped_platform_paint( |
| - background_store_.canvas.get()); |
| - CGContextRef bg_context = scoped_platform_paint.GetPlatformSurface(); |
| - |
| - DCHECK_EQ(CGBitmapContextGetBitsPerPixel(context), |
| - CGBitmapContextGetBitsPerPixel(bg_context)); |
| - const unsigned char* bg_bytes = static_cast<const unsigned char*>( |
| - CGBitmapContextGetData(bg_context)); |
| - int full_bg_width = CGBitmapContextGetWidth(bg_context); |
| - int full_bg_height = CGBitmapContextGetHeight(bg_context); |
| - int bg_stride = CGBitmapContextGetBytesPerRow(bg_context); |
| - int bg_last_row = CGBitmapContextGetHeight(bg_context) - 1; |
| - |
| - int bytes_per_pixel = CGBitmapContextGetBitsPerPixel(context) / 8; |
| -#else |
| - cairo_surface_flush(page_surface); |
| - const unsigned char* page_bytes = cairo_image_surface_get_data(page_surface); |
| - int page_stride = cairo_image_surface_get_stride(page_surface); |
| - int page_start_x = content_rect.x() - static_cast<int>(page_x_double); |
| - int page_start_y = content_rect.y() - static_cast<int>(page_y_double); |
| - |
| - skia::ScopedPlatformPaint scoped_platform_paint( |
| - background_store_.canvas.get()); |
| - cairo_surface_t* bg_surface =cairo_get_target( |
| - scoped_platform_paint.GetPlatformSurface()); |
| - DCHECK_EQ(cairo_surface_get_type(bg_surface), CAIRO_SURFACE_TYPE_IMAGE); |
| - DCHECK_EQ(cairo_image_surface_get_format(bg_surface), CAIRO_FORMAT_ARGB32); |
| - cairo_surface_flush(bg_surface); |
| - const unsigned char* bg_bytes = cairo_image_surface_get_data(bg_surface); |
| - int full_bg_width = cairo_image_surface_get_width(bg_surface); |
| - int full_bg_height = cairo_image_surface_get_height(bg_surface); |
| - int bg_stride = cairo_image_surface_get_stride(bg_surface); |
| - |
| - int bytes_per_pixel = 4; // ARGB32 = 4 bytes per pixel. |
| -#endif |
| - |
| - int damage_width = content_rect.width(); |
| - int damage_height = content_rect.height(); |
| - |
| - int bg_start_x = rect.x() - plugin_rect_.x(); |
| - int bg_start_y = rect.y() - plugin_rect_.y(); |
| - // The damage rect is supposed to have been intersected with the plugin rect; |
| - // double-check, since if it hasn't we'll walk off the end of the buffer. |
| - DCHECK_LE(bg_start_x + damage_width, full_bg_width); |
| - DCHECK_LE(bg_start_y + damage_height, full_bg_height); |
| - |
| - int bg_x_byte_offset = bg_start_x * bytes_per_pixel; |
| - int page_x_byte_offset = page_start_x * bytes_per_pixel; |
| - for (int row = 0; row < damage_height; ++row) { |
| - int page_offset = page_stride * (page_start_y + row) + page_x_byte_offset; |
| - int bg_y = bg_start_y + row; |
| -#if defined(OS_MACOSX) |
| - // The background buffer is upside down relative to the content. |
| - bg_y = bg_last_row - bg_y; |
| -#endif |
| - int bg_offset = bg_stride * bg_y + bg_x_byte_offset; |
| - if (memcmp(page_bytes + page_offset, |
| - bg_bytes + bg_offset, |
| - damage_width * bytes_per_pixel) != 0) |
| - return true; |
| - } |
| -#endif |
| -#endif // OS_ANDROID |
| - |
| return false; |
| } |