summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorneb@chromium.org <neb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-25 23:25:16 +0000
committerneb@chromium.org <neb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-25 23:25:16 +0000
commit9e7e0e0c96dcd2773747077ac1041913e73a481a (patch)
tree715cf95cf9de7f75fd0eca1846cfb2c346c462eb
parent1e730344d06a78c40062912a50aa3b4e61fc160d (diff)
downloadchromium_src-9e7e0e0c96dcd2773747077ac1041913e73a481a.zip
chromium_src-9e7e0e0c96dcd2773747077ac1041913e73a481a.tar.gz
chromium_src-9e7e0e0c96dcd2773747077ac1041913e73a481a.tar.bz2
Refactor Pepper device API
Track Pepper DeviceContexts using ID (and reclaim them upon shutdown) Refactor device-specific code into pepper_devices.h Review URL: http://codereview.chromium.org/548100 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37060 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/id_map.h62
-rw-r--r--base/id_map_unittest.cc80
-rwxr-xr-xchrome/chrome_renderer.gypi2
-rw-r--r--chrome/renderer/pepper_devices.cc172
-rw-r--r--chrome/renderer/pepper_devices.h77
-rw-r--r--chrome/renderer/webplugin_delegate_pepper.cc230
-rw-r--r--chrome/renderer/webplugin_delegate_pepper.h64
-rw-r--r--third_party/npapi/bindings/npapi_extensions.h5
8 files changed, 424 insertions, 268 deletions
diff --git a/base/id_map.h b/base/id_map.h
index 13fb2f2..b108dbd 100644
--- a/base/id_map.h
+++ b/base/id_map.h
@@ -11,6 +11,13 @@
#include "base/hash_tables.h"
#include "base/logging.h"
+// Ownership semantics - own pointer means the pointer is deleted in Remove()
+// & during destruction
+enum IDMapOwnershipSemantics {
+ IDMapExternalPointer,
+ IDMapOwnPointer
+};
+
// This object maintains a list of IDs that can be quickly converted to
// pointers to objects. It is implemented as a hash table, optimized for
// relatively small data sets (in the common case, there will be exactly one
@@ -19,22 +26,30 @@
// Items can be inserted into the container with arbitrary ID, but the caller
// must ensure they are unique. Inserting IDs and relying on automatically
// generated ones is not allowed because they can collide.
-template<class T>
+//
+// This class does not have a virtual destructor, do not inherit from it when
+// ownership semantics are set to own because pointers will leak.
+template<typename T, IDMapOwnershipSemantics OS = IDMapExternalPointer>
class IDMap {
private:
- typedef base::hash_map<int32, T*> HashTable;
+ typedef int32 KeyType;
+ typedef base::hash_map<KeyType, T*> HashTable;
public:
IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) {
}
+ ~IDMap() {
+ Releaser<OS, 0>::release_all(&data_);
+ }
+
// Sets whether Add should CHECK if passed in NULL data. Default is false.
void set_check_on_null_data(bool value) { check_on_null_data_ = value; }
// Adds a view with an automatically generated unique ID. See AddWithID.
- int32 Add(T* data) {
+ KeyType Add(T* data) {
CHECK(!check_on_null_data_ || data);
- int32 this_id = next_id_;
+ KeyType this_id = next_id_;
DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
data_[this_id] = data;
next_id_++;
@@ -45,30 +60,32 @@ class IDMap {
// the list. The caller either must generate all unique IDs itself and use
// this function, or allow this object to generate IDs and call Add. These
// two methods may not be mixed, or duplicate IDs may be generated
- void AddWithID(T* data, int32 id) {
+ void AddWithID(T* data, KeyType id) {
CHECK(!check_on_null_data_ || data);
DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
data_[id] = data;
}
- void Remove(int32 id) {
+ void Remove(KeyType id) {
typename HashTable::iterator i = data_.find(id);
if (i == data_.end()) {
NOTREACHED() << "Attempting to remove an item not in the list";
return;
}
- if (iteration_depth_ == 0)
+ if (iteration_depth_ == 0) {
+ Releaser<OS, 0>::release(i->second);
data_.erase(i);
- else
+ } else {
removed_ids_.insert(id);
+ }
}
bool IsEmpty() const {
return data_.empty();
}
- T* Lookup(int32 id) const {
+ T* Lookup(KeyType id) const {
typename HashTable::const_iterator i = data_.find(id);
if (i == data_.end())
return NULL;
@@ -100,7 +117,7 @@ class IDMap {
return iter_ == map_->data_.end();
}
- int32 GetCurrentKey() const {
+ KeyType GetCurrentKey() const {
return iter_->first;
}
@@ -130,9 +147,28 @@ class IDMap {
typedef Iterator<const T> const_iterator;
private:
+
+ // The dummy parameter is there because C++ standard does not allow
+ // explicitly specialized templates inside classes
+ template<IDMapOwnershipSemantics OI, int dummy> struct Releaser {
+ static inline void release(T* ptr) {}
+ static inline void release_all(HashTable* table) {}
+ };
+
+ template<int dummy> struct Releaser<IDMapOwnPointer, dummy> {
+ static inline void release(T* ptr) { delete ptr;}
+ static inline void release_all(HashTable* table) {
+ for (typename HashTable::iterator i = table->begin();
+ i != table->end(); ++i) {
+ delete i->second;
+ }
+ table->clear();
+ }
+ };
+
void Compact() {
DCHECK_EQ(0, iteration_depth_);
- for (std::set<int32>::const_iterator i = removed_ids_.begin();
+ for (std::set<KeyType>::const_iterator i = removed_ids_.begin();
i != removed_ids_.end(); ++i) {
Remove(*i);
}
@@ -146,10 +182,10 @@ class IDMap {
// Keep set of IDs that should be removed after the outermost iteration has
// finished. This way we manage to not invalidate the iterator when an element
// is removed.
- std::set<int32> removed_ids_;
+ std::set<KeyType> removed_ids_;
// The next ID that we will return from Add()
- int32 next_id_;
+ KeyType next_id_;
HashTable data_;
diff --git a/base/id_map_unittest.cc b/base/id_map_unittest.cc
index 7b12e35..58abf96 100644
--- a/base/id_map_unittest.cc
+++ b/base/id_map_unittest.cc
@@ -14,6 +14,14 @@ class IDMapTest : public testing::Test {
class TestObject {
};
+class DestructorCounter {
+ public:
+ explicit DestructorCounter(int* counter) : counter_(counter) {}
+ ~DestructorCounter() { ++(*counter_); }
+ private:
+ int* counter_;
+};
+
TEST_F(IDMapTest, Basic) {
IDMap<TestObject> map;
EXPECT_TRUE(map.IsEmpty());
@@ -103,4 +111,76 @@ TEST_F(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
}
}
+TEST_F(IDMapTest, OwningPointersDeletesThemOnRemove) {
+ const int kCount = 3;
+
+ int external_del_count = 0;
+ DestructorCounter* external_obj[kCount];
+ int map_external_ids[kCount];
+
+ int owned_del_count = 0;
+ DestructorCounter* owned_obj[kCount];
+ int map_owned_ids[kCount];
+
+ IDMap<DestructorCounter> map_external;
+ IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+ for (int i = 0; i < kCount; ++i) {
+ external_obj[i] = new DestructorCounter(&external_del_count);
+ map_external_ids[i] = map_external.Add(external_obj[i]);
+
+ owned_obj[i] = new DestructorCounter(&owned_del_count);
+ map_owned_ids[i] = map_owned.Add(owned_obj[i]);
+ }
+
+ for (int i = 0; i < kCount; ++i) {
+ EXPECT_EQ(external_del_count, 0);
+ EXPECT_EQ(owned_del_count, i);
+
+ map_external.Remove(map_external_ids[i]);
+ map_owned.Remove(map_owned_ids[i]);
+ }
+
+ for (int i = 0; i < kCount; ++i) {
+ delete external_obj[i];
+ }
+
+ EXPECT_EQ(external_del_count, kCount);
+ EXPECT_EQ(owned_del_count, kCount);
+}
+
+TEST_F(IDMapTest, OwningPointersDeletesThemOnDestruct) {
+ const int kCount = 3;
+
+ int external_del_count = 0;
+ DestructorCounter* external_obj[kCount];
+ int map_external_ids[kCount];
+
+ int owned_del_count = 0;
+ DestructorCounter* owned_obj[kCount];
+ int map_owned_ids[kCount];
+
+ {
+ IDMap<DestructorCounter> map_external;
+ IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+ for (int i = 0; i < kCount; ++i) {
+ external_obj[i] = new DestructorCounter(&external_del_count);
+ map_external_ids[i] = map_external.Add(external_obj[i]);
+
+ owned_obj[i] = new DestructorCounter(&owned_del_count);
+ map_owned_ids[i] = map_owned.Add(owned_obj[i]);
+ }
+ }
+
+ EXPECT_EQ(external_del_count, 0);
+
+ for (int i = 0; i < kCount; ++i) {
+ delete external_obj[i];
+ }
+
+ EXPECT_EQ(external_del_count, kCount);
+ EXPECT_EQ(owned_del_count, kCount);
+}
+
} // namespace
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index ea95478..a15c82b 100755
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -87,6 +87,8 @@
'renderer/notification_provider.cc',
'renderer/notification_provider.h',
'renderer/paint_aggregator.cc',
+ 'renderer/pepper_devices.cc',
+ 'renderer/pepper_devices.h',
'renderer/plugin_channel_host.cc',
'renderer/plugin_channel_host.h',
'renderer/print_web_view_helper.cc',
diff --git a/chrome/renderer/pepper_devices.cc b/chrome/renderer/pepper_devices.cc
new file mode 100644
index 0000000..ff39088
--- /dev/null
+++ b/chrome/renderer/pepper_devices.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/pepper_devices.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace {
+ const uint32 kBytesPerPixel = 4; // Only 8888 RGBA for now.
+} // namespace
+
+int Graphics2DDeviceContext::next_buffer_id_ = 0;
+
+NPError Graphics2DDeviceContext::Initialize(
+ gfx::Rect window_rect, const NPDeviceContext2DConfig* config,
+ NPDeviceContext2D* context) {
+ int width = window_rect.width();
+ int height = window_rect.height();
+ uint32 buffer_size = width * height * kBytesPerPixel;
+
+ // Allocate the transport DIB and the PlatformCanvas pointing to it.
+ transport_dib_.reset(TransportDIB::Create(buffer_size, ++next_buffer_id_));
+ if (!transport_dib_.get())
+ return NPERR_OUT_OF_MEMORY_ERROR;
+ canvas_.reset(transport_dib_->GetPlatformCanvas(width, height));
+ if (!canvas_.get())
+ return NPERR_OUT_OF_MEMORY_ERROR;
+
+ // Note that we need to get the address out of the bitmap rather than
+ // using plugin_buffer_->memory(). The memory() is when the bitmap data
+ // has had "Map" called on it. For Windows, this is separate than making a
+ // bitmap using the shared section.
+ const SkBitmap& plugin_bitmap =
+ canvas_->getTopPlatformDevice().accessBitmap(true);
+ SkAutoLockPixels locker(plugin_bitmap);
+
+ // TODO(brettw) this theoretically shouldn't be necessary. But the
+ // platform device on Windows will fill itself with green to help you
+ // catch areas you didn't paint.
+ plugin_bitmap.eraseARGB(0, 0, 0, 0);
+
+ // Save the canvas to the output context structure and save the
+ // OpenPaintContext for future reference.
+ context->region = plugin_bitmap.getAddr32(0, 0);
+ context->stride = width * kBytesPerPixel;
+ context->dirty.left = 0;
+ context->dirty.top = 0;
+ context->dirty.right = width;
+ context->dirty.bottom = height;
+ return NPERR_NO_ERROR;
+}
+
+NPError Graphics2DDeviceContext::Flush(SkBitmap* committed_bitmap,
+ NPDeviceContext2D* context,
+ NPDeviceFlushContextCallbackPtr callback,
+ NPP id, void* user_data) {
+ // Draw the bitmap to the backing store.
+ //
+ // TODO(brettw) we can optimize this in the case where the entire canvas is
+ // updated by actually taking ownership of the buffer and not telling the
+ // plugin we're done using it. This wat we can avoid the copy when the entire
+ // canvas has been updated.
+ SkIRect src_rect = { context->dirty.left,
+ context->dirty.top,
+ context->dirty.right,
+ context->dirty.bottom };
+ SkRect dest_rect = { SkIntToScalar(context->dirty.left),
+ SkIntToScalar(context->dirty.top),
+ SkIntToScalar(context->dirty.right),
+ SkIntToScalar(context->dirty.bottom) };
+ SkCanvas committed_canvas(*committed_bitmap);
+
+ // We want to replace the contents of the bitmap rather than blend.
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ committed_canvas.drawBitmapRect(
+ canvas_->getTopPlatformDevice().accessBitmap(false),
+ &src_rect, dest_rect);
+
+ committed_bitmap->setIsOpaque(false);
+
+ // Invoke the callback to inform the caller the work was done.
+ // TODO(brettw) this is not how we want this to work, this should
+ // happen when the frame is painted so the plugin knows when it can draw
+ // the next frame.
+ //
+ // This should also be called in the failure cases as well.
+ if (callback != NULL)
+ (*callback)(id, context, NPERR_NO_ERROR, user_data);
+
+ return NPERR_NO_ERROR;
+}
+
+
+AudioDeviceContext::~AudioDeviceContext() {
+ if (stream_id_) {
+ OnDestroy();
+ }
+}
+
+NPError AudioDeviceContext::Initialize(
+ AudioMessageFilter* filter, const NPDeviceContextAudioConfig* config,
+ NPDeviceContextAudio* context) {
+ filter_ = filter;
+ context_= context;
+ // Make sure we don't call init more than once.
+ DCHECK_EQ(0, stream_id_);
+ stream_id_ = filter_->AddDelegate(this);
+
+ ViewHostMsg_Audio_CreateStream params;
+ params.format = AudioManager::AUDIO_PCM_LINEAR;
+ params.channels = config->outputChannelMap;
+ params.sample_rate = config->sampleRate;
+ switch (config->sampleType) {
+ case NPAudioSampleTypeInt16:
+ params.bits_per_sample = 16;
+ break;
+ case NPAudioSampleTypeFloat32:
+ params.bits_per_sample = 32;
+ break;
+ default:
+ return NPERR_INVALID_PARAM;
+ }
+
+ context->config = *config;
+ params.packet_size = config->sampleFrameCount * config->outputChannelMap
+ * (params.bits_per_sample >> 3);
+
+ // TODO(neb): figure out if this number is grounded in reality
+ params.buffer_capacity = params.packet_size * 3;
+
+ LOG(INFO) << "Initializing Pepper Audio Context (" <<
+ config->sampleFrameCount << "Hz, " << params.bits_per_sample <<
+ " bits, " << config->outputChannelMap << "channels";
+
+ filter->Send(new ViewHostMsg_CreateAudioStream(0, stream_id_, params));
+ return NPERR_NO_ERROR;
+}
+
+void AudioDeviceContext::OnDestroy() {
+ // Make sure we don't call destroy more than once.
+ DCHECK_NE(0, stream_id_);
+ filter_->RemoveDelegate(stream_id_);
+ filter_->Send(new ViewHostMsg_CloseAudioStream(0, stream_id_));
+ stream_id_ = 0;
+}
+
+void AudioDeviceContext::OnRequestPacket(
+ size_t bytes_in_buffer, const base::Time& message_timestamp) {
+ context_->config.callback(context_);
+ filter_->Send(new ViewHostMsg_NotifyAudioPacketReady(0, stream_id_,
+ shared_memory_size_));
+}
+
+void AudioDeviceContext::OnStateChanged(
+ ViewMsg_AudioStreamState state) {
+}
+
+void AudioDeviceContext::OnCreated(
+ base::SharedMemoryHandle handle, size_t length) {
+ shared_memory_.reset(new base::SharedMemory(handle, false));
+ shared_memory_->Map(length);
+ shared_memory_size_ = length;
+
+ context_->outBuffer = shared_memory_->memory();
+ // TODO(neb): call play after prefilling
+ filter_->Send(new ViewHostMsg_PlayAudioStream(0, stream_id_));
+}
+
+void AudioDeviceContext::OnVolume(double volume) {
+}
+
diff --git a/chrome/renderer/pepper_devices.h b/chrome/renderer/pepper_devices.h
new file mode 100644
index 0000000..50b3013
--- /dev/null
+++ b/chrome/renderer/pepper_devices.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_PEPPER_DEVICES_H_
+#define CHROME_RENDERER_PEPPER_DEVICES_H_
+
+#include <stdint.h>
+
+#include "base/scoped_ptr.h"
+#include "base/shared_memory.h"
+#include "base/gfx/rect.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/transport_dib.h"
+#include "chrome/renderer/audio_message_filter.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npapi_extensions.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+// Lists all contexts currently open for painting. These are ones requested by
+// the plugin but not destroyed by it yet. The source pointer is the raw
+// pixels. We use this to look up the corresponding transport DIB when the
+// plugin tells us to flush or destroy it.
+class Graphics2DDeviceContext {
+ public:
+ NPError Initialize(gfx::Rect window_rect,
+ const NPDeviceContext2DConfig* config,
+ NPDeviceContext2D* context);
+
+ NPError Flush(SkBitmap* commited_bitmap, NPDeviceContext2D* context,
+ NPDeviceFlushContextCallbackPtr callback, NPP id,
+ void* user_data);
+
+ private:
+ static int32 next_buffer_id_;
+ scoped_ptr<TransportDIB> transport_dib_;
+
+ // The canvas associated with the transport DIB, containing the mapped
+ // memory of the image.
+ scoped_ptr<skia::PlatformCanvas> canvas_;
+};
+
+
+// Each instance of AudioDeviceContext corresponds to one host stream (and one
+// audio context). NPDeviceContextAudio contains the id of the context's
+// stream in the privatePtr member.
+class AudioDeviceContext : public AudioMessageFilter::Delegate {
+ public:
+ // TODO(neb): if plugin_delegate parameter is indeed unused, remove it
+ explicit AudioDeviceContext() : stream_id_(0) {
+ }
+ virtual ~AudioDeviceContext();
+
+ NPError Initialize(AudioMessageFilter* filter,
+ const NPDeviceContextAudioConfig* config,
+ NPDeviceContextAudio* context);
+
+ // AudioMessageFilter::Delegate implementation
+ virtual void OnRequestPacket(size_t bytes_in_buffer,
+ const base::Time& message_timestamp);
+ virtual void OnStateChanged(ViewMsg_AudioStreamState state);
+ virtual void OnCreated(base::SharedMemoryHandle handle, size_t length);
+ virtual void OnVolume(double volume);
+ // End of AudioMessageFilter::Delegate implementation
+
+ private:
+ void OnDestroy();
+
+ NPDeviceContextAudio* context_;
+ scoped_refptr<AudioMessageFilter> filter_;
+ int32 stream_id_;
+ scoped_ptr<base::SharedMemory> shared_memory_;
+ size_t shared_memory_size_;
+};
+
+#endif // CHROME_RENDERER_PEPPER_DEVICES_H_
+
diff --git a/chrome/renderer/webplugin_delegate_pepper.cc b/chrome/renderer/webplugin_delegate_pepper.cc
index c5b0b14..68e611d 100644
--- a/chrome/renderer/webplugin_delegate_pepper.cc
+++ b/chrome/renderer/webplugin_delegate_pepper.cc
@@ -42,12 +42,6 @@ using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;
using WebKit::WebMouseWheelEvent;
-namespace {
-
-const uint32 kBytesPerPixel = 4; // Only 8888 RGBA for now.
-
-} // namespace
-
// Implementation artifacts for a context
struct Device2DImpl {
TransportDIB* dib;
@@ -57,8 +51,6 @@ struct Device3DImpl {
gpu::CommandBuffer* command_buffer;
};
-uint32 WebPluginDelegatePepper::next_buffer_id = 0;
-
WebPluginDelegatePepper* WebPluginDelegatePepper::Create(
const FilePath& filename,
const std::string& mime_type,
@@ -260,63 +252,23 @@ NPError WebPluginDelegatePepper::Device2DQueryConfig(
NPError WebPluginDelegatePepper::Device2DInitializeContext(
const NPDeviceContext2DConfig* config,
NPDeviceContext2D* context) {
+
+ if (!render_view_) {
+ return NPERR_GENERIC_ERROR;
+ }
+
// This is a windowless plugin, so set it to have a NULL handle. Defer this
// until we know the plugin will use the 2D device. If it uses the 3D device
// it will have a window handle.
plugin_->SetWindow(NULL);
- int width = window_rect_.width();
- int height = window_rect_.height();
- uint32 buffer_size = width * height * kBytesPerPixel;
-
- // Initialize the impelementation information in case of failure.
- context->reserved = NULL;
-
- // Allocate the transport DIB and the PlatformCanvas pointing to it.
- scoped_ptr<OpenPaintContext> paint_context(new OpenPaintContext);
- paint_context->transport_dib.reset(
- TransportDIB::Create(buffer_size, ++next_buffer_id));
- if (!paint_context->transport_dib.get())
- return NPERR_OUT_OF_MEMORY_ERROR;
- paint_context->canvas.reset(
- paint_context->transport_dib->GetPlatformCanvas(width, height));
- if (!paint_context->canvas.get())
- return NPERR_OUT_OF_MEMORY_ERROR;
-
- // Note that we need to get the address out of the bitmap rather than
- // using plugin_buffer_->memory(). The memory() is when the bitmap data
- // has had "Map" called on it. For Windows, this is separate than making a
- // bitmap using the shared section.
- const SkBitmap& plugin_bitmap =
- paint_context->canvas->getTopPlatformDevice().accessBitmap(true);
- SkAutoLockPixels locker(plugin_bitmap);
-
- // TODO(brettw) this theoretically shouldn't be necessary. But the
- // platform device on Windows will fill itself with green to help you
- // catch areas you didn't paint.
- plugin_bitmap.eraseARGB(0, 0, 0, 0);
-
- // Save the implementation information (the TransportDIB).
- Device2DImpl* impl = new Device2DImpl;
- if (impl == NULL) {
- // TODO(sehr,brettw): cleanup the context if we fail.
- return NPERR_GENERIC_ERROR;
+ scoped_ptr<Graphics2DDeviceContext> g2d(new Graphics2DDeviceContext());
+ NPError status = g2d->Initialize(window_rect_, config, context);
+ if (NPERR_NO_ERROR == status) {
+ context->reserved = reinterpret_cast<void *>(
+ graphic2d_contexts_.Add(g2d.release()));
}
- impl->dib = paint_context->transport_dib.get();
- context->reserved = reinterpret_cast<void*>(impl);
-
- // Save the canvas to the output context structure and save the
- // OpenPaintContext for future reference.
- context->region = plugin_bitmap.getAddr32(0, 0);
- context->stride = width * kBytesPerPixel;
- context->dirty.left = 0;
- context->dirty.top = 0;
- context->dirty.right = width;
- context->dirty.bottom = height;
- open_paint_contexts_[context->region] =
- linked_ptr<OpenPaintContext>(paint_context.release());
-
- return NPERR_NO_ERROR;
+ return status;
}
NPError WebPluginDelegatePepper::Device2DSetStateContext(
@@ -338,61 +290,28 @@ NPError WebPluginDelegatePepper::Device2DFlushContext(
NPDeviceContext2D* context,
NPDeviceFlushContextCallbackPtr callback,
void* user_data) {
- // Get the bitmap data associated with the incoming context.
- OpenPaintContextMap::iterator found = open_paint_contexts_.find(
- context->region);
- if (found == open_paint_contexts_.end())
- return NPERR_INVALID_PARAM; // TODO(brettw) call callback.
- OpenPaintContext* paint_context = found->second.get();
-
- // Draw the bitmap to the backing store.
- //
- // TODO(brettw) we can optimize this in the case where the entire canvas is
- // updated by actually taking ownership of the buffer and not telling the
- // plugin we're done using it. This wat we can avoid the copy when the entire
- // canvas has been updated.
- SkIRect src_rect = { context->dirty.left,
- context->dirty.top,
- context->dirty.right,
- context->dirty.bottom };
- SkRect dest_rect = { SkIntToScalar(context->dirty.left),
- SkIntToScalar(context->dirty.top),
- SkIntToScalar(context->dirty.right),
- SkIntToScalar(context->dirty.bottom) };
- SkCanvas committed_canvas(committed_bitmap_);
-
- // We want to replace the contents of the bitmap rather than blend.
- SkPaint paint;
- paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- committed_canvas.drawBitmapRect(
- paint_context->canvas->getTopPlatformDevice().accessBitmap(false),
- &src_rect, dest_rect);
-
- committed_bitmap_.setIsOpaque(false);
-
- // Invoke the callback to inform the caller the work was done.
- // TODO(brettw) this is not how we want this to work, this should
- // happen when the frame is painted so the plugin knows when it can draw
- // the next frame.
- //
- // This should also be called in the failure cases as well.
- if (callback != NULL)
- (*callback)(id, context, NPERR_NO_ERROR, user_data);
+ if (!context) {
+ return NPERR_INVALID_PARAM;
+ }
- return NPERR_NO_ERROR;
+ Graphics2DDeviceContext* ctx = graphic2d_contexts_.Lookup(
+ reinterpret_cast<intptr_t>(context->reserved));
+ if (!ctx) {
+ return NPERR_INVALID_PARAM; // TODO(brettw) call callback.
+ }
+ return ctx->Flush(&committed_bitmap_, context, callback, id, user_data);
}
NPError WebPluginDelegatePepper::Device2DDestroyContext(
NPDeviceContext2D* context) {
- OpenPaintContextMap::iterator found = open_paint_contexts_.find(
- context->region);
- if (found == open_paint_contexts_.end())
- return NPERR_INVALID_PARAM;
- open_paint_contexts_.erase(found);
- // Free the implementation information.
- delete reinterpret_cast<Device2DImpl*>(context->reserved);
+ if (!context || !graphic2d_contexts_.Lookup(
+ reinterpret_cast<intptr_t>(context->reserved))) {
+ return NPERR_INVALID_PARAM;
+ }
+ graphic2d_contexts_.Remove(reinterpret_cast<intptr_t>(context->reserved));
+ memset(context, 0, sizeof(NPDeviceContext2D));
return NPERR_NO_ERROR;
}
@@ -585,39 +504,14 @@ NPError WebPluginDelegatePepper::DeviceAudioInitializeContext(
return NPERR_GENERIC_ERROR;
}
- scoped_refptr<AudioMessageFilter> filter =
- render_view_->audio_message_filter();
- ViewHostMsg_Audio_CreateStream params;
-
- params.format = AudioManager::AUDIO_PCM_LINEAR;
- params.channels = config->outputChannelMap;
- params.sample_rate = config->sampleRate;
- switch (config->sampleType) {
- case NPAudioSampleTypeInt16:
- params.bits_per_sample = 16;
- break;
- case NPAudioSampleTypeFloat32:
- params.bits_per_sample = 32;
- break;
- default:
- return NPERR_INVALID_PARAM;
+ scoped_ptr<AudioDeviceContext> audio(new AudioDeviceContext());
+ NPError status = audio->Initialize(render_view_->audio_message_filter(),
+ config, context);
+ if (NPERR_NO_ERROR == status) {
+ context->reserved =
+ reinterpret_cast<void *>(audio_contexts_.Add(audio.release()));
}
-
- context->config = *config;
- params.packet_size = config->sampleFrameCount * config->outputChannelMap
- * (params.bits_per_sample >> 3);
- LOG(INFO) << "Initializing Pepper Audio Context (" <<
- config->sampleFrameCount << "Hz, " << params.bits_per_sample <<
- " bits, " << config->outputChannelMap << "channels";
-
- // TODO(neb): figure out if this number is grounded in reality
- params.buffer_capacity = params.packet_size * 3;
-
- // TODO(neb): keep these guys tracked somewhere so we can delete them
- // even if the plugin doesn't
- AudioStream *audio = new AudioStream(this);
- audio->Initialize(filter, params, context);
- return NPERR_NO_ERROR;
+ return status;
}
NPError WebPluginDelegatePepper::DeviceAudioSetStateContext(
@@ -647,73 +541,21 @@ NPError WebPluginDelegatePepper::DeviceAudioFlushContext(
NPError WebPluginDelegatePepper::DeviceAudioDestroyContext(
NPDeviceContextAudio* context) {
- if (!context || !context->privatePtr) {
+ if (!context || !audio_contexts_.Lookup(
+ reinterpret_cast<intptr_t>(context->reserved))) {
return NPERR_INVALID_PARAM;
}
- delete reinterpret_cast<AudioStream *>(context->privatePtr);
+ audio_contexts_.Remove(reinterpret_cast<intptr_t>(context->reserved));
memset(context, 0, sizeof(NPDeviceContextAudio));
return NPERR_NO_ERROR;
}
-WebPluginDelegatePepper::AudioStream::~AudioStream() {
- if (stream_id_) {
- OnDestroy();
- }
-}
-
-void WebPluginDelegatePepper::AudioStream::Initialize(
- AudioMessageFilter* filter, const ViewHostMsg_Audio_CreateStream& params,
- NPDeviceContextAudio* context) {
- filter_ = filter;
- context_= context;
- context_->privatePtr = this;
- // Make sure we don't call init more than once.
- DCHECK_EQ(0, stream_id_);
- stream_id_ = filter_->AddDelegate(this);
- filter->Send(new ViewHostMsg_CreateAudioStream(0, stream_id_, params));
-}
-
-void WebPluginDelegatePepper::AudioStream::OnDestroy() {
- // Make sure we don't call destroy more than once.
- DCHECK_NE(0, stream_id_);
- filter_->RemoveDelegate(stream_id_);
- filter_->Send(new ViewHostMsg_CloseAudioStream(0, stream_id_));
- stream_id_ = 0;
-}
-
-void WebPluginDelegatePepper::AudioStream::OnRequestPacket(
- size_t bytes_in_buffer, const base::Time& message_timestamp) {
- context_->config.callback(context_);
- filter_->Send(new ViewHostMsg_NotifyAudioPacketReady(0, stream_id_,
- shared_memory_size_));
-}
-
-void WebPluginDelegatePepper::AudioStream::OnStateChanged(
- ViewMsg_AudioStreamState state) {
-}
-
-void WebPluginDelegatePepper::AudioStream::OnCreated(
- base::SharedMemoryHandle handle, size_t length) {
- shared_memory_.reset(new base::SharedMemory(handle, false));
- shared_memory_->Map(length);
- shared_memory_size_ = length;
-
- context_->outBuffer = shared_memory_->memory();
- // TODO(neb): call play after prefilling
- filter_->Send(new ViewHostMsg_PlayAudioStream(0, stream_id_));
-}
-
-void WebPluginDelegatePepper::AudioStream::OnVolume(double volume) {
-}
-
WebPluginDelegatePepper::WebPluginDelegatePepper(
const base::WeakPtr<RenderView>& render_view,
NPAPI::PluginInstance *instance)
: render_view_(render_view),
plugin_(NULL),
instance_(instance),
- buffer_size_(0),
- plugin_buffer_(0),
nested_delegate_(NULL) {
// For now we keep a window struct, although it isn't used.
memset(&window_, 0, sizeof(window_));
diff --git a/chrome/renderer/webplugin_delegate_pepper.h b/chrome/renderer/webplugin_delegate_pepper.h
index 608748c..91e35b6 100644
--- a/chrome/renderer/webplugin_delegate_pepper.h
+++ b/chrome/renderer/webplugin_delegate_pepper.h
@@ -13,20 +13,15 @@
#include "app/gfx/native_widget_types.h"
#include "base/file_path.h"
-#include "base/linked_ptr.h"
+#include "base/id_map.h"
#include "base/gfx/rect.h"
#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
#include "base/task.h"
#include "base/weak_ptr.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/transport_dib.h"
-#include "chrome/renderer/audio_message_filter.h"
+#include "chrome/renderer/pepper_devices.h"
#include "chrome/renderer/render_view.h"
#include "chrome/renderer/command_buffer_proxy.h"
-#include "skia/ext/platform_canvas.h"
#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
#include "webkit/glue/webcursor.h"
#include "webkit/glue/webplugin_delegate.h"
@@ -145,40 +140,6 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate {
// End of WebPluginDelegate implementation.
- // Each instance of AudioStream corresponds to one host stream (and one
- // audio context). NPDeviceContextAudio contains a pointer to the context's
- // stream as privatePtr.
- class AudioStream : public AudioMessageFilter::Delegate {
- public:
- // TODO(neb): if plugin_delegate parameter is indeed unused, remove it
- explicit AudioStream(WebPluginDelegatePepper* plugin_delegate)
- : plugin_delegate_(plugin_delegate), stream_id_(0) {
- }
- virtual ~AudioStream();
-
- void Initialize(AudioMessageFilter *filter,
- const ViewHostMsg_Audio_CreateStream& params,
- NPDeviceContextAudio* context);
-
- // AudioMessageFilter::Delegate implementation
- virtual void OnRequestPacket(size_t bytes_in_buffer,
- const base::Time& message_timestamp);
- virtual void OnStateChanged(ViewMsg_AudioStreamState state);
- virtual void OnCreated(base::SharedMemoryHandle handle, size_t length);
- virtual void OnVolume(double volume);
- // End of AudioMessageFilter::Delegate implementation
-
- private:
- void OnDestroy();
-
- NPDeviceContextAudio *context_;
- WebPluginDelegatePepper* plugin_delegate_;
- scoped_refptr<AudioMessageFilter> filter_;
- int32 stream_id_;
- scoped_ptr<base::SharedMemory> shared_memory_;
- size_t shared_memory_size_;
- };
-
gfx::Rect GetRect() const { return window_rect_; }
gfx::Rect GetClipRect() const { return clip_rect_; }
@@ -213,26 +174,13 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate {
gfx::Rect clip_rect_;
std::vector<gfx::Rect> cutout_rects_;
+ // Open device contexts
+ IDMap<Graphics2DDeviceContext, IDMapOwnPointer> graphic2d_contexts_;
+ IDMap<AudioDeviceContext, IDMapOwnPointer> audio_contexts_;
+
// Plugin graphics context implementation
- size_t buffer_size_;
- TransportDIB* plugin_buffer_;
- static uint32 next_buffer_id;
SkBitmap committed_bitmap_;
- // Lists all contexts currently open for painting. These are ones requested by
- // the plugin but not destroyed by it yet. The source pointer is the raw
- // pixels. We use this to look up the corresponding transport DIB when the
- // plugin tells us to flush or destroy it.
- struct OpenPaintContext {
- scoped_ptr<TransportDIB> transport_dib;
-
- // The canvas associated with the transport DIB, containing the mapped
- // memory of the image.
- scoped_ptr<skia::PlatformCanvas> canvas;
- };
- typedef std::map< void*, linked_ptr<OpenPaintContext> > OpenPaintContextMap;
- OpenPaintContextMap open_paint_contexts_;
-
// The url with which the plugin was instantiated.
std::string plugin_url_;
diff --git a/third_party/npapi/bindings/npapi_extensions.h b/third_party/npapi/bindings/npapi_extensions.h
index a53ead2..c24cd99 100644
--- a/third_party/npapi/bindings/npapi_extensions.h
+++ b/third_party/npapi/bindings/npapi_extensions.h
@@ -29,7 +29,7 @@ typedef struct _NPDeviceBuffer {
/* completion callback for flush device */
typedef void (*NPDeviceFlushContextCallbackPtr)(
- NPP instace,
+ NPP instance,
NPDeviceContext* context,
NPError err,
NPUserData* userData);
@@ -378,11 +378,10 @@ typedef struct _NPDeviceContextAudioConfig {
} NPDeviceContextAudioConfig;
struct _NPDeviceContextAudio {
-// NPP npp;
NPDeviceContextAudioConfig config;
void *outBuffer;
void *inBuffer;
- void *privatePtr;
+ void *reserved;
};
#endif /* _NP_EXTENSIONS_H_ */