diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-14 19:10:48 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-14 19:10:48 +0000 |
commit | 95ff077352e9cf1f78b79b2aa86e5675cbafae1d (patch) | |
tree | 47f32ccbfcda90df866fb1f5be1bf237f791c16d | |
parent | 6c8bece66bb899bd9395a5d23d4442a344e74cc0 (diff) | |
download | chromium_src-95ff077352e9cf1f78b79b2aa86e5675cbafae1d.zip chromium_src-95ff077352e9cf1f78b79b2aa86e5675cbafae1d.tar.gz chromium_src-95ff077352e9cf1f78b79b2aa86e5675cbafae1d.tar.bz2 |
Implement new painting API in Chrome. This also makes some minor tweaks and improvements to resource management in the Chrome Pepper layer.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/2096002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47294 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | DEPS | 2 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_device_context_2d.cc | 303 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_device_context_2d.h | 29 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_image_data.cc | 44 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_image_data.h | 18 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_resource_tracker.cc | 24 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_resource_tracker.h | 15 |
7 files changed, 341 insertions, 94 deletions
@@ -143,7 +143,7 @@ deps = { Var("ffmpeg_revision"), "src/third_party/ppapi": - "http://ppapi.googlecode.com/svn/trunk@11", + "http://ppapi.googlecode.com/svn/trunk@26", } diff --git a/webkit/glue/plugins/pepper_device_context_2d.cc b/webkit/glue/plugins/pepper_device_context_2d.cc index 964c605..926d194 100644 --- a/webkit/glue/plugins/pepper_device_context_2d.cc +++ b/webkit/glue/plugins/pepper_device_context_2d.cc @@ -26,43 +26,129 @@ namespace pepper { namespace { -PP_Resource Create(PP_Module module_id, int32_t width, int32_t height) { +// Converts a rect inside an image of the given dimensions. The rect may be +// NULL to indicate it should be the entire image. If the rect is outside of +// the image, this will do nothing and return false. +bool ValidateAndConvertRect(const PP_Rect* rect, + int image_width, int image_height, + gfx::Rect* dest) { + if (!rect) { + // Use the entire image area. + *dest = gfx::Rect(0, 0, image_width, image_height); + } else { + // Validate the passed-in area. + if (rect->point.x < 0 || rect->point.y < 0 || + rect->size.width <= 0 || rect->size.height <= 0) + return false; + + // Check the max bounds, being careful of overflow. + if (static_cast<int64>(rect->point.x) + + static_cast<int64>(rect->size.width) > + static_cast<int64>(image_width)) + return false; + if (static_cast<int64>(rect->point.y) + + static_cast<int64>(rect->size.height) > + static_cast<int64>(image_height)) + return false; + + *dest = gfx::Rect(rect->point.x, rect->point.y, + rect->size.width, rect->size.height); + } + return true; +} + +PP_Resource Create(PP_Module module_id, int32_t width, int32_t height, + bool is_always_opaque) { PluginModule* module = PluginModule::FromPPModule(module_id); if (!module) return NullPPResource(); scoped_refptr<DeviceContext2D> context(new DeviceContext2D(module)); - if (!context->Init(width, height)) + if (!context->Init(width, height, is_always_opaque)) return NullPPResource(); context->AddRef(); // AddRef for the caller. return context->GetResource(); } -void PaintImageData(PP_Resource device_context, +bool PaintImageData(PP_Resource device_context, PP_Resource image, int32_t x, int32_t y, - const PP_Rect* dirty, - uint32_t dirty_rect_count, - PPB_DeviceContext2D_PaintCallback callback, - void* callback_data) { - scoped_refptr<Resource> device_resource = - ResourceTracker::Get()->GetResource(device_context); - if (!device_resource.get()) - return; - DeviceContext2D* context = device_resource->AsDeviceContext2D(); - if (!context) - return; - context->PaintImageData(image, x, y, dirty, dirty_rect_count, - callback, callback_data); + const PP_Rect* src_rect) { + scoped_refptr<DeviceContext2D> context( + ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); + if (!context.get()) + return false; + return context->PaintImageData(image, x, y, src_rect); +} + +bool Scroll(PP_Resource device_context, + const PP_Rect* clip_rect, + int32_t dx, int32_t dy) { + scoped_refptr<DeviceContext2D> context( + ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); + if (!context.get()) + return false; + return context->Scroll(clip_rect, dx, dy); +} + +bool ReplaceContents(PP_Resource device_context, PP_Resource image) { + scoped_refptr<DeviceContext2D> context( + ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); + if (!context.get()) + return false; + return context->ReplaceContents(image); +} + +bool Flush(PP_Resource device_context, + PPB_DeviceContext2D_FlushCallback callback, + void* callback_data) { + scoped_refptr<DeviceContext2D> context( + ResourceTracker::Get()->GetAsDeviceContext2D(device_context)); + if (!context.get()) + return false; + return context->Flush(callback, callback_data); } const PPB_DeviceContext2D ppb_devicecontext2d = { &Create, &PaintImageData, + &Scroll, + &ReplaceContents, + &Flush }; } // namespace +struct DeviceContext2D::QueuedOperation { + enum Type { + PAINT, + SCROLL, + REPLACE + }; + + QueuedOperation(Type t) + : type(t), + paint_x(0), + paint_y(0), + scroll_dx(0), + scroll_dy(0) { + } + + Type type; + + // Valid when type == PAINT. + scoped_refptr<ImageData> paint_image; + int paint_x, paint_y; + gfx::Rect paint_src_rect; + + // Valid when type == SCROLL. + gfx::Rect scroll_clip_rect; + int scroll_dx, scroll_dy; + + // Valid when type == REPLACE. + scoped_refptr<ImageData> replace_image; +}; + DeviceContext2D::DeviceContext2D(PluginModule* module) : Resource(module) { } @@ -74,9 +160,9 @@ const PPB_DeviceContext2D* DeviceContext2D::GetInterface() { return &ppb_devicecontext2d; } -bool DeviceContext2D::Init(int width, int height) { +bool DeviceContext2D::Init(int width, int height, bool is_always_opaque) { image_data_ = new ImageData(module()); - if (!image_data_->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width, height) || + if (!image_data_->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width, height, true) || !image_data_->Map()) { image_data_ = NULL; return false; @@ -85,61 +171,115 @@ bool DeviceContext2D::Init(int width, int height) { return true; } -void DeviceContext2D::PaintImageData(PP_Resource image, +bool DeviceContext2D::PaintImageData(PP_Resource image, int32_t x, int32_t y, - const PP_Rect* dirty, - uint32_t dirty_rect_count, - PPB_DeviceContext2D_PaintCallback callback, - void* callback_data) { - scoped_refptr<Resource> image_resource = - ResourceTracker::Get()->GetResource(image); - if (!image_resource.get()) - return; - ImageData* new_image_data = image_resource->AsImageData(); - if (!new_image_data) - return; - - const SkBitmap& new_image_bitmap = new_image_data->GetMappedBitmap(); - - // TODO(brettw) handle multiple dirty rects. - DCHECK(dirty_rect_count <= 1); - - // Draw the bitmap to the backing store. - SkIRect src_rect; - if (dirty_rect_count == 0 || !dirty) { - // Default to the entire bitmap. - src_rect.fLeft = 0; - src_rect.fTop = 0; - src_rect.fRight = new_image_bitmap.width(); - src_rect.fBottom = new_image_bitmap.height(); - } else { - src_rect.fLeft = dirty->point.x; - src_rect.fTop = dirty->point.y; - src_rect.fRight = dirty->point.x + dirty->size.width; - src_rect.fBottom = dirty->point.y + dirty->size.height; - } - SkRect dest_rect = { SkIntToScalar(src_rect.fLeft), - SkIntToScalar(src_rect.fTop), - SkIntToScalar(src_rect.fRight), - SkIntToScalar(src_rect.fBottom) }; + const PP_Rect* src_rect) { + scoped_refptr<ImageData> image_resource( + ResourceTracker::Get()->GetAsImageData(image)); + if (!image_resource.get() || !image_resource->is_valid()) + return false; - // We're guaranteed to have a mapped canvas since we mapped it in Init(). - skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas(); + const SkBitmap& new_image_bitmap = image_resource->GetMappedBitmap(); - // We want to replace the contents of the bitmap rather than blend. - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - backing_canvas->drawBitmapRect(new_image_bitmap, - &src_rect, dest_rect, &paint); + QueuedOperation operation(QueuedOperation::PAINT); + operation.paint_image = image_resource; + if (!ValidateAndConvertRect(src_rect, new_image_bitmap.width(), + new_image_bitmap.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()) > + image_data_->width()) + return false; + if (y < 0 || + static_cast<int64>(y) + + static_cast<int64>(operation.paint_src_rect.bottom()) > + image_data_->height()) + return false; + operation.paint_x = x; + operation.paint_y = y; - // TODO(brettw) implement invalidate and callbacks! + queued_operations_.push_back(operation); + return true; +} + +bool DeviceContext2D::Scroll(const PP_Rect* clip_rect, + int32_t dx, int32_t dy) { + QueuedOperation operation(QueuedOperation::SCROLL); + if (!ValidateAndConvertRect(clip_rect, + image_data_->width(), + image_data_->height(), + &operation.scroll_clip_rect)) + return false; + + // If we're being asked to scroll by more than the clip rect size, just + // ignore this scroll command and say it worked. + if (dx <= -image_data_->width() || dx >= image_data_->width() || + dx <= -image_data_->height() || dy >= image_data_->height()) + return true; + + operation.scroll_dx = dx; + operation.scroll_dy = dy; + + queued_operations_.push_back(operation); + return false; +} + +bool DeviceContext2D::ReplaceContents(PP_Resource image) { + scoped_refptr<ImageData> image_resource( + ResourceTracker::Get()->GetAsImageData(image)); + if (!image_resource.get() || !image_resource->is_valid()) + 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()); + 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; +} + +bool DeviceContext2D::Flush(PPB_DeviceContext2D_FlushCallback callback, + void* callback_data) { + for (size_t i = 0; i < queued_operations_.size(); i++) { + QueuedOperation& operation = queued_operations_[i]; + switch (operation.type) { + case QueuedOperation::PAINT: + ExecutePaintImageData(operation.paint_image.get(), + operation.paint_x, operation.paint_y, + operation.paint_src_rect); + break; + case QueuedOperation::SCROLL: + ExecuteScroll(operation.scroll_clip_rect, + operation.scroll_dx, operation.scroll_dy); + break; + case QueuedOperation::REPLACE: + ExecuteReplaceContents(operation.replace_image.get()); + break; + } + } + queued_operations_.clear(); + // TODO(brettw) implement invalidate and callbacks! // Cause the updated part of the screen to be repainted. This will happen // asynchronously. /* - gfx::Rect dest_gfx_rect(dirty->left, dirty->top, - dirty->right - dirty->left, - dirty->bottom - dirty->top); + gfx::Rect dest_gfx_rect(src_rect->left, src_rect->top, + src_rect->right - src_rect->left, + src_rect->bottom - src_rect->top); plugin_delegate_->instance()->webplugin()->InvalidateRect(dest_gfx_rect); @@ -150,6 +290,7 @@ void DeviceContext2D::PaintImageData(PP_Resource image, FlushCallbackData(callback, id, context, user_data)); } */ + return true; } void DeviceContext2D::Paint(WebKit::WebCanvas* canvas, @@ -196,4 +337,36 @@ void DeviceContext2D::Paint(WebKit::WebCanvas* canvas, #endif } + +void DeviceContext2D::ExecutePaintImageData(const ImageData* image, + int x, int y, + const gfx::Rect& src_rect) { + // Portion within the source image to cut out. + SkIRect src_irect = { src_rect.x(), src_rect.y(), + src_rect.right(), src_rect.bottom() }; + + // Location within the backing store to copy to. + SkRect dest_rect = { SkIntToScalar(x + src_rect.x()), + SkIntToScalar(y + src_rect.y()), + SkIntToScalar(x + src_rect.right()), + SkIntToScalar(y + src_rect.bottom()) }; + + // We're guaranteed to have a mapped canvas since we mapped it in Init(). + skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas(); + + // We want to replace the contents of the bitmap rather than blend. + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + backing_canvas->drawBitmapRect(image->GetMappedBitmap(), + &src_irect, dest_rect, &paint); +} + +void DeviceContext2D::ExecuteScroll(const gfx::Rect& clip, int dx, int dy) { + // FIXME(brettw) +} + +void DeviceContext2D::ExecuteReplaceContents(ImageData* image) { + image_data_->Swap(image); +} + } // namespace pepper diff --git a/webkit/glue/plugins/pepper_device_context_2d.h b/webkit/glue/plugins/pepper_device_context_2d.h index 5e8a877..8036c76 100644 --- a/webkit/glue/plugins/pepper_device_context_2d.h +++ b/webkit/glue/plugins/pepper_device_context_2d.h @@ -5,6 +5,8 @@ #ifndef WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_2D_H_ #define WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_2D_H_ +#include <vector> + #include "base/basictypes.h" #include "third_party/ppapi/c/ppb_device_context_2d.h" #include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h" @@ -30,25 +32,40 @@ class DeviceContext2D : public Resource { // exposed to the plugin. static const PPB_DeviceContext2D* GetInterface(); - bool Init(int width, int height); + bool Init(int width, int height, bool is_always_opaque); // Resource override. virtual DeviceContext2D* AsDeviceContext2D() { return this; } - void PaintImageData(PP_Resource image, + // PPB_DeviceContext2D functions. + bool PaintImageData(PP_Resource image, int32_t x, int32_t y, - const PP_Rect* dirty, - uint32_t dirty_rect_count, - PPB_DeviceContext2D_PaintCallback callback, - void* callback_data); + const PP_Rect* src_rect); + bool Scroll(const PP_Rect* clip_rect, int32_t dx, int32_t dy); + bool ReplaceContents(PP_Resource image); + bool Flush(PPB_DeviceContext2D_FlushCallback callback, + void* callback_data); void Paint(WebKit::WebCanvas* canvas, const gfx::Rect& plugin_rect, const gfx::Rect& paint_rect); private: + // Called internally to execute the different queued commands. The + // parameters to these functions will have already been validated. + void ExecutePaintImageData(const ImageData* image, + int x, int y, + const gfx::Rect& src_rect); + void ExecuteScroll(const gfx::Rect& clip, int dx, int dy); + void ExecuteReplaceContents(ImageData* image); + scoped_refptr<ImageData> image_data_; + // Keeps track of all drawing commands queued before a Flush call. + struct QueuedOperation; + typedef std::vector<QueuedOperation> OperationQueue; + OperationQueue queued_operations_; + DISALLOW_COPY_AND_ASSIGN(DeviceContext2D); }; diff --git a/webkit/glue/plugins/pepper_image_data.cc b/webkit/glue/plugins/pepper_image_data.cc index c53c91b..cf86437 100644 --- a/webkit/glue/plugins/pepper_image_data.cc +++ b/webkit/glue/plugins/pepper_image_data.cc @@ -4,6 +4,9 @@ #include "webkit/glue/plugins/pepper_image_data.h" +#include <algorithm> + +#include "base/logging.h" #include "base/scoped_ptr.h" #include "skia/ext/platform_canvas.h" #include "third_party/ppapi/c/pp_instance.h" @@ -28,14 +31,14 @@ ImageData* ResourceAsImageData(PP_Resource resource) { PP_Resource Create(PP_Module module_id, PP_ImageDataFormat format, - int32_t width, - int32_t height) { + int32_t width, int32_t height, + bool init_to_zero) { PluginModule* module = PluginModule::FromPPModule(module_id); if (!module) return NullPPResource(); scoped_refptr<ImageData> data(new ImageData(module)); - if (!data->Init(format, width, height)) + if (!data->Init(format, width, height, init_to_zero)) return NullPPResource(); data->AddRef(); // AddRef for the caller. @@ -43,11 +46,7 @@ PP_Resource Create(PP_Module module_id, } bool IsImageData(PP_Resource resource) { - scoped_refptr<Resource> image_resource = - ResourceTracker::Get()->GetResource(resource); - if (!image_resource.get()) - return false; - return !!image_resource->AsImageData(); + return !!ResourceTracker::Get()->GetAsImageData(resource).get(); } bool Describe(PP_Resource resource, @@ -55,22 +54,25 @@ bool Describe(PP_Resource resource, // Give predictable values on failure. memset(desc, 0, sizeof(PP_ImageDataDesc)); - ImageData* image_data = ResourceAsImageData(resource); - if (!image_data) + scoped_refptr<ImageData> image_data( + ResourceTracker::Get()->GetAsImageData(resource)); + if (!image_data.get()) return false; image_data->Describe(desc); return true; } void* Map(PP_Resource resource) { - ImageData* image_data = ResourceAsImageData(resource); - if (!image_data) + scoped_refptr<ImageData> image_data( + ResourceTracker::Get()->GetAsImageData(resource)); + if (!image_data.get()) return NULL; return image_data->Map(); } void Unmap(PP_Resource resource) { - ImageData* image_data = ResourceAsImageData(resource); + scoped_refptr<ImageData> image_data( + ResourceTracker::Get()->GetAsImageData(resource)); if (!image_data) return; return image_data->Unmap(); @@ -101,9 +103,10 @@ const PPB_ImageData* ImageData::GetInterface() { } bool ImageData::Init(PP_ImageDataFormat format, - int width, - int height) { + int width, int height, + bool init_to_zero) { // TODO(brettw) this should be called only on the main thread! + // TODO(brettw) use init_to_zero when we implement caching. platform_image_.reset( module()->GetSomeInstance()->delegate()->CreateImage2D(width, height)); width_ = width; @@ -119,6 +122,9 @@ void ImageData::Describe(PP_ImageDataDesc* desc) const { } void* ImageData::Map() { + if (!is_valid()) + return NULL; + if (!mapped_canvas_.get()) { mapped_canvas_.reset(platform_image_->Map()); if (!mapped_canvas_.get()) @@ -142,7 +148,15 @@ void ImageData::Unmap() { } const SkBitmap& ImageData::GetMappedBitmap() const { + DCHECK(is_valid()); return mapped_canvas_->getTopPlatformDevice().accessBitmap(false); } +void ImageData::Swap(ImageData* other) { + swap(other->platform_image_, platform_image_); + swap(other->mapped_canvas_, mapped_canvas_); + std::swap(other->width_, width_); + std::swap(other->height_, height_); +} + } // namespace pepper diff --git a/webkit/glue/plugins/pepper_image_data.h b/webkit/glue/plugins/pepper_image_data.h index e4af427..d2395b3 100644 --- a/webkit/glue/plugins/pepper_image_data.h +++ b/webkit/glue/plugins/pepper_image_data.h @@ -27,6 +27,13 @@ class ImageData : public Resource { explicit ImageData(PluginModule* module); virtual ~ImageData(); + int width() const { return width_; } + int height() const { return height_; } + + // Returns true if this image is valid and can be used. False means that the + // image is invalid and can't be used. + bool is_valid() const { return !!platform_image_.get(); } + // Returns a pointer to the interface implementing PPB_ImageData that is // exposed to the plugin. static const PPB_ImageData* GetInterface(); @@ -36,8 +43,8 @@ class ImageData : public Resource { // PPB_ImageData implementation. bool Init(PP_ImageDataFormat format, - int width, - int height); + int width, int height, + bool init_to_zero); void Describe(PP_ImageDataDesc* desc) const; void* Map(); void Unmap(); @@ -46,7 +53,12 @@ class ImageData : public Resource { const SkBitmap& GetMappedBitmap() const; + // Swaps the guts of this image data with another. + void Swap(ImageData* other); + private: + // This will be NULL before initialization, and if this ImageData is + // swapped with another. scoped_ptr<PluginDelegate::PlatformImage2D> platform_image_; // When the device is mapped, this is the image. Null when umapped. @@ -54,6 +66,8 @@ class ImageData : public Resource { int width_; int height_; + + DISALLOW_COPY_AND_ASSIGN(ImageData); }; } // namespace pepper diff --git a/webkit/glue/plugins/pepper_resource_tracker.cc b/webkit/glue/plugins/pepper_resource_tracker.cc index 13c5c2c..8a58256 100644 --- a/webkit/glue/plugins/pepper_resource_tracker.cc +++ b/webkit/glue/plugins/pepper_resource_tracker.cc @@ -8,6 +8,8 @@ #include "base/logging.h" #include "third_party/ppapi/c/pp_resource.h" +#include "webkit/glue/plugins/pepper_device_context_2d.h" +#include "webkit/glue/plugins/pepper_image_data.h" #include "webkit/glue/plugins/pepper_resource.h" namespace pepper { @@ -23,12 +25,12 @@ ResourceTracker* ResourceTracker::Get() { return Singleton<ResourceTracker>::get(); } -Resource* ResourceTracker::GetResource(PP_Resource res) const { +scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const { AutoLock lock(lock_); Resource* resource = reinterpret_cast<Resource*>(res.id); if (live_resources_.find(resource) == live_resources_.end()) - return NULL; - return resource; + return scoped_refptr<Resource>(); + return scoped_refptr<Resource>(resource); } void ResourceTracker::AddResource(Resource* resource) { @@ -47,4 +49,20 @@ void ResourceTracker::DeleteResource(Resource* resource) { live_resources_.erase(found); } +scoped_refptr<DeviceContext2D> ResourceTracker::GetAsDeviceContext2D( + PP_Resource res) const { + scoped_refptr<Resource> resource = GetResource(res); + if (!resource.get()) + return scoped_refptr<DeviceContext2D>(); + return scoped_refptr<DeviceContext2D>(resource->AsDeviceContext2D()); +} + +scoped_refptr<ImageData> ResourceTracker::GetAsImageData( + PP_Resource res) const { + scoped_refptr<Resource> resource = GetResource(res); + if (!resource.get()) + return scoped_refptr<ImageData>(); + return scoped_refptr<ImageData>(resource->AsImageData()); +} + } // namespace pepper diff --git a/webkit/glue/plugins/pepper_resource_tracker.h b/webkit/glue/plugins/pepper_resource_tracker.h index f114549..f24afc2 100644 --- a/webkit/glue/plugins/pepper_resource_tracker.h +++ b/webkit/glue/plugins/pepper_resource_tracker.h @@ -17,6 +17,8 @@ typedef struct _pp_Resource PP_Resource; namespace pepper { +class DeviceContext2D; +class ImageData; class Resource; // This class maintains a global list of all live pepper resources. It allows @@ -28,8 +30,12 @@ class ResourceTracker { // Returns the pointer to the singleton object. static ResourceTracker* Get(); - // The returned pointer will be NULL if there is no resource. - Resource* GetResource(PP_Resource res) const; + // The returned pointer will be NULL if there is no resource. Note that this + // return value is a scoped_refptr so that we ensure the resource is valid + // from the point of the loopkup to the point that the calling code needs it. + // Otherwise, the plugin could Release() the resource on another thread and + // the object will get deleted out from under us. + scoped_refptr<Resource> GetResource(PP_Resource res) const; // Adds the given resource to the tracker and assigns it a resource ID. The // assigned resource ID will be returned. @@ -37,6 +43,11 @@ class ResourceTracker { void DeleteResource(Resource* resource); + // Helpers for converting resources to a specific type. Returns NULL if the + // resource is invalid or is a different type. + scoped_refptr<DeviceContext2D> GetAsDeviceContext2D(PP_Resource res) const; + scoped_refptr<ImageData> GetAsImageData(PP_Resource res) const; + private: friend struct DefaultSingletonTraits<ResourceTracker>; |