| Index: webkit/glue/plugins/pepper_device_context_2d.cc
 | 
| ===================================================================
 | 
| --- webkit/glue/plugins/pepper_device_context_2d.cc	(revision 48097)
 | 
| +++ webkit/glue/plugins/pepper_device_context_2d.cc	(working copy)
 | 
| @@ -70,6 +70,15 @@
 | 
|    return context->GetResource();
 | 
|  }
 | 
|  
 | 
| +bool Describe(PP_Resource device_context,
 | 
| +              int32_t* width, int32_t* height, bool* is_always_opaque) {
 | 
| +  scoped_refptr<DeviceContext2D> context(
 | 
| +      ResourceTracker::Get()->GetAsDeviceContext2D(device_context));
 | 
| +  if (!context.get())
 | 
| +    return false;
 | 
| +  return context->Describe(width, height, is_always_opaque);
 | 
| +}
 | 
| +
 | 
|  bool PaintImageData(PP_Resource device_context,
 | 
|                      PP_Resource image,
 | 
|                      int32_t x, int32_t y,
 | 
| @@ -109,12 +118,24 @@
 | 
|    return context->Flush(callback, callback_data);
 | 
|  }
 | 
|  
 | 
| +bool ReadImageData(PP_Resource device_context,
 | 
| +                   PP_Resource image,
 | 
| +                   int32_t x, int32_t y) {
 | 
| +  scoped_refptr<DeviceContext2D> context(
 | 
| +      ResourceTracker::Get()->GetAsDeviceContext2D(device_context));
 | 
| +  if (!context.get())
 | 
| +    return false;
 | 
| +  return context->ReadImageData(image, x, y);
 | 
| +}
 | 
| +
 | 
|  const PPB_DeviceContext2D ppb_devicecontext2d = {
 | 
|    &Create,
 | 
| +  &Describe,
 | 
|    &PaintImageData,
 | 
|    &Scroll,
 | 
|    &ReplaceContents,
 | 
| -  &Flush
 | 
| +  &Flush,
 | 
| +  &ReadImageData
 | 
|  };
 | 
|  
 | 
|  }  // namespace
 | 
| @@ -161,6 +182,7 @@
 | 
|  }
 | 
|  
 | 
|  bool DeviceContext2D::Init(int width, int height, bool is_always_opaque) {
 | 
| +  // The underlying ImageData will validate the dimensions.
 | 
|    image_data_ = new ImageData(module());
 | 
|    if (!image_data_->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width, height, true) ||
 | 
|        !image_data_->Map()) {
 | 
| @@ -171,32 +193,38 @@
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| +bool DeviceContext2D::Describe(int32_t* width, int32_t* height,
 | 
| +                               bool* is_always_opaque) {
 | 
| +  *width = image_data_->width();
 | 
| +  *height = image_data_->height();
 | 
| +  *is_always_opaque = false;  // TODO(brettw) implement this.
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
|  bool DeviceContext2D::PaintImageData(PP_Resource image,
 | 
|                                       int32_t x, int32_t y,
 | 
|                                       const PP_Rect* src_rect) {
 | 
|    scoped_refptr<ImageData> image_resource(
 | 
|        ResourceTracker::Get()->GetAsImageData(image));
 | 
| -  if (!image_resource.get() || !image_resource->is_valid())
 | 
| +  if (!image_resource.get())
 | 
|      return false;
 | 
|  
 | 
| -  const SkBitmap& new_image_bitmap = image_resource->GetMappedBitmap();
 | 
| -
 | 
|    QueuedOperation operation(QueuedOperation::PAINT);
 | 
|    operation.paint_image = image_resource;
 | 
| -  if (!ValidateAndConvertRect(src_rect, new_image_bitmap.width(),
 | 
| -                              new_image_bitmap.height(),
 | 
| +  if (!ValidateAndConvertRect(src_rect, image_resource->width(),
 | 
| +                              image_resource->height(),
 | 
|                                &operation.paint_src_rect))
 | 
|      return false;
 | 
|  
 | 
| -  // Validate the bitmap position using the previously-validated rect.
 | 
| -  if (x < 0 ||
 | 
| -      static_cast<int64>(x) +
 | 
| -      static_cast<int64>(operation.paint_src_rect.right()) >
 | 
| +  // Validate the bitmap position using the previously-validated rect, there
 | 
| +  // should be no painted area outside of the image.
 | 
| +  int64 x64 = static_cast<int64>(x), y64 = static_cast<int64>(y);
 | 
| +  if (x64 + static_cast<int64>(operation.paint_src_rect.x()) < 0 ||
 | 
| +      x64 + static_cast<int64>(operation.paint_src_rect.right()) >
 | 
|        image_data_->width())
 | 
|      return false;
 | 
| -  if (y < 0 ||
 | 
| -      static_cast<int64>(y) +
 | 
| -      static_cast<int64>(operation.paint_src_rect.bottom()) >
 | 
| +  if (y64 + static_cast<int64>(operation.paint_src_rect.y()) < 0 ||
 | 
| +      y64 + static_cast<int64>(operation.paint_src_rect.bottom()) >
 | 
|        image_data_->height())
 | 
|      return false;
 | 
|    operation.paint_x = x;
 | 
| @@ -231,25 +259,20 @@
 | 
|  bool DeviceContext2D::ReplaceContents(PP_Resource image) {
 | 
|    scoped_refptr<ImageData> image_resource(
 | 
|        ResourceTracker::Get()->GetAsImageData(image));
 | 
| -  if (!image_resource.get() || !image_resource->is_valid())
 | 
| +  if (!image_resource.get())
 | 
|      return false;
 | 
| +  if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL)
 | 
| +    return false;
 | 
|  
 | 
|    if (image_resource->width() != image_data_->width() ||
 | 
|        image_resource->height() != image_data_->height())
 | 
|      return false;
 | 
|  
 | 
|    QueuedOperation operation(QueuedOperation::REPLACE);
 | 
| -  operation.replace_image = new ImageData(image_resource->module());
 | 
| +  operation.replace_image = image_resource;
 | 
|    queued_operations_.push_back(operation);
 | 
|  
 | 
| -  // Swap the input image data with the new one we just made in the
 | 
| -  // QueuedOperation. This way the plugin still gets to manage the reference
 | 
| -  // count of the old object without having memory released out from under it.
 | 
| -  // But it ensures that after this, if the plugin does try to use the image
 | 
| -  // it gave us, those operations will fail.
 | 
| -  operation.replace_image->Swap(image_resource.get());
 | 
| -
 | 
| -  return false;
 | 
| +  return true;
 | 
|  }
 | 
|  
 | 
|  bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback,
 | 
| @@ -293,11 +316,51 @@
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| +bool DeviceContext2D::ReadImageData(PP_Resource image, int32_t x, int32_t y) {
 | 
| +  // Get and validate the image object to paint into.
 | 
| +  scoped_refptr<ImageData> image_resource(
 | 
| +      ResourceTracker::Get()->GetAsImageData(image));
 | 
| +  if (!image_resource.get())
 | 
| +    return false;
 | 
| +  if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL)
 | 
| +    return false;  // Must be in the right format.
 | 
| +
 | 
| +  // Validate the bitmap position.
 | 
| +  if (x < 0 ||
 | 
| +      static_cast<int64>(x) + static_cast<int64>(image_resource->width()) >
 | 
| +      image_data_->width())
 | 
| +    return false;
 | 
| +  if (y < 0 ||
 | 
| +      static_cast<int64>(y) + static_cast<int64>(image_resource->height()) >
 | 
| +      image_data_->height())
 | 
| +    return false;
 | 
| +
 | 
| +  ImageDataAutoMapper auto_mapper(image_resource.get());
 | 
| +  if (!auto_mapper.is_valid())
 | 
| +    return false;
 | 
| +  skia::PlatformCanvas* dest_canvas = image_resource->mapped_canvas();
 | 
| +
 | 
| +  SkIRect src_irect = { x, y,
 | 
| +                        x + image_resource->width(),
 | 
| +                        y + image_resource->height() };
 | 
| +  SkRect dest_rect = { SkIntToScalar(0),
 | 
| +                       SkIntToScalar(0),
 | 
| +                       SkIntToScalar(image_resource->width()),
 | 
| +                       SkIntToScalar(image_resource->height()) };
 | 
| +
 | 
| +  // We want to replace the contents of the bitmap rather than blend.
 | 
| +  SkPaint paint;
 | 
| +  paint.setXfermodeMode(SkXfermode::kSrc_Mode);
 | 
| +  dest_canvas->drawBitmapRect(*image_data_->GetMappedBitmap(),
 | 
| +                              &src_irect, dest_rect, &paint);
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
|  void DeviceContext2D::Paint(WebKit::WebCanvas* canvas,
 | 
|                              const gfx::Rect& plugin_rect,
 | 
|                              const gfx::Rect& paint_rect) {
 | 
|    // We're guaranteed to have a mapped canvas since we mapped it in Init().
 | 
| -  const SkBitmap& backing_bitmap = image_data_->GetMappedBitmap();
 | 
| +  const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap();
 | 
|  
 | 
|  #if defined(OS_MACOSX)
 | 
|    SkAutoLockPixels lock(backing_bitmap);
 | 
| @@ -337,8 +400,7 @@
 | 
|  #endif
 | 
|  }
 | 
|  
 | 
| -
 | 
| -void DeviceContext2D::ExecutePaintImageData(const ImageData* image,
 | 
| +void DeviceContext2D::ExecutePaintImageData(ImageData* image,
 | 
|                                              int x, int y,
 | 
|                                              const gfx::Rect& src_rect) {
 | 
|    // Portion within the source image to cut out.
 | 
| @@ -354,10 +416,15 @@
 | 
|    // We're guaranteed to have a mapped canvas since we mapped it in Init().
 | 
|    skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas();
 | 
|  
 | 
| +  // Ensure the source image is mapped to read from it.
 | 
| +  ImageDataAutoMapper auto_mapper(image);
 | 
| +  if (!auto_mapper.is_valid())
 | 
| +    return;
 | 
| +
 | 
|    // We want to replace the contents of the bitmap rather than blend.
 | 
|    SkPaint paint;
 | 
|    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
 | 
| -  backing_canvas->drawBitmapRect(image->GetMappedBitmap(),
 | 
| +  backing_canvas->drawBitmapRect(*image->GetMappedBitmap(),
 | 
|                                   &src_irect, dest_rect, &paint);
 | 
|  }
 | 
|  
 | 
| 
 |