diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/plugin/webplugin_delegate_stub.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/plugin/webplugin_delegate_stub.cc')
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.cc | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc new file mode 100644 index 0000000..0678b14 --- /dev/null +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -0,0 +1,462 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/plugin/webplugin_delegate_stub.h" + +#include "base/command_line.h" +#include "base/time.h" +#include "base/gfx/bitmap_header.h" +#include "base/gfx/platform_device.h" +#include "bindings/npapi.h" +#include "bindings/npruntime.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/gfx/emf.h" +#include "chrome/common/plugin_messages.h" +#include "chrome/common/win_util.h" +#include "chrome/plugin/npobject_stub.h" +#include "chrome/plugin/plugin_channel.h" +#include "chrome/plugin/plugin_thread.h" +#include "chrome/plugin/webplugin_proxy.h" +#include "webkit/glue/plugins/webplugin_delegate_impl.h" +#include "webkit/glue/webcursor.h" + +class FinishDestructionTask : public Task { + public: + FinishDestructionTask(WebPluginDelegate* delegate, WebPlugin* webplugin) + : delegate_(delegate), webplugin_(webplugin) { } + + void Run() { + // WebPlugin must outlive WebPluginDelegate. + if (delegate_) + delegate_->PluginDestroyed(); + + delete webplugin_; + } + + private: + WebPluginDelegate* delegate_; + WebPlugin* webplugin_; +}; + +WebPluginDelegateStub::WebPluginDelegateStub( + const std::string& mime_type, int instance_id, PluginChannel* channel) : + mime_type_(mime_type), + instance_id_(instance_id), + channel_(channel), + delegate_(NULL), + webplugin_(NULL) { + DCHECK(channel); +} + +WebPluginDelegateStub::~WebPluginDelegateStub() { + if (channel_->in_send()) { + // The delegate or an npobject is in the callstack, so don't delete it + // right away. + MessageLoop::current()->PostTask(FROM_HERE, + new FinishDestructionTask(delegate_, webplugin_)); + } else { + // Safe to delete right away. + if (delegate_) + delegate_->PluginDestroyed(); + + delete webplugin_; + } +} + +void WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) { + // A plugin can execute a script to delete itself in any of its NPP methods. + // Hold an extra reference to ourself so that if this does occur and we're + // handling a sync message, we don't crash when attempting to send a reply. + AddRef(); + + IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateStub, msg) + IPC_MESSAGE_HANDLER(PluginMsg_Init, OnInit) + IPC_MESSAGE_HANDLER(PluginMsg_WillSendRequest, OnWillSendRequest) + IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveResponse, OnDidReceiveResponse) + IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveData, OnDidReceiveData) + IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoading, OnDidFinishLoading) + IPC_MESSAGE_HANDLER(PluginMsg_DidFail, OnDidFail) + IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoadWithReason, + OnDidFinishLoadWithReason) + IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus) + IPC_MESSAGE_HANDLER(PluginMsg_HandleEvent, OnHandleEvent) + IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint) + IPC_MESSAGE_HANDLER(PluginMsg_Print, OnPrint) + IPC_MESSAGE_HANDLER(PluginMsg_PaintIntoSharedMemory, + OnPaintIntoSharedMemory) + IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject, + OnGetPluginScriptableObject) + IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry) + IPC_MESSAGE_HANDLER(PluginMsg_SendJavaScriptStream, + OnSendJavaScriptStream) + IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse, + OnDidReceiveManualResponse) + IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualData, OnDidReceiveManualData) + IPC_MESSAGE_HANDLER(PluginMsg_DidFinishManualLoading, + OnDidFinishManualLoading) + IPC_MESSAGE_HANDLER(PluginMsg_DidManualLoadFail, OnDidManualLoadFail) + IPC_MESSAGE_HANDLER(PluginMsg_InstallMissingPlugin, OnInstallMissingPlugin) + IPC_MESSAGE_HANDLER(PluginMsg_HandleURLRequestReply, OnHandleURLRequestReply) + IPC_MESSAGE_HANDLER(PluginMsg_URLRequestRouted, OnURLRequestRouted) + IPC_MESSAGE_UNHANDLED_ERROR() + IPC_END_MESSAGE_MAP() + + Release(); +} + +bool WebPluginDelegateStub::Send(IPC::Message* msg) { + return channel_->Send(msg); +} + +void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params, + bool* result) { + *result = false; + int argc = static_cast<int>(params.arg_names.size()); + if (argc != static_cast<int>(params.arg_values.size())) { + NOTREACHED(); + return; + } + + char **argn = new char*[argc]; + char **argv = new char*[argc]; + for (int i = 0; i < argc; ++i) { + argn[i] = const_cast<char*>(params.arg_names[i].c_str()); + argv[i] = const_cast<char*>(params.arg_values[i].c_str()); + } + + CommandLine command_line; + std::wstring path = command_line.GetSwitchValue(switches::kPluginPath); + delegate_ = WebPluginDelegateImpl::Create( + path, mime_type_, params.containing_window); + if (delegate_) { + webplugin_ = new WebPluginProxy( + channel_, instance_id_, delegate_, params.modal_dialog_event); + *result = delegate_->Initialize( + params.url, argn, argv, argc, webplugin_, params.load_manually); + } + + delete[] argn; + delete[] argv; +} + +void WebPluginDelegateStub::OnWillSendRequest(int id, const GURL& url) { + WebPluginResourceClient* client = webplugin_->GetResourceClient(id); + if (!client) + return; + + client->WillSendRequest(url); +} + +void WebPluginDelegateStub::OnDidReceiveResponse( + const PluginMsg_DidReceiveResponseParams& params, bool* cancel) { + *cancel = false; + WebPluginResourceClient* client = webplugin_->GetResourceClient(params.id); + if (!client) + return; + + client->DidReceiveResponse(params.mime_type, + params.headers, + params.expected_length, + params.last_modified, + cancel); +} + +void WebPluginDelegateStub::OnDidReceiveData(int id, + const std::vector<char>& buffer) { + WebPluginResourceClient* client = webplugin_->GetResourceClient(id); + if (!client) + return; + + client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size())); +} + +void WebPluginDelegateStub::OnDidFinishLoading(int id) { + WebPluginResourceClient* client = webplugin_->GetResourceClient(id); + if (!client) + return; + + client->DidFinishLoading(); +} + +void WebPluginDelegateStub::OnDidFail(int id) { + WebPluginResourceClient* client = webplugin_->GetResourceClient(id); + if (!client) + return; + + client->DidFail(); +} + +void WebPluginDelegateStub::OnDidFinishLoadWithReason(int reason) { + delegate_->DidFinishLoadWithReason(reason); +} + +void WebPluginDelegateStub::OnSetFocus() { + delegate_->SetFocus(); +} + +void WebPluginDelegateStub::OnHandleEvent(const NPEvent& event, + bool* handled, + WebCursor* cursor) { + *handled = delegate_->HandleEvent(const_cast<NPEvent*>(&event), cursor); +} + +void WebPluginDelegateStub::OnPaint(const PluginMsg_Paint_Params& params) { + // Convert the shared memory handle to a handle that works in our process, + // and then use that to create an HDC. + win_util::ScopedHandle shared_section(win_util::GetSectionFromProcess( + params.shared_memory, channel_->renderer_handle(), false)); + + if (shared_section == NULL) { + NOTREACHED(); + return; + } + + void* data = NULL; + HDC screen_dc = GetDC(NULL); + BITMAPINFOHEADER bitmap_header; + gfx::CreateBitmapHeader(params.size.width(), params.size.height(), + &bitmap_header); + win_util::ScopedBitmap hbitmap(CreateDIBSection( + screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header), + DIB_RGB_COLORS, &data, + shared_section, 0)); + ReleaseDC(NULL, screen_dc); + if (hbitmap == NULL) { + NOTREACHED(); + return; + } + + win_util::ScopedHDC hdc(CreateCompatibleDC(NULL)); + if (hdc == NULL) { + NOTREACHED(); + return; + } + gfx::PlatformDevice::InitializeDC(hdc); + SelectObject(hdc, hbitmap); + SetWorldTransform(hdc, ¶ms.xf); + + win_util::ScopedHRGN hrgn(CreateRectRgnIndirect(¶ms.clip_rect.ToRECT())); + SelectClipRgn(hdc, hrgn); + webplugin_->WillPaint(); + delegate_->Paint(hdc, params.damaged_rect); +} + +void WebPluginDelegateStub::OnPrint(PluginMsg_PrintResponse_Params* params) { + gfx::Emf emf; + if (!emf.CreateDc(NULL, NULL)) { + NOTREACHED(); + return; + } + HDC hdc = emf.hdc(); + gfx::PlatformDevice::InitializeDC(hdc); + delegate_->Print(hdc); + if (!emf.CloseDc()) { + NOTREACHED(); + return; + } + + size_t size = emf.GetDataSize(); + DCHECK(size); + params->size = size; + SharedMemory shared_buf; + CreateSharedBuffer(size, &shared_buf, ¶ms->shared_memory); + + // Retrieve a copy of the data. + bool success = emf.GetData(shared_buf.memory(), size); + DCHECK(success); +} + +void WebPluginDelegateStub::OnPaintIntoSharedMemory( + const PluginMsg_Paint_Params& params, + SharedMemoryHandle* emf_buffer, + size_t* bytes) { + *emf_buffer = NULL; + *bytes = 0; + + gfx::Emf emf; + if (!emf.CreateDc(NULL, NULL)) { + NOTREACHED(); + return; + } + HDC hdc = emf.hdc(); + gfx::PlatformDevice::InitializeDC(hdc); + + if (delegate_->windowless()) { + WindowlessPaint(hdc, params); + } else { + WindowedPaint(hdc, params.damaged_rect); + } + + // Need to send back the data as shared memory. + if (!emf.CloseDc()) { + NOTREACHED(); + return; + } + + size_t size = emf.GetDataSize(); + DCHECK(size); + *bytes = size; + SharedMemory shared_buf; + CreateSharedBuffer(size, &shared_buf, emf_buffer); + + // Retrieve a copy of the data. + bool success = emf.GetData(shared_buf.memory(), size); + DCHECK(success); +} + +void WebPluginDelegateStub::WindowedPaint(HDC hdc, + const gfx::Rect& window_rect) { + // Use the NPAPI print() function to render the plugin. + delegate_->Print(hdc); +} + +void WebPluginDelegateStub::WindowlessPaint( + HDC hdc, + const PluginMsg_Paint_Params& params) { + void* data = NULL; + HDC screen_dc = GetDC(NULL); + BITMAPINFOHEADER bitmap_header; + gfx::CreateBitmapHeader(params.size.width(), params.size.height(), + &bitmap_header); + win_util::ScopedBitmap hbitmap(CreateDIBSection( + screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header), + DIB_RGB_COLORS, &data, NULL, 0)); + ReleaseDC(NULL, screen_dc); + if (hbitmap == NULL) { + NOTREACHED(); + return; + } + SelectObject(hdc, hbitmap); + + // Apply transform and clipping. + SetWorldTransform(hdc, ¶ms.xf); + win_util::ScopedHRGN hrgn(CreateRectRgnIndirect(¶ms.clip_rect.ToRECT())); + SelectClipRgn(hdc, hrgn); + webplugin_->WillPaint(); + delegate_->Paint(hdc, params.damaged_rect); +} + +void WebPluginDelegateStub::OnUpdateGeometry(const gfx::Rect& window_rect, + const gfx::Rect& clip_rect, + bool visible) { + delegate_->UpdateGeometry(window_rect, clip_rect, visible); +} + +void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id, + void** npobject_ptr) { + NPObject* object = delegate_->GetPluginScriptableObject(); + if (!object) { + *route_id = MSG_ROUTING_NONE; + return; + } + + *route_id = channel_->GenerateRouteID(); + *npobject_ptr = object; + // The stub will delete itself when the proxy tells it that it's released, or + // otherwise when the channel is closed. + NPObjectStub* stub = new NPObjectStub(object, channel_.get(), *route_id); + + // Release ref added by GetPluginScriptableObject (our stub holds its own). + NPN_ReleaseObject(object); +} + +void WebPluginDelegateStub::OnSendJavaScriptStream(const std::string& url, + const std::wstring& result, + bool success, + bool notify_needed, + int notify_data) { + delegate_->SendJavaScriptStream(url, result, success, notify_needed, + notify_data); +} + +void WebPluginDelegateStub::OnDidReceiveManualResponse( + const std::string& url, + const PluginMsg_DidReceiveResponseParams& params) { + delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers, + params.expected_length, + params.last_modified); +} + +void WebPluginDelegateStub::OnDidReceiveManualData( + const std::vector<char>& buffer) { + delegate_->DidReceiveManualData(&buffer.front(), + static_cast<int>(buffer.size())); +} + +void WebPluginDelegateStub::OnDidFinishManualLoading() { + delegate_->DidFinishManualLoading(); +} + +void WebPluginDelegateStub::OnDidManualLoadFail() { + delegate_->DidManualLoadFail(); +} + +void WebPluginDelegateStub::OnInstallMissingPlugin() { + delegate_->InstallMissingPlugin(); +} + +void WebPluginDelegateStub::CreateSharedBuffer( + size_t size, + SharedMemory* shared_buf, + SharedMemoryHandle* remote_handle) { + if (!shared_buf->Create(std::wstring(), false, false, size)) { + NOTREACHED(); + return; + } + if (!shared_buf->Map(size)) { + NOTREACHED(); + shared_buf->Close(); + return; + } + + BOOL result = DuplicateHandle(GetCurrentProcess(), + shared_buf->handle(), + channel_->renderer_handle(), + remote_handle, 0, FALSE, + DUPLICATE_SAME_ACCESS); + DCHECK_NE(result, 0); + // If the calling function's shared_buf is on the stack, its destructor will + // close the shared memory buffer handle. This is fine since we already + // duplicated the handle to the renderer process so it will stay "alive". +} + +void WebPluginDelegateStub::OnHandleURLRequestReply( + const PluginMsg_URLRequestReply_Params& params) { + WebPluginResourceClient* resource_client = + delegate_->CreateResourceClient(params.resource_id, params.url, + params.notify_needed, + params.notify_data); + webplugin_->OnResourceCreated(params.resource_id, resource_client); +} + +void WebPluginDelegateStub::OnURLRequestRouted(const std::string& url, + bool notify_needed, + HANDLE notify_data) { + delegate_->URLRequestRouted(url, notify_needed, notify_data); +} |