diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-16 18:15:52 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-16 18:15:52 +0000 |
commit | 0bd753681a82634f322d4867b19148474c25566b (patch) | |
tree | 2f96cb4494c075ddee5a3e42e6b41c096a5357a9 /webkit/plugins | |
parent | d1d0afe664ff43825a4585f88ee8ce412eab0194 (diff) | |
download | chromium_src-0bd753681a82634f322d4867b19148474c25566b.zip chromium_src-0bd753681a82634f322d4867b19148474c25566b.tar.gz chromium_src-0bd753681a82634f322d4867b19148474c25566b.tar.bz2 |
Move the Pepper implementation from webkit/glue/plugins/pepper_* to
webkit/plugins/ppapi/*. This renamed the files and interface implementation
classes from foo.cc/Foo to ppb_foo_impl/PPB_Foo_Impl to match the proxy
ppb_foo_proxy/PPB_Foo_Proxy.
This moves plugin_switches.* from webkit/glue/plugins to webkit/plugins.
Review URL: http://codereview.chromium.org/5828003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69424 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/plugins')
90 files changed, 15432 insertions, 0 deletions
diff --git a/webkit/plugins/plugin_switches.cc b/webkit/plugins/plugin_switches.cc new file mode 100644 index 0000000..be3342c --- /dev/null +++ b/webkit/plugins/plugin_switches.cc @@ -0,0 +1,15 @@ +// 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 "webkit/plugins/plugin_switches.h" + +namespace switches { + +// Enables the testing interface for PPAPI. +const char kEnablePepperTesting[] = "enable-pepper-testing"; + +// Dumps extra logging about plugin loading to the log file. +const char kDebugPluginLoading[] = "debug-plugin-loading"; + +} // namespace switches diff --git a/webkit/plugins/plugin_switches.h b/webkit/plugins/plugin_switches.h new file mode 100644 index 0000000..7497ec1 --- /dev/null +++ b/webkit/plugins/plugin_switches.h @@ -0,0 +1,15 @@ +// 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 WEBKIT_PLUGINS_PLUGIN_SWITCHES_H_ +#define WEBKIT_PLUGINS_PLUGIN_SWITCHES_H_ + +namespace switches { + +extern const char kDebugPluginLoading[]; +extern const char kEnablePepperTesting[]; + +} // namespace switches + +#endif // WEBKIT_PLUGINS_PLUGIN_SWITCHES_H_ diff --git a/webkit/plugins/ppapi/DEPS b/webkit/plugins/ppapi/DEPS new file mode 100644 index 0000000..884f203 --- /dev/null +++ b/webkit/plugins/ppapi/DEPS @@ -0,0 +1,8 @@ +include_rules = [ + "+app", + "+gpu/command_buffer", + "+ppapi/c", + "+ppapi/shared_impl", + "+printing", + "+skia", +] diff --git a/webkit/plugins/ppapi/common.h b/webkit/plugins/ppapi/common.h new file mode 100644 index 0000000..542bad9 --- /dev/null +++ b/webkit/plugins/ppapi/common.h @@ -0,0 +1,26 @@ +// 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 WEBKIT_PLUGINS_PPAPI_COMMON_H_ +#define WEBKIT_PLUGINS_PPAPI_COMMON_H_ + +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_var.h" + +namespace webkit { +namespace ppapi { + +inline PP_Bool BoolToPPBool(bool value) { + return value ? PP_TRUE : PP_FALSE; +} + +inline bool PPBoolToBool(PP_Bool value) { + return (PP_TRUE == value); +} + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_COMMON_H_ + diff --git a/webkit/plugins/ppapi/dir_contents.h b/webkit/plugins/ppapi/dir_contents.h new file mode 100644 index 0000000..f9a6c45 --- /dev/null +++ b/webkit/plugins/ppapi/dir_contents.h @@ -0,0 +1,25 @@ +// 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 WEBKIT_PLUGINS_PPAPI_DIR_CONTENTS_H_ +#define WEBKIT_PLUGINS_PPAPI_DIR_CONTENTS_H_ + +#include <vector> + +#include "base/file_path.h" + +namespace webkit { +namespace ppapi { + +struct DirEntry { + FilePath name; + bool is_dir; +}; + +typedef std::vector<DirEntry> DirContents; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_DIR_CONTENTS_H_ diff --git a/webkit/plugins/ppapi/error_util.cc b/webkit/plugins/ppapi/error_util.cc new file mode 100644 index 0000000..0ff127d --- /dev/null +++ b/webkit/plugins/ppapi/error_util.cc @@ -0,0 +1,36 @@ +// 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 "webkit/plugins/ppapi/error_util.h" + +#include "ppapi/c/pp_errors.h" + +namespace webkit { +namespace ppapi { + +int PlatformFileErrorToPepperError(base::PlatformFileError error_code) { + switch (error_code) { + case base::PLATFORM_FILE_OK: + return PP_OK; + case base::PLATFORM_FILE_ERROR_EXISTS: + return PP_ERROR_FILEEXISTS; + case base::PLATFORM_FILE_ERROR_NOT_FOUND: + return PP_ERROR_FILENOTFOUND; + case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: + case base::PLATFORM_FILE_ERROR_SECURITY: + return PP_ERROR_NOACCESS; + case base::PLATFORM_FILE_ERROR_NO_MEMORY: + return PP_ERROR_NOMEMORY; + case base::PLATFORM_FILE_ERROR_NO_SPACE: + return PP_ERROR_NOSPACE; + case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY: + return PP_ERROR_FAILED; + default: + return PP_ERROR_FAILED; + } +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/error_util.h b/webkit/plugins/ppapi/error_util.h new file mode 100644 index 0000000..660f7d2 --- /dev/null +++ b/webkit/plugins/ppapi/error_util.h @@ -0,0 +1,18 @@ +// 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 WEBKIT_PLUGINS_PPAPI_ERROR_UTIL_H_ +#define WEBKIT_PLUGINS_PPAPI_ERROR_UTIL_H_ + +#include "base/platform_file.h" + +namespace webkit { +namespace ppapi { + +int PlatformFileErrorToPepperError(base::PlatformFileError error_code); + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_ERROR_UTIL_H_ diff --git a/webkit/plugins/ppapi/event_conversion.cc b/webkit/plugins/ppapi/event_conversion.cc new file mode 100644 index 0000000..c5e8fac --- /dev/null +++ b/webkit/plugins/ppapi/event_conversion.cc @@ -0,0 +1,302 @@ +// 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 "webkit/plugins/ppapi/event_conversion.h" + +#include "base/i18n/char_iterator.h" +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "base/utf_string_conversion_utils.h" +#include "ppapi/c/pp_input_event.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "webkit/plugins/ppapi/common.h" + +using WebKit::WebInputEvent; +using WebKit::WebKeyboardEvent; +using WebKit::WebMouseEvent; +using WebKit::WebMouseWheelEvent; + +namespace webkit { +namespace ppapi { + +namespace { + +PP_InputEvent_Type ConvertEventTypes(WebInputEvent::Type wetype) { + switch (wetype) { + case WebInputEvent::MouseDown: + return PP_INPUTEVENT_TYPE_MOUSEDOWN; + case WebInputEvent::MouseUp: + return PP_INPUTEVENT_TYPE_MOUSEUP; + case WebInputEvent::MouseMove: + return PP_INPUTEVENT_TYPE_MOUSEMOVE; + case WebInputEvent::MouseEnter: + return PP_INPUTEVENT_TYPE_MOUSEENTER; + case WebInputEvent::MouseLeave: + return PP_INPUTEVENT_TYPE_MOUSELEAVE; + case WebInputEvent::MouseWheel: + return PP_INPUTEVENT_TYPE_MOUSEWHEEL; + case WebInputEvent::RawKeyDown: + return PP_INPUTEVENT_TYPE_RAWKEYDOWN; + case WebInputEvent::KeyDown: + return PP_INPUTEVENT_TYPE_KEYDOWN; + case WebInputEvent::KeyUp: + return PP_INPUTEVENT_TYPE_KEYUP; + case WebInputEvent::Char: + return PP_INPUTEVENT_TYPE_CHAR; + case WebInputEvent::Undefined: + default: + return PP_INPUTEVENT_TYPE_UNDEFINED; + } +} + +// Generates a PP_InputEvent with the fields common to all events, as well as +// the event type from the given web event. Event-specific fields will be zero +// initialized. +PP_InputEvent GetPPEventWithCommonFieldsAndType( + const WebInputEvent& web_event) { + PP_InputEvent result; + memset(&result, 0, sizeof(PP_InputEvent)); + result.type = ConvertEventTypes(web_event.type); + // TODO(brettw) http://code.google.com/p/chromium/issues/detail?id=57448 + // This should use a tick count rather than the wall clock time that WebKit + // uses. + result.time_stamp = web_event.timeStampSeconds; + return result; +} + +void AppendKeyEvent(const WebInputEvent& event, + std::vector<PP_InputEvent>* pp_events) { + const WebKeyboardEvent& key_event = + reinterpret_cast<const WebKeyboardEvent&>(event); + PP_InputEvent result = GetPPEventWithCommonFieldsAndType(event); + result.u.key.modifier = key_event.modifiers; + result.u.key.key_code = key_event.windowsKeyCode; + pp_events->push_back(result); +} + +void AppendCharEvent(const WebInputEvent& event, + std::vector<PP_InputEvent>* pp_events) { + const WebKeyboardEvent& key_event = + reinterpret_cast<const WebKeyboardEvent&>(event); + + // This is a bit complex, the input event will normally just have one 16-bit + // character in it, but may be zero or more than one. The text array is + // just padded with 0 values for the unused ones, but is not necessarily + // null-terminated. + // + // Here we see how many UTF-16 characters we have. + size_t utf16_char_count = 0; + while (utf16_char_count < WebKeyboardEvent::textLengthCap && + key_event.text[utf16_char_count]) + utf16_char_count++; + + // Make a separate PP_InputEvent for each Unicode character in the input. + base::UTF16CharIterator iter(key_event.text, utf16_char_count); + while (!iter.end()) { + PP_InputEvent result = GetPPEventWithCommonFieldsAndType(event); + result.u.character.modifier = key_event.modifiers; + + std::string utf8_char; + base::WriteUnicodeCharacter(iter.get(), &utf8_char); + base::strlcpy(result.u.character.text, utf8_char.c_str(), + sizeof(result.u.character.text)); + + pp_events->push_back(result); + iter.Advance(); + } +} + +void AppendMouseEvent(const WebInputEvent& event, + std::vector<PP_InputEvent>* pp_events) { + COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonNone) == + static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_NONE), + MouseNone); + COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonLeft) == + static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_LEFT), + MouseLeft); + COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonRight) == + static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_RIGHT), + MouseRight); + COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonMiddle) == + static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_MIDDLE), + MouseMiddle); + + const WebMouseEvent& mouse_event = + reinterpret_cast<const WebMouseEvent&>(event); + PP_InputEvent result = GetPPEventWithCommonFieldsAndType(event); + result.u.mouse.modifier = mouse_event.modifiers; + result.u.mouse.button = + static_cast<PP_InputEvent_MouseButton>(mouse_event.button); + result.u.mouse.x = static_cast<float>(mouse_event.x); + result.u.mouse.y = static_cast<float>(mouse_event.y); + result.u.mouse.click_count = mouse_event.clickCount; + pp_events->push_back(result); +} + +void AppendMouseWheelEvent(const WebInputEvent& event, + std::vector<PP_InputEvent>* pp_events) { + const WebMouseWheelEvent& mouse_wheel_event = + reinterpret_cast<const WebMouseWheelEvent&>(event); + PP_InputEvent result = GetPPEventWithCommonFieldsAndType(event); + result.u.wheel.modifier = mouse_wheel_event.modifiers; + result.u.wheel.delta_x = mouse_wheel_event.deltaX; + result.u.wheel.delta_y = mouse_wheel_event.deltaY; + result.u.wheel.wheel_ticks_x = mouse_wheel_event.wheelTicksX; + result.u.wheel.wheel_ticks_y = mouse_wheel_event.wheelTicksY; + result.u.wheel.scroll_by_page = + BoolToPPBool(!!mouse_wheel_event.scrollByPage); + pp_events->push_back(result); +} + +WebKeyboardEvent* BuildKeyEvent(const PP_InputEvent& event) { + WebKeyboardEvent* key_event = new WebKeyboardEvent(); + switch (event.type) { + case PP_INPUTEVENT_TYPE_RAWKEYDOWN: + key_event->type = WebInputEvent::RawKeyDown; + break; + case PP_INPUTEVENT_TYPE_KEYDOWN: + key_event->type = WebInputEvent::KeyDown; + break; + case PP_INPUTEVENT_TYPE_KEYUP: + key_event->type = WebInputEvent::KeyUp; + break; + default: + NOTREACHED(); + } + key_event->timeStampSeconds = event.time_stamp; + key_event->modifiers = event.u.key.modifier; + key_event->windowsKeyCode = event.u.key.key_code; + return key_event; +} + +WebKeyboardEvent* BuildCharEvent(const PP_InputEvent& event) { + WebKeyboardEvent* key_event = new WebKeyboardEvent(); + key_event->type = WebInputEvent::Char; + key_event->timeStampSeconds = event.time_stamp; + key_event->modifiers = event.u.character.modifier; + + // Make sure to not read beyond the buffer in case some bad code doesn't + // NULL-terminate it (this is called from plugins). + size_t text_length_cap = WebKeyboardEvent::textLengthCap; + size_t text_len = 0; + while (text_len < text_length_cap && event.u.character.text[text_len]) + text_len++; + string16 text16 = UTF8ToUTF16(std::string(event.u.character.text, text_len)); + + memset(key_event->text, 0, text_length_cap); + memset(key_event->unmodifiedText, 0, text_length_cap); + for (size_t i = 0; + i < std::min(text_length_cap, text16.size()); + ++i) + key_event->text[i] = text16[i]; + return key_event; +} + +WebMouseEvent* BuildMouseEvent(const PP_InputEvent& event) { + WebMouseEvent* mouse_event = new WebMouseEvent(); + switch (event.type) { + case PP_INPUTEVENT_TYPE_MOUSEDOWN: + mouse_event->type = WebInputEvent::MouseDown; + break; + case PP_INPUTEVENT_TYPE_MOUSEUP: + mouse_event->type = WebInputEvent::MouseUp; + break; + case PP_INPUTEVENT_TYPE_MOUSEMOVE: + mouse_event->type = WebInputEvent::MouseMove; + break; + case PP_INPUTEVENT_TYPE_MOUSEENTER: + mouse_event->type = WebInputEvent::MouseEnter; + break; + case PP_INPUTEVENT_TYPE_MOUSELEAVE: + mouse_event->type = WebInputEvent::MouseLeave; + break; + default: + NOTREACHED(); + } + mouse_event->timeStampSeconds = event.time_stamp; + mouse_event->modifiers = event.u.mouse.modifier; + mouse_event->button = + static_cast<WebMouseEvent::Button>(event.u.mouse.button); + mouse_event->x = static_cast<int>(event.u.mouse.x); + mouse_event->y = static_cast<int>(event.u.mouse.y); + mouse_event->clickCount = event.u.mouse.click_count; + return mouse_event; +} + +WebMouseWheelEvent* BuildMouseWheelEvent(const PP_InputEvent& event) { + WebMouseWheelEvent* mouse_wheel_event = new WebMouseWheelEvent(); + mouse_wheel_event->type = WebInputEvent::MouseWheel; + mouse_wheel_event->timeStampSeconds = event.time_stamp; + mouse_wheel_event->modifiers = event.u.wheel.modifier; + mouse_wheel_event->deltaX = event.u.wheel.delta_x; + mouse_wheel_event->deltaY = event.u.wheel.delta_y; + mouse_wheel_event->wheelTicksX = event.u.wheel.wheel_ticks_x; + mouse_wheel_event->wheelTicksY = event.u.wheel.wheel_ticks_y; + mouse_wheel_event->scrollByPage = event.u.wheel.scroll_by_page; + return mouse_wheel_event; +} + +} // namespace + +void CreatePPEvent(const WebInputEvent& event, + std::vector<PP_InputEvent>* pp_events) { + pp_events->clear(); + + switch (event.type) { + case WebInputEvent::MouseDown: + case WebInputEvent::MouseUp: + case WebInputEvent::MouseMove: + case WebInputEvent::MouseEnter: + case WebInputEvent::MouseLeave: + AppendMouseEvent(event, pp_events); + break; + case WebInputEvent::MouseWheel: + AppendMouseWheelEvent(event, pp_events); + break; + case WebInputEvent::RawKeyDown: + case WebInputEvent::KeyDown: + case WebInputEvent::KeyUp: + AppendKeyEvent(event, pp_events); + break; + case WebInputEvent::Char: + AppendCharEvent(event, pp_events); + break; + case WebInputEvent::Undefined: + default: + break; + } +} + +WebInputEvent* CreateWebInputEvent(const PP_InputEvent& event) { + scoped_ptr<WebInputEvent> web_input_event; + switch (event.type) { + case PP_INPUTEVENT_TYPE_UNDEFINED: + return NULL; + case PP_INPUTEVENT_TYPE_MOUSEDOWN: + case PP_INPUTEVENT_TYPE_MOUSEUP: + case PP_INPUTEVENT_TYPE_MOUSEMOVE: + case PP_INPUTEVENT_TYPE_MOUSEENTER: + case PP_INPUTEVENT_TYPE_MOUSELEAVE: + web_input_event.reset(BuildMouseEvent(event)); + break; + case PP_INPUTEVENT_TYPE_MOUSEWHEEL: + web_input_event.reset(BuildMouseWheelEvent(event)); + break; + case PP_INPUTEVENT_TYPE_RAWKEYDOWN: + case PP_INPUTEVENT_TYPE_KEYDOWN: + case PP_INPUTEVENT_TYPE_KEYUP: + web_input_event.reset(BuildKeyEvent(event)); + break; + case PP_INPUTEVENT_TYPE_CHAR: + web_input_event.reset(BuildCharEvent(event)); + break; + } + + return web_input_event.release(); +} +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/event_conversion.h b/webkit/plugins/ppapi/event_conversion.h new file mode 100644 index 0000000..71beee6 --- /dev/null +++ b/webkit/plugins/ppapi/event_conversion.h @@ -0,0 +1,32 @@ +// 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 WEBKIT_PLUGINS_PPAPI_EVENT_CONVERSION_H_ +#define WEBKIT_PLUGINS_PPAPI_EVENT_CONVERSION_H_ + +#include <vector> + +struct PP_InputEvent; + +namespace WebKit { +class WebInputEvent; +} + +namespace webkit { +namespace ppapi { + +// Converts the given WebKit event to one or possibly multiple PP_InputEvents. +// The generated events will be filled into the given vector. On failure, no +// events will ge generated and the vector will be empty. +void CreatePPEvent(const WebKit::WebInputEvent& event, + std::vector<PP_InputEvent>* pp_events); + +// Creates a WebInputEvent from the given PP_InputEvent. If it fails, returns +// NULL. The caller owns the created object on success. +WebKit::WebInputEvent* CreateWebInputEvent(const PP_InputEvent& event); + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_EVENT_CONVERSION_H_ diff --git a/webkit/plugins/ppapi/file_callbacks.cc b/webkit/plugins/ppapi/file_callbacks.cc new file mode 100644 index 0000000..9f991be --- /dev/null +++ b/webkit/plugins/ppapi/file_callbacks.cc @@ -0,0 +1,103 @@ +// 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 "webkit/plugins/ppapi/file_callbacks.h" + +#include "base/file_path.h" +#include "base/logging.h" +#include "ppapi/c/dev/ppb_file_system_dev.h" +#include "ppapi/c/dev/pp_file_info_dev.h" +#include "ppapi/c/pp_errors.h" +#include "webkit/plugins/ppapi/ppb_directory_reader_impl.h" +#include "webkit/plugins/ppapi/error_util.h" +#include "webkit/plugins/ppapi/ppb_file_system_impl.h" +#include "webkit/fileapi/file_system_types.h" + +namespace webkit { +namespace ppapi { + +FileCallbacks::FileCallbacks( + const base::WeakPtr<PluginModule>& module, + PP_CompletionCallback callback, + PP_FileInfo_Dev* info, + scoped_refptr<PPB_FileSystem_Impl> file_system, + scoped_refptr<PPB_DirectoryReader_Impl> directory_reader) + : module_(module), + callback_(callback), + info_(info), + file_system_(file_system), + directory_reader_(directory_reader) { +} + +FileCallbacks::~FileCallbacks() {} + +void FileCallbacks::DidSucceed() { + if (!module_.get() || !callback_.func) + return; + + PP_RunCompletionCallback(&callback_, PP_OK); +} + +void FileCallbacks::DidReadMetadata( + const base::PlatformFileInfo& file_info) { + if (!module_.get() || !callback_.func) + return; + + DCHECK(info_); + DCHECK(file_system_); + info_->size = file_info.size; + info_->creation_time = file_info.creation_time.ToDoubleT(); + info_->last_access_time = file_info.last_accessed.ToDoubleT(); + info_->last_modified_time = file_info.last_modified.ToDoubleT(); + info_->system_type = file_system_->type(); + if (file_info.is_directory) + info_->type = PP_FILETYPE_DIRECTORY; + else + info_->type = PP_FILETYPE_REGULAR; + + PP_RunCompletionCallback(&callback_, PP_OK); +} + +void FileCallbacks::DidReadDirectory( + const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more) { + if (!module_.get() || !callback_.func) + return; + + DCHECK(directory_reader_); + directory_reader_->AddNewEntries(entries, has_more); + + PP_RunCompletionCallback(&callback_, PP_OK); +} + +void FileCallbacks::DidOpenFileSystem(const std::string&, + const FilePath& root_path) { + if (!module_.get() || !callback_.func) + return; + + DCHECK(file_system_); + file_system_->set_root_path(root_path); + file_system_->set_opened(true); + + PP_RunCompletionCallback(&callback_, PP_OK); +} + +void FileCallbacks::DidFail(base::PlatformFileError error_code) { + RunCallback(error_code); +} + +void FileCallbacks::DidWrite(int64 bytes, bool complete) { + NOTREACHED(); +} + +void FileCallbacks::RunCallback(base::PlatformFileError error_code) { + if (!module_.get() || !callback_.func) + return; + + PP_RunCompletionCallback( + &callback_, PlatformFileErrorToPepperError(error_code)); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/file_callbacks.h b/webkit/plugins/ppapi/file_callbacks.h new file mode 100644 index 0000000..4b96d1c --- /dev/null +++ b/webkit/plugins/ppapi/file_callbacks.h @@ -0,0 +1,59 @@ +// 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 WEBKIT_PLUGINS_PPAPI_FILE_CALLBACKS_H_ +#define WEBKIT_PLUGINS_PPAPI_FILE_CALLBACKS_H_ + +#include "base/platform_file.h" +#include "base/weak_ptr.h" +#include "ppapi/c/pp_completion_callback.h" +#include "webkit/fileapi/file_system_callback_dispatcher.h" + +struct PP_FileInfo_Dev; + +namespace base { +class FilePath; +} + +namespace webkit { +namespace ppapi { + +class PPB_DirectoryReader_Impl; +class PPB_FileSystem_Impl; +class PluginModule; + +// Instances of this class are deleted by FileSystemDispatcher. +class FileCallbacks : public fileapi::FileSystemCallbackDispatcher { + public: + FileCallbacks(const base::WeakPtr<PluginModule>& module, + PP_CompletionCallback callback, + PP_FileInfo_Dev* info, + scoped_refptr<PPB_FileSystem_Impl> file_system, + scoped_refptr<PPB_DirectoryReader_Impl> directory_reader); + virtual ~FileCallbacks(); + + // FileSystemCallbackDispatcher implementation. + virtual void DidSucceed(); + virtual void DidReadMetadata(const base::PlatformFileInfo& file_info); + virtual void DidReadDirectory( + const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more); + virtual void DidOpenFileSystem(const std::string&, + const FilePath& root_path); + virtual void DidFail(base::PlatformFileError error_code); + virtual void DidWrite(int64 bytes, bool complete); + + private: + void RunCallback(base::PlatformFileError error_code); + + base::WeakPtr<PluginModule> module_; + PP_CompletionCallback callback_; + PP_FileInfo_Dev* info_; + scoped_refptr<PPB_FileSystem_Impl> file_system_; + scoped_refptr<PPB_DirectoryReader_Impl> directory_reader_; +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_FILE_CALLBACKS_H_ diff --git a/webkit/plugins/ppapi/fullscreen_container.h b/webkit/plugins/ppapi/fullscreen_container.h new file mode 100644 index 0000000..8318282 --- /dev/null +++ b/webkit/plugins/ppapi/fullscreen_container.h @@ -0,0 +1,38 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_FULLSCREEN_CONTAINER_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_FULLSCREEN_CONTAINER_IMPL_H_ + +namespace WebKit { +struct WebRect; +} // namespace WebKit + +namespace webkit { +namespace ppapi { + +// This class is like a lightweight WebPluginContainer for fullscreen PPAPI +// plugins, that only handles painting. +class FullscreenContainer { + public: + virtual ~FullscreenContainer() {} + + // Invalidates the full plugin region. + virtual void Invalidate() = 0; + + // Invalidates a partial region of the plugin. + virtual void InvalidateRect(const WebKit::WebRect&) = 0; + + // Scrolls a partial region of the plugin in the given direction. + virtual void ScrollRect(int dx, int dy, const WebKit::WebRect&) = 0; + + // Destroys the fullscreen window. This also destroys the FullscreenContainer + // instance. + virtual void Destroy() = 0; +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_FULLSCREEN_CONTAINER_IMPL_H_ diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.cc b/webkit/plugins/ppapi/mock_plugin_delegate.cc new file mode 100644 index 0000000..93ace2c --- /dev/null +++ b/webkit/plugins/ppapi/mock_plugin_delegate.cc @@ -0,0 +1,190 @@ +// 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 "webkit/plugins/ppapi/mock_plugin_delegate.h" + +#include "base/message_loop_proxy.h" + +namespace webkit { +namespace ppapi { + +MockPluginDelegate::MockPluginDelegate() { +} + +MockPluginDelegate::~MockPluginDelegate() { +} + +void MockPluginDelegate::InstanceCreated(PluginInstance* instance) { +} + +void MockPluginDelegate::InstanceDeleted(PluginInstance* instance) { +} + +MockPluginDelegate::PlatformImage2D* MockPluginDelegate::CreateImage2D( + int width, + int height) { + return NULL; +} + +MockPluginDelegate::PlatformContext3D* MockPluginDelegate::CreateContext3D() { + return NULL; +} + +MockPluginDelegate::PlatformVideoDecoder* +MockPluginDelegate::CreateVideoDecoder( + const PP_VideoDecoderConfig_Dev& decoder_config) { + return NULL; +} + +MockPluginDelegate::PlatformAudio* MockPluginDelegate::CreateAudio( + uint32_t sample_rate, + uint32_t sample_count, + PlatformAudio::Client* client) { + return NULL; +} + +void MockPluginDelegate::NumberOfFindResultsChanged(int identifier, + int total, + bool final_result) { +} + +void MockPluginDelegate::SelectedFindResultChanged(int identifier, int index) { +} + +bool MockPluginDelegate::RunFileChooser( + const WebKit::WebFileChooserParams& params, + WebKit::WebFileChooserCompletion* chooser_completion) { + return false; +} + +bool MockPluginDelegate::AsyncOpenFile(const FilePath& path, + int flags, + AsyncOpenFileCallback* callback) { + return false; +} + +bool MockPluginDelegate::OpenFileSystem( + const GURL& url, + fileapi::FileSystemType type, + long long size, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + return false; +} + +bool MockPluginDelegate::MakeDirectory( + const FilePath& path, + bool recursive, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + return false; +} + +bool MockPluginDelegate::Query( + const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + return false; +} + +bool MockPluginDelegate::Touch( + const FilePath& path, + const base::Time& last_access_time, + const base::Time& last_modified_time, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + return false; +} + +bool MockPluginDelegate::Delete( + const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + return false; +} + +bool MockPluginDelegate::Rename( + const FilePath& file_path, + const FilePath& new_file_path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + return false; +} + +bool MockPluginDelegate::ReadDirectory( + const FilePath& directory_path, + fileapi::FileSystemCallbackDispatcher* dispatcher) { + return false; +} + +base::PlatformFileError MockPluginDelegate::OpenModuleLocalFile( + const std::string& module_name, + const FilePath& path, + int flags, + base::PlatformFile* file) { + return base::PLATFORM_FILE_ERROR_FAILED; +} + +base::PlatformFileError MockPluginDelegate::RenameModuleLocalFile( + const std::string& module_name, + const FilePath& path_from, + const FilePath& path_to) { + return base::PLATFORM_FILE_ERROR_FAILED; +} + +base::PlatformFileError MockPluginDelegate::DeleteModuleLocalFileOrDir( + const std::string& module_name, + const FilePath& path, + bool recursive) { + return base::PLATFORM_FILE_ERROR_FAILED; +} + +base::PlatformFileError MockPluginDelegate::CreateModuleLocalDir( + const std::string& module_name, + const FilePath& path) { + return base::PLATFORM_FILE_ERROR_FAILED; +} + +base::PlatformFileError MockPluginDelegate::QueryModuleLocalFile( + const std::string& module_name, + const FilePath& path, + base::PlatformFileInfo* info) { + return base::PLATFORM_FILE_ERROR_FAILED; +} + +base::PlatformFileError MockPluginDelegate::GetModuleLocalDirContents( + const std::string& module_name, + const FilePath& path, + DirContents* contents) { + return base::PLATFORM_FILE_ERROR_FAILED; +} + +scoped_refptr<base::MessageLoopProxy> +MockPluginDelegate::GetFileThreadMessageLoopProxy() { + return scoped_refptr<base::MessageLoopProxy>(); +} + +FullscreenContainer* MockPluginDelegate::CreateFullscreenContainer( + PluginInstance* instance) { + return NULL; +} + +std::string MockPluginDelegate::GetDefaultEncoding() { + return "iso-8859-1"; +} + +void MockPluginDelegate::ZoomLimitsChanged(double minimum_factor, + double maximum_factor) { +} + +std::string MockPluginDelegate::ResolveProxy(const GURL& url) { + return std::string(); +} + +void MockPluginDelegate::DidStartLoading() { +} + +void MockPluginDelegate::DidStopLoading() { +} + +void MockPluginDelegate::SetContentRestriction(int restrictions) { +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.h b/webkit/plugins/ppapi/mock_plugin_delegate.h new file mode 100644 index 0000000..4f83a80 --- /dev/null +++ b/webkit/plugins/ppapi/mock_plugin_delegate.h @@ -0,0 +1,100 @@ +// 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 WEBKIT_PLUGINS_PPAPI_MOCK_PLUGIN_DELEGATE_H_ +#define WEBKIT_PLUGINS_PPAPI_MOCK_PLUGIN_DELEGATE_H_ + +#include "webkit/plugins/ppapi/plugin_delegate.h" + +namespace webkit { +namespace ppapi { + +class MockPluginDelegate : public PluginDelegate { + public: + MockPluginDelegate(); + ~MockPluginDelegate(); + + virtual void InstanceCreated(PluginInstance* instance); + virtual void InstanceDeleted(PluginInstance* instance); + virtual PlatformImage2D* CreateImage2D(int width, int height); + virtual PlatformContext3D* CreateContext3D(); + virtual PlatformVideoDecoder* CreateVideoDecoder( + const PP_VideoDecoderConfig_Dev& decoder_config); + virtual PlatformAudio* CreateAudio(uint32_t sample_rate, + uint32_t sample_count, + PlatformAudio::Client* client); + virtual void NumberOfFindResultsChanged(int identifier, + int total, + bool final_result); + virtual void SelectedFindResultChanged(int identifier, int index); + virtual bool RunFileChooser( + const WebKit::WebFileChooserParams& params, + WebKit::WebFileChooserCompletion* chooser_completion); + virtual bool AsyncOpenFile(const FilePath& path, + int flags, + AsyncOpenFileCallback* callback); + virtual bool OpenFileSystem( + const GURL& url, + fileapi::FileSystemType type, + long long size, + fileapi::FileSystemCallbackDispatcher* dispatcher); + virtual bool MakeDirectory( + const FilePath& path, + bool recursive, + fileapi::FileSystemCallbackDispatcher* dispatcher); + virtual bool Query(const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher); + virtual bool Touch(const FilePath& path, + const base::Time& last_access_time, + const base::Time& last_modified_time, + fileapi::FileSystemCallbackDispatcher* dispatcher); + virtual bool Delete(const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher); + virtual bool Rename(const FilePath& file_path, + const FilePath& new_file_path, + fileapi::FileSystemCallbackDispatcher* dispatcher); + virtual bool ReadDirectory( + const FilePath& directory_path, + fileapi::FileSystemCallbackDispatcher* dispatcher); + virtual base::PlatformFileError OpenModuleLocalFile( + const std::string& module_name, + const FilePath& path, + int flags, + base::PlatformFile* file); + virtual base::PlatformFileError RenameModuleLocalFile( + const std::string& module_name, + const FilePath& path_from, + const FilePath& path_to); + virtual base::PlatformFileError DeleteModuleLocalFileOrDir( + const std::string& module_name, + const FilePath& path, + bool recursive); + virtual base::PlatformFileError CreateModuleLocalDir( + const std::string& module_name, + const FilePath& path); + virtual base::PlatformFileError QueryModuleLocalFile( + const std::string& module_name, + const FilePath& path, + base::PlatformFileInfo* info); + virtual base::PlatformFileError GetModuleLocalDirContents( + const std::string& module_name, + const FilePath& path, + DirContents* contents); + virtual scoped_refptr<base::MessageLoopProxy> + GetFileThreadMessageLoopProxy(); + virtual FullscreenContainer* CreateFullscreenContainer( + PluginInstance* instance); + virtual std::string GetDefaultEncoding(); + virtual void ZoomLimitsChanged(double minimum_factor, + double maximum_factor); + virtual std::string ResolveProxy(const GURL& url); + virtual void DidStartLoading(); + virtual void DidStopLoading(); + virtual void SetContentRestriction(int restrictions); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_MOCK_PLUGIN_DELEGATE_H_ diff --git a/webkit/plugins/ppapi/mock_resource.h b/webkit/plugins/ppapi/mock_resource.h new file mode 100644 index 0000000..081c990 --- /dev/null +++ b/webkit/plugins/ppapi/mock_resource.h @@ -0,0 +1,27 @@ +// 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 WEBKIT_PLUGINS_PPAPI_MOCK_RESOURCE_H_ +#define WEBKIT_PLUGINS_PPAPI_MOCK_RESOURCE_H_ + +#include "webkit/plugins/ppapi/resource.h" + +namespace webkit { +namespace ppapi { + +// Tests can derive from this to implement special test-specific resources. +// It's assumed that a test will only need one mock resource, so it can +// static_cast to get its own implementation. +class MockResource : public Resource { + public: + MockResource(PluginModule* module) : Resource(module) {} + ~MockResource() {} + + virtual MockResource* AsMockResource() { return this; } +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_MOCK_RESOURCE_H_ diff --git a/webkit/plugins/ppapi/npapi_glue.cc b/webkit/plugins/ppapi/npapi_glue.cc new file mode 100644 index 0000000..d22c13f --- /dev/null +++ b/webkit/plugins/ppapi/npapi_glue.cc @@ -0,0 +1,199 @@ +// 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 "webkit/plugins/ppapi/npapi_glue.h" + +#include "base/logging.h" +#include "base/ref_counted.h" +#include "base/string_util.h" +#include "webkit/plugins/ppapi/plugin_object.h" +#include "webkit/plugins/ppapi/var.h" +#include "third_party/npapi/bindings/npapi.h" +#include "third_party/npapi/bindings/npruntime.h" +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" + +using WebKit::WebBindings; + +namespace webkit { +namespace ppapi { + +namespace { + +const char kInvalidPluginValue[] = "Error: Plugin returned invalid value."; + +} // namespace + +// Utilities ------------------------------------------------------------------- + +bool PPVarToNPVariant(PP_Var var, NPVariant* result) { + switch (var.type) { + case PP_VARTYPE_UNDEFINED: + VOID_TO_NPVARIANT(*result); + break; + case PP_VARTYPE_NULL: + NULL_TO_NPVARIANT(*result); + break; + case PP_VARTYPE_BOOL: + BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result); + break; + case PP_VARTYPE_INT32: + INT32_TO_NPVARIANT(var.value.as_int, *result); + break; + case PP_VARTYPE_DOUBLE: + DOUBLE_TO_NPVARIANT(var.value.as_double, *result); + break; + case PP_VARTYPE_STRING: { + scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); + if (!string) { + VOID_TO_NPVARIANT(*result); + return false; + } + const std::string& value = string->value(); + STRINGN_TO_NPVARIANT(base::strdup(value.c_str()), value.size(), *result); + break; + } + case PP_VARTYPE_OBJECT: { + scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var)); + if (!object) { + VOID_TO_NPVARIANT(*result); + return false; + } + OBJECT_TO_NPVARIANT(WebBindings::retainObject(object->np_object()), + *result); + break; + } + } + return true; +} + +// PPResultAndExceptionToNPResult ---------------------------------------------- + +PPResultAndExceptionToNPResult::PPResultAndExceptionToNPResult( + NPObject* object_var, + NPVariant* np_result) + : object_var_(object_var), + np_result_(np_result), + exception_(PP_MakeUndefined()), + success_(false), + checked_exception_(false) { +} + +PPResultAndExceptionToNPResult::~PPResultAndExceptionToNPResult() { + // The user should have called SetResult or CheckExceptionForNoResult + // before letting this class go out of scope, or the exception will have + // been lost. + DCHECK(checked_exception_); + + ObjectVar::PluginReleasePPVar(exception_); +} + +// Call this with the return value of the PPAPI function. It will convert +// the result to the NPVariant output parameter and pass any exception on to +// the JS engine. It will update the success flag and return it. +bool PPResultAndExceptionToNPResult::SetResult(PP_Var result) { + DCHECK(!checked_exception_); // Don't call more than once. + DCHECK(np_result_); // Should be expecting a result. + + checked_exception_ = true; + + if (has_exception()) { + ThrowException(); + success_ = false; + } else if (!PPVarToNPVariant(result, np_result_)) { + WebBindings::setException(object_var_, kInvalidPluginValue); + success_ = false; + } else { + success_ = true; + } + + // No matter what happened, we need to release the reference to the + // value passed in. On success, a reference to this value will be in + // the np_result_. + Var::PluginReleasePPVar(result); + return success_; +} + +// Call this after calling a PPAPI function that could have set the +// exception. It will pass the exception on to the JS engine and update +// the success flag. +// +// The success flag will be returned. +bool PPResultAndExceptionToNPResult::CheckExceptionForNoResult() { + DCHECK(!checked_exception_); // Don't call more than once. + DCHECK(!np_result_); // Can't have a result when doing this. + + checked_exception_ = true; + + if (has_exception()) { + ThrowException(); + success_ = false; + return false; + } + success_ = true; + return true; +} + +// Call this to ignore any exception. This prevents the DCHECK from failing +// in the destructor. +void PPResultAndExceptionToNPResult::IgnoreException() { + checked_exception_ = true; +} + +// Throws the current exception to JS. The exception must be set. +void PPResultAndExceptionToNPResult::ThrowException() { + scoped_refptr<StringVar> string(StringVar::FromPPVar(exception_)); + if (string) { + WebBindings::setException(object_var_, string->value().c_str()); + } +} + +// PPVarArrayFromNPVariantArray ------------------------------------------------ + +PPVarArrayFromNPVariantArray::PPVarArrayFromNPVariantArray(PluginModule* module, + size_t size, + const NPVariant* variants) + : size_(size) { + if (size_ > 0) { + array_.reset(new PP_Var[size_]); + for (size_t i = 0; i < size_; i++) + array_[i] = Var::NPVariantToPPVar(module, &variants[i]); + } +} + +PPVarArrayFromNPVariantArray::~PPVarArrayFromNPVariantArray() { + for (size_t i = 0; i < size_; i++) + Var::PluginReleasePPVar(array_[i]); +} + +// PPVarFromNPObject ----------------------------------------------------------- + +PPVarFromNPObject::PPVarFromNPObject(PluginModule* module, NPObject* object) + : var_(ObjectVar::NPObjectToPPVar(module, object)) { +} + +PPVarFromNPObject::~PPVarFromNPObject() { + Var::PluginReleasePPVar(var_); +} + +// NPObjectAccessorWithIdentifier ---------------------------------------------- + +NPObjectAccessorWithIdentifier::NPObjectAccessorWithIdentifier( + NPObject* object, + NPIdentifier identifier, + bool allow_integer_identifier) + : object_(PluginObject::FromNPObject(object)), + identifier_(PP_MakeUndefined()) { + if (object_) { + identifier_ = Var::NPIdentifierToPPVar(object_->module(), identifier); + if (identifier_.type == PP_VARTYPE_INT32 && !allow_integer_identifier) + identifier_.type = PP_VARTYPE_UNDEFINED; // Mark it invalid. + } +} + +NPObjectAccessorWithIdentifier::~NPObjectAccessorWithIdentifier() { + Var::PluginReleasePPVar(identifier_); +} + +} // namespace ppapi +} // namespace webkit diff --git a/webkit/plugins/ppapi/npapi_glue.h b/webkit/plugins/ppapi/npapi_glue.h new file mode 100644 index 0000000..11fd82a --- /dev/null +++ b/webkit/plugins/ppapi/npapi_glue.h @@ -0,0 +1,188 @@ +// 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 WEBKIT_PLUGINS_PPAPI_NPAPI_GLUE_H_ +#define WEBKIT_PLUGINS_PPAPI_NPAPI_GLUE_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "ppapi/c/pp_var.h" + +struct NPObject; +typedef struct _NPVariant NPVariant; +typedef void* NPIdentifier; + +namespace webkit { +namespace ppapi { + +class PluginModule; +class PluginObject; + +// Utilities ------------------------------------------------------------------- + +// Converts the given PP_Var to an NPVariant, returning true on success. +// False means that the given variant is invalid. In this case, the result +// NPVariant will be set to a void one. +// +// The contents of the PP_Var will be copied unless the PP_Var corresponds to +// an object. +bool PPVarToNPVariant(PP_Var var, NPVariant* result); + +// PPResultAndExceptionToNPResult ---------------------------------------------- + +// Convenience object for converting a PPAPI call that can throw an exception +// and optionally return a value, back to the NPAPI layer which expects a +// NPVariant as a result. +// +// Normal usage is that you will pass the result of exception() to the +// PPAPI function as the exception output parameter. Then you will either +// call SetResult with the result of the PPAPI call, or +// CheckExceptionForNoResult if the PPAPI call doesn't return a PP_Var. +// +// Both SetResult and CheckExceptionForNoResult will throw an exception to +// the JavaScript library if the plugin reported an exception. SetResult +// will additionally convert the result to an NPVariant and write it to the +// output parameter given in the constructor. +class PPResultAndExceptionToNPResult { + public: + // The object_var parameter is the object to associate any exception with. + // It may not be NULL. + // + // The np_result parameter is the NPAPI result output parameter. This may be + // NULL if there is no NPVariant result (like for HasProperty). If this is + // specified, you must call SetResult() to set it. If it is not, you must + // call CheckExceptionForNoResult to do the exception checking with no result + // conversion. + PPResultAndExceptionToNPResult(NPObject* object_var, NPVariant* np_result); + + ~PPResultAndExceptionToNPResult(); + + // Returns true if an exception has been set. + bool has_exception() const { return exception_.type != PP_VARTYPE_UNDEFINED; } + + // Returns a pointer to the exception. You would pass this to the PPAPI + // function as the exception parameter. If it is set to non-void, this object + // will take ownership of destroying it. + PP_Var* exception() { return &exception_; } + + // Returns true if everything succeeded with no exception. This is valid only + // after calling SetResult/CheckExceptionForNoResult. + bool success() const { + return success_; + } + + // Call this with the return value of the PPAPI function. It will convert + // the result to the NPVariant output parameter and pass any exception on to + // the JS engine. It will update the success flag and return it. + bool SetResult(PP_Var result); + + // Call this after calling a PPAPI function that could have set the + // exception. It will pass the exception on to the JS engine and update + // the success flag. + // + // The success flag will be returned. + bool CheckExceptionForNoResult(); + + // Call this to ignore any exception. This prevents the DCHECK from failing + // in the destructor. + void IgnoreException(); + + private: + // Throws the current exception to JS. The exception must be set. + void ThrowException(); + + NPObject* object_var_; // Non-owning ref (see constructor). + NPVariant* np_result_; // Output value, possibly NULL (see constructor). + PP_Var exception_; // Exception set by the PPAPI call. We own a ref to it. + bool success_; // See the success() function above. + bool checked_exception_; // SetResult/CheckExceptionForNoResult was called. + + DISALLOW_COPY_AND_ASSIGN(PPResultAndExceptionToNPResult); +}; + +// PPVarArrayFromNPVariantArray ------------------------------------------------ + +// Converts an array of NPVariants to an array of PP_Var, and scopes the +// ownership of the PP_Var. This is used when converting argument lists from +// WebKit to the plugin. +class PPVarArrayFromNPVariantArray { + public: + PPVarArrayFromNPVariantArray(PluginModule* module, + size_t size, + const NPVariant* variants); + ~PPVarArrayFromNPVariantArray(); + + PP_Var* array() { return array_.get(); } + + private: + size_t size_; + scoped_array<PP_Var> array_; + + DISALLOW_COPY_AND_ASSIGN(PPVarArrayFromNPVariantArray); +}; + +// PPVarFromNPObject ----------------------------------------------------------- + +// Converts an NPObject tp PP_Var, and scopes the ownership of the PP_Var. This +// is used when converting 'this' pointer from WebKit to the plugin. +class PPVarFromNPObject { + public: + PPVarFromNPObject(PluginModule* module, NPObject* object); + ~PPVarFromNPObject(); + + PP_Var var() const { return var_; } + + private: + const PP_Var var_; + + DISALLOW_COPY_AND_ASSIGN(PPVarFromNPObject); +}; + +// NPObjectAccessorWithIdentifier ---------------------------------------------- + +// Helper class for our NPObject wrapper. This converts a call from WebKit +// where it gives us an NPObject and an NPIdentifier to an easily-accessible +// ObjectVar (corresponding to the NPObject) and PP_Var (corresponding to the +// NPIdentifier). +// +// If the NPObject or identifier is invalid, we'll set is_valid() to false. +// The caller should check is_valid() before doing anything with the class. +// +// JS can't have integer functions, so when dealing with these, we don't want +// to allow integer identifiers. The calling code can decode if it wants to +// allow integer identifiers (like for property access) or prohibit them +// (like for method calling) by setting |allow_integer_identifier|. If this +// is false and the identifier is an integer, we'll set is_valid() to false. +// +// Getting an integer identifier in this case should be impossible. V8 +// shouldn't be allowing this, and the Pepper Var calls from the plugin are +// supposed to error out before calling into V8 (which will then call us back). +// Aside from an egregious error, the only time this could happen is an NPAPI +// plugin calling us. +class NPObjectAccessorWithIdentifier { + public: + NPObjectAccessorWithIdentifier(NPObject* object, + NPIdentifier identifier, + bool allow_integer_identifier); + ~NPObjectAccessorWithIdentifier(); + + // Returns true if both the object and identifier are valid. + bool is_valid() const { + return object_ && identifier_.type != PP_VARTYPE_UNDEFINED; + } + + PluginObject* object() { return object_; } + PP_Var identifier() const { return identifier_; } + + private: + PluginObject* object_; + PP_Var identifier_; + + DISALLOW_COPY_AND_ASSIGN(NPObjectAccessorWithIdentifier); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_NPAPI_GLUE_H_ diff --git a/webkit/plugins/ppapi/plugin_delegate.h b/webkit/plugins/ppapi/plugin_delegate.h new file mode 100644 index 0000000..fef6cff --- /dev/null +++ b/webkit/plugins/ppapi/plugin_delegate.h @@ -0,0 +1,314 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PLUGIN_DELEGATE_H_ +#define WEBKIT_PLUGINS_PPAPI_PLUGIN_DELEGATE_H_ + +#include <string> + +#include "base/callback.h" +#include "base/platform_file.h" +#include "base/ref_counted.h" +#include "base/shared_memory.h" +#include "base/sync_socket.h" +#include "gfx/size.h" +#include "googleurl/src/gurl.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_stdint.h" +#include "webkit/fileapi/file_system_types.h" +#include "webkit/plugins/ppapi/dir_contents.h" + +class AudioMessageFilter; +class GURL; + +namespace base { +class MessageLoopProxy; +class Time; +} + +namespace fileapi { +class FileSystemCallbackDispatcher; +} + +namespace gfx { +class Rect; +} + +namespace gpu { +namespace gles2 { +class GLES2Implementation; +} +} + +namespace skia { +class PlatformCanvas; +} + +namespace WebKit { +class WebFileChooserCompletion; +struct WebFileChooserParams; +} + +struct PP_VideoCompressedDataBuffer_Dev; +struct PP_VideoDecoderConfig_Dev; +struct PP_VideoUncompressedDataBuffer_Dev; + +class TransportDIB; + +namespace webkit { +namespace ppapi { + +class FileIO; +class PluginInstance; +class FullscreenContainer; + +// Virtual interface that the browser implements to implement features for +// PPAPI plugins. +class PluginDelegate { + public: + // This class is implemented by the PluginDelegate implementation and is + // designed to manage the lifetime and communicatin with the proxy's + // HostDispatcher for out-of-process PPAPI plugins. + // + // The point of this is to avoid having a relationship from the PPAPI plugin + // implementation to the ppapi proxy code. Otherwise, things like the IPC + // system will be dependencies of the webkit directory, which we don't want. + // + // The PluginModule will scope the lifetime of this object to its own + // lifetime, so the implementation can use this to manage the HostDispatcher + // lifetime without introducing the dependency. + class OutOfProcessProxy { + public: + virtual ~OutOfProcessProxy() {} + + // Implements GetInterface for the proxied plugin. + virtual const void* GetProxiedInterface(const char* name) = 0; + + // Notification to the out-of-process layer that the given plugin instance + // has been created. This will happen before the normal PPB_Instance method + // calls so the out-of-process code can set up the tracking information for + // the new instance. + virtual void AddInstance(PP_Instance instance) = 0; + + // Like AddInstance but removes the given instance. This is called after + // regular instance shutdown so the out-of-process code can clean up its + // tracking information. + virtual void RemoveInstance(PP_Instance instance) = 0; + }; + + // Represents an image. This is to allow the browser layer to supply a correct + // image representation. In Chrome, this will be a TransportDIB. + class PlatformImage2D { + public: + virtual ~PlatformImage2D() {} + + // Caller will own the returned pointer, returns NULL on failure. + virtual skia::PlatformCanvas* Map() = 0; + + // Returns the platform-specific shared memory handle of the data backing + // this image. This is used by PPAPI proxying to send the image to the + // out-of-process plugin. On success, the size in bytes will be placed into + // |*bytes_count|. Returns 0 on failure. + virtual intptr_t GetSharedMemoryHandle(uint32* byte_count) const = 0; + + virtual TransportDIB* GetTransportDIB() const = 0; + }; + + class PlatformContext3D { + public: + virtual ~PlatformContext3D() {} + + // Initialize the context. + virtual bool Init() = 0; + + // Present the rendered frame to the compositor. + virtual bool SwapBuffers() = 0; + + // Get the last EGL error. + virtual unsigned GetError() = 0; + + // Resize the backing texture used as a back buffer by OpenGL. + virtual void ResizeBackingTexture(const gfx::Size& size) = 0; + + // Set an optional callback that will be invoked when the side effects of + // a SwapBuffers call become visible to the compositor. Takes ownership + // of the callback. + virtual void SetSwapBuffersCallback(Callback0::Type* callback) = 0; + + // If the plugin instance is backed by an OpenGL, return its ID in the + // compositors namespace. Otherwise return 0. Returns 0 by default. + virtual unsigned GetBackingTextureId() = 0; + + // This call will return the address of the GLES2 implementation for this + // context that is constructed in Initialize() and is valid until this + // context is destroyed. + virtual gpu::gles2::GLES2Implementation* GetGLES2Implementation() = 0; + }; + + class PlatformAudio { + public: + class Client { + protected: + virtual ~Client() {} + + public: + // Called when the stream is created. + virtual void StreamCreated(base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size, + base::SyncSocket::Handle socket) = 0; + }; + + // Starts the playback. Returns false on error or if called before the + // stream is created or after the stream is closed. + virtual bool StartPlayback() = 0; + + // Stops the playback. Returns false on error or if called before the stream + // is created or after the stream is closed. + virtual bool StopPlayback() = 0; + + // Closes the stream. Make sure to call this before the object is + // destructed. + virtual void ShutDown() = 0; + + protected: + virtual ~PlatformAudio() {} + }; + + class PlatformVideoDecoder { + public: + virtual ~PlatformVideoDecoder() {} + + // Returns false on failure. + virtual bool Decode(PP_VideoCompressedDataBuffer_Dev& input_buffer) = 0; + virtual int32_t Flush(PP_CompletionCallback& callback) = 0; + virtual bool ReturnUncompressedDataBuffer( + PP_VideoUncompressedDataBuffer_Dev& buffer) = 0; + }; + + // Indicates that the given instance has been created. + virtual void InstanceCreated(PluginInstance* instance) = 0; + + // Indicates that the given instance is being destroyed. This is called from + // the destructor, so it's important that the instance is not dereferenced + // from this call. + virtual void InstanceDeleted(PluginInstance* instance) = 0; + + // The caller will own the pointer returned from this. + virtual PlatformImage2D* CreateImage2D(int width, int height) = 0; + + // The caller will own the pointer returned from this. + virtual PlatformContext3D* CreateContext3D() = 0; + + // The caller will own the pointer returned from this. + virtual PlatformVideoDecoder* CreateVideoDecoder( + const PP_VideoDecoderConfig_Dev& decoder_config) = 0; + + // The caller will own the pointer returned from this. + virtual PlatformAudio* CreateAudio(uint32_t sample_rate, + uint32_t sample_count, + PlatformAudio::Client* client) = 0; + + // Notifies that the number of find results has changed. + virtual void NumberOfFindResultsChanged(int identifier, + int total, + bool final_result) = 0; + + // Notifies that the index of the currently selected item has been updated. + virtual void SelectedFindResultChanged(int identifier, int index) = 0; + + // Runs a file chooser. + virtual bool RunFileChooser( + const WebKit::WebFileChooserParams& params, + WebKit::WebFileChooserCompletion* chooser_completion) = 0; + + // Sends an async IPC to open a file. + typedef Callback2<base::PlatformFileError, base::PlatformFile + >::Type AsyncOpenFileCallback; + virtual bool AsyncOpenFile(const FilePath& path, + int flags, + AsyncOpenFileCallback* callback) = 0; + virtual bool OpenFileSystem( + const GURL& url, + fileapi::FileSystemType type, + long long size, + fileapi::FileSystemCallbackDispatcher* dispatcher) = 0; + virtual bool MakeDirectory( + const FilePath& path, + bool recursive, + fileapi::FileSystemCallbackDispatcher* dispatcher) = 0; + virtual bool Query(const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher) = 0; + virtual bool Touch(const FilePath& path, + const base::Time& last_access_time, + const base::Time& last_modified_time, + fileapi::FileSystemCallbackDispatcher* dispatcher) = 0; + virtual bool Delete(const FilePath& path, + fileapi::FileSystemCallbackDispatcher* dispatcher) = 0; + virtual bool Rename(const FilePath& file_path, + const FilePath& new_file_path, + fileapi::FileSystemCallbackDispatcher* dispatcher) = 0; + virtual bool ReadDirectory( + const FilePath& directory_path, + fileapi::FileSystemCallbackDispatcher* dispatcher) = 0; + + virtual base::PlatformFileError OpenModuleLocalFile( + const std::string& module_name, + const FilePath& path, + int flags, + base::PlatformFile* file) = 0; + virtual base::PlatformFileError RenameModuleLocalFile( + const std::string& module_name, + const FilePath& path_from, + const FilePath& path_to) = 0; + virtual base::PlatformFileError DeleteModuleLocalFileOrDir( + const std::string& module_name, + const FilePath& path, + bool recursive) = 0; + virtual base::PlatformFileError CreateModuleLocalDir( + const std::string& module_name, + const FilePath& path) = 0; + virtual base::PlatformFileError QueryModuleLocalFile( + const std::string& module_name, + const FilePath& path, + base::PlatformFileInfo* info) = 0; + virtual base::PlatformFileError GetModuleLocalDirContents( + const std::string& module_name, + const FilePath& path, + DirContents* contents) = 0; + + // Returns a MessageLoopProxy instance associated with the message loop + // of the file thread in this renderer. + virtual scoped_refptr<base::MessageLoopProxy> + GetFileThreadMessageLoopProxy() = 0; + + // Create a fullscreen container for a plugin instance. This effectively + // switches the plugin to fullscreen. + virtual FullscreenContainer* CreateFullscreenContainer( + PluginInstance* instance) = 0; + + // Returns a string with the name of the default 8-bit char encoding. + virtual std::string GetDefaultEncoding() = 0; + + // Sets the mininum and maximium zoom factors. + virtual void ZoomLimitsChanged(double minimum_factor, + double maximum_factor) = 0; + + // Retrieves the proxy information for the given URL in PAC format. On error, + // this will return an empty string. + virtual std::string ResolveProxy(const GURL& url) = 0; + + // Tell the browser when resource loading starts/ends. + virtual void DidStartLoading() = 0; + virtual void DidStopLoading() = 0; + + // Sets restrictions on how the content can be used (i.e. no print/copy). + virtual void SetContentRestriction(int restrictions) = 0; +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PLUGIN_DELEGATE_H_ diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc new file mode 100644 index 0000000..96eadfb --- /dev/null +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -0,0 +1,498 @@ +// 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 "webkit/plugins/ppapi/plugin_module.h" + +#include <set> + +#include "base/command_line.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/time.h" +#include "ppapi/c/dev/ppb_buffer_dev.h" +#include "ppapi/c/dev/ppb_char_set_dev.h" +#include "ppapi/c/dev/ppb_cursor_control_dev.h" +#include "ppapi/c/dev/ppb_directory_reader_dev.h" +#include "ppapi/c/dev/ppb_file_io_dev.h" +#include "ppapi/c/dev/ppb_file_io_trusted_dev.h" +#include "ppapi/c/dev/ppb_file_system_dev.h" +#include "ppapi/c/dev/ppb_find_dev.h" +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/dev/ppb_fullscreen_dev.h" +#include "ppapi/c/dev/ppb_graphics_3d_dev.h" +#include "ppapi/c/dev/ppb_opengles_dev.h" +#include "ppapi/c/dev/ppb_scrollbar_dev.h" +#include "ppapi/c/dev/ppb_testing_dev.h" +#include "ppapi/c/dev/ppb_transport_dev.h" +#include "ppapi/c/dev/ppb_url_util_dev.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/dev/ppb_video_decoder_dev.h" +#include "ppapi/c/dev/ppb_widget_dev.h" +#include "ppapi/c/dev/ppb_zoom_dev.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_class.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/ppb_graphics_2d.h" +#include "ppapi/c/ppb_image_data.h" +#include "ppapi/c/ppb_instance.h" +#include "ppapi/c/ppb_url_loader.h" +#include "ppapi/c/ppb_url_request_info.h" +#include "ppapi/c/ppb_url_response_info.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/c/ppp.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/c/trusted/ppb_image_data_trusted.h" +#include "ppapi/c/trusted/ppb_url_loader_trusted.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_object.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_audio_impl.h" +#include "webkit/plugins/ppapi/ppb_buffer_impl.h" +#include "webkit/plugins/ppapi/ppb_char_set_impl.h" +#include "webkit/plugins/ppapi/ppb_cursor_control_impl.h" +#include "webkit/plugins/ppapi/ppb_directory_reader_impl.h" +#include "webkit/plugins/ppapi/ppb_file_chooser_impl.h" +#include "webkit/plugins/ppapi/ppb_file_io_impl.h" +#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" +#include "webkit/plugins/ppapi/ppb_file_system_impl.h" +#include "webkit/plugins/ppapi/ppb_flash.h" +#include "webkit/plugins/ppapi/ppb_flash_impl.h" +#include "webkit/plugins/ppapi/ppb_font_impl.h" +#include "webkit/plugins/ppapi/ppb_graphics_2d_impl.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" +#include "webkit/plugins/ppapi/ppb_pdf.h" +#include "webkit/plugins/ppapi/ppb_pdf_impl.h" +#include "webkit/plugins/ppapi/ppb_scrollbar_impl.h" +#include "webkit/plugins/ppapi/ppb_transport_impl.h" +#include "webkit/plugins/ppapi/ppb_url_loader_impl.h" +#include "webkit/plugins/ppapi/ppb_url_request_info_impl.h" +#include "webkit/plugins/ppapi/ppb_url_response_info_impl.h" +#include "webkit/plugins/ppapi/ppb_url_util_impl.h" +#include "webkit/plugins/ppapi/ppb_video_decoder_impl.h" +#include "webkit/plugins/ppapi/ppb_widget_impl.h" +#include "webkit/plugins/ppapi/resource_tracker.h" +#include "webkit/plugins/ppapi/var.h" +#include "webkit/plugins/ppapi/var_object_class.h" + +#ifdef ENABLE_GPU +#include "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" +#endif // ENABLE_GPU + +namespace webkit { +namespace ppapi { + +namespace { + +// Maintains all currently loaded plugin libs for validating PP_Module +// identifiers. +typedef std::set<PluginModule*> PluginModuleSet; + +PluginModuleSet* GetLivePluginSet() { + static PluginModuleSet live_plugin_libs; + return &live_plugin_libs; +} + +base::MessageLoopProxy* GetMainThreadMessageLoop() { + static scoped_refptr<base::MessageLoopProxy> proxy( + base::MessageLoopProxy::CreateForCurrentThread()); + return proxy.get(); +} + +// PPB_Core -------------------------------------------------------------------- + +void AddRefResource(PP_Resource resource) { + if (!ResourceTracker::Get()->AddRefResource(resource)) { + DLOG(WARNING) << "AddRefResource()ing a nonexistent resource"; + } +} + +void ReleaseResource(PP_Resource resource) { + if (!ResourceTracker::Get()->UnrefResource(resource)) { + DLOG(WARNING) << "ReleaseResource()ing a nonexistent resource"; + } +} + +void* MemAlloc(size_t num_bytes) { + return malloc(num_bytes); +} + +void MemFree(void* ptr) { + free(ptr); +} + +double GetTime() { + return base::Time::Now().ToDoubleT(); +} + +double GetTickTime() { + // TODO(brettw) http://code.google.com/p/chromium/issues/detail?id=57448 + // This should be a tick timer rather than wall clock time, but needs to + // match message times, which also currently use wall clock time. + return GetTime(); +} + +void CallOnMainThread(int delay_in_msec, + PP_CompletionCallback callback, + int32_t result) { + GetMainThreadMessageLoop()->PostDelayedTask( + FROM_HERE, + NewRunnableFunction(callback.func, callback.user_data, result), + delay_in_msec); +} + +PP_Bool IsMainThread() { + return BoolToPPBool(GetMainThreadMessageLoop()->BelongsToCurrentThread()); +} + +const PPB_Core core_interface = { + &AddRefResource, + &ReleaseResource, + &MemAlloc, + &MemFree, + &GetTime, + &GetTickTime, + &CallOnMainThread, + &IsMainThread +}; + +// PPB_Testing ----------------------------------------------------------------- + +PP_Bool ReadImageData(PP_Resource device_context_2d, + PP_Resource image, + const PP_Point* top_left) { + scoped_refptr<PPB_Graphics2D_Impl> context( + Resource::GetAs<PPB_Graphics2D_Impl>(device_context_2d)); + if (!context.get()) + return PP_FALSE; + return BoolToPPBool(context->ReadImageData(image, top_left)); +} + +void RunMessageLoop() { + bool old_state = MessageLoop::current()->NestableTasksAllowed(); + MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoop::current()->Run(); + MessageLoop::current()->SetNestableTasksAllowed(old_state); +} + +void QuitMessageLoop() { + MessageLoop::current()->QuitNow(); +} + +uint32_t GetLiveObjectCount(PP_Module module_id) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return static_cast<uint32_t>(-1); + return ResourceTracker::Get()->GetLiveObjectsForModule(module); +} + +const PPB_Testing_Dev testing_interface = { + &ReadImageData, + &RunMessageLoop, + &QuitMessageLoop, + &GetLiveObjectCount +}; + +// GetInterface ---------------------------------------------------------------- + +const void* GetInterface(const char* name) { + // Please keep alphabetized by interface macro name with "special" stuff at + // the bottom. + if (strcmp(name, PPB_AUDIO_CONFIG_DEV_INTERFACE) == 0) + return PPB_AudioConfig_Impl::GetInterface(); + if (strcmp(name, PPB_AUDIO_DEV_INTERFACE) == 0) + return PPB_Audio_Impl::GetInterface(); + if (strcmp(name, PPB_AUDIO_TRUSTED_DEV_INTERFACE) == 0) + return PPB_Audio_Impl::GetTrustedInterface(); + if (strcmp(name, PPB_BUFFER_DEV_INTERFACE) == 0) + return PPB_Buffer_Impl::GetInterface(); + if (strcmp(name, PPB_CHAR_SET_DEV_INTERFACE) == 0) + return PPB_CharSet_Impl::GetInterface(); + if (strcmp(name, PPB_CLASS_INTERFACE) == 0) + return VarObjectClass::GetInterface(); + if (strcmp(name, PPB_CORE_INTERFACE) == 0) + return &core_interface; + if (strcmp(name, PPB_CURSOR_CONTROL_DEV_INTERFACE) == 0) + return GetCursorControlInterface(); + if (strcmp(name, PPB_DIRECTORYREADER_DEV_INTERFACE) == 0) + return PPB_DirectoryReader_Impl::GetInterface(); + if (strcmp(name, PPB_FILECHOOSER_DEV_INTERFACE) == 0) + return PPB_FileChooser_Impl::GetInterface(); + if (strcmp(name, PPB_FILEIO_DEV_INTERFACE) == 0) + return PPB_FileIO_Impl::GetInterface(); + if (strcmp(name, PPB_FILEIOTRUSTED_DEV_INTERFACE) == 0) + return PPB_FileIO_Impl::GetTrustedInterface(); + if (strcmp(name, PPB_FILEREF_DEV_INTERFACE) == 0) + return PPB_FileRef_Impl::GetInterface(); + if (strcmp(name, PPB_FILESYSTEM_DEV_INTERFACE) == 0) + return PPB_FileSystem_Impl::GetInterface(); + if (strcmp(name, PPB_FIND_DEV_INTERFACE) == 0) + return PluginInstance::GetFindInterface(); + if (strcmp(name, PPB_FLASH_INTERFACE) == 0) + return PPB_Flash_Impl::GetInterface(); + if (strcmp(name, PPB_FONT_DEV_INTERFACE) == 0) + return PPB_Font_Impl::GetInterface(); + if (strcmp(name, PPB_FULLSCREEN_DEV_INTERFACE) == 0) + return PluginInstance::GetFullscreenInterface(); + if (strcmp(name, PPB_GRAPHICS_2D_INTERFACE) == 0) + return PPB_Graphics2D_Impl::GetInterface(); + if (strcmp(name, PPB_IMAGEDATA_INTERFACE) == 0) + return PPB_ImageData_Impl::GetInterface(); + if (strcmp(name, PPB_IMAGEDATA_TRUSTED_INTERFACE) == 0) + return PPB_ImageData_Impl::GetTrustedInterface(); + if (strcmp(name, PPB_INSTANCE_INTERFACE) == 0) + return PluginInstance::GetInterface(); + if (strcmp(name, PPB_PDF_INTERFACE) == 0) + return PPB_PDF_Impl::GetInterface(); + if (strcmp(name, PPB_SCROLLBAR_DEV_INTERFACE) == 0) + return PPB_Scrollbar_Impl::GetInterface(); + if (strcmp(name, PPB_TRANSPORT_DEV_INTERFACE) == 0) + return PPB_Transport_Impl::GetInterface(); + if (strcmp(name, PPB_URLLOADER_INTERFACE) == 0) + return PPB_URLLoader_Impl::GetInterface(); + if (strcmp(name, PPB_URLLOADERTRUSTED_INTERFACE) == 0) + return PPB_URLLoader_Impl::GetTrustedInterface(); + if (strcmp(name, PPB_URLREQUESTINFO_INTERFACE) == 0) + return PPB_URLRequestInfo_Impl::GetInterface(); + if (strcmp(name, PPB_URLRESPONSEINFO_INTERFACE) == 0) + return PPB_URLResponseInfo_Impl::GetInterface(); + if (strcmp(name, PPB_URLUTIL_DEV_INTERFACE) == 0) + return PPB_UrlUtil_Impl::GetInterface(); + if (strcmp(name, PPB_VAR_DEPRECATED_INTERFACE) == 0) + return Var::GetDeprecatedInterface(); + if (strcmp(name, PPB_VAR_INTERFACE) == 0) + return Var::GetInterface(); + if (strcmp(name, PPB_VIDEODECODER_DEV_INTERFACE) == 0) + return PPB_VideoDecoder_Impl::GetInterface(); + if (strcmp(name, PPB_WIDGET_DEV_INTERFACE) == 0) + return PPB_Widget_Impl::GetInterface(); + if (strcmp(name, PPB_ZOOM_DEV_INTERFACE) == 0) + return PluginInstance::GetZoomInterface(); + +#ifdef ENABLE_GPU + if (strcmp(name, PPB_GRAPHICS_3D_DEV_INTERFACE) == 0) + return PPB_Graphics3D_Impl::GetInterface(); + if (strcmp(name, PPB_OPENGLES_DEV_INTERFACE) == 0) + return PPB_Graphics3D_Impl::GetOpenGLESInterface(); +#endif // ENABLE_GPU + + // Only support the testing interface when the command line switch is + // specified. This allows us to prevent people from (ab)using this interface + // in production code. + if (strcmp(name, PPB_TESTING_DEV_INTERFACE) == 0) { + if (CommandLine::ForCurrentProcess()->HasSwitch("enable-pepper-testing")) + return &testing_interface; + } + return NULL; +} + +// Gets the PPAPI entry points from the given library and places them into the +// given structure. Returns true on success. +bool LoadEntryPointsFromLibrary(const base::NativeLibrary& library, + PluginModule::EntryPoints* entry_points) { + entry_points->get_interface = + reinterpret_cast<PluginModule::GetInterfaceFunc>( + base::GetFunctionPointerFromNativeLibrary(library, + "PPP_GetInterface")); + if (!entry_points->get_interface) { + LOG(WARNING) << "No PPP_GetInterface in plugin library"; + return false; + } + + entry_points->initialize_module = + reinterpret_cast<PluginModule::PPP_InitializeModuleFunc>( + base::GetFunctionPointerFromNativeLibrary(library, + "PPP_InitializeModule")); + if (!entry_points->initialize_module) { + LOG(WARNING) << "No PPP_InitializeModule in plugin library"; + return false; + } + + // It's okay for PPP_ShutdownModule to not be defined and shutdown_module to + // be NULL. + entry_points->shutdown_module = + reinterpret_cast<PluginModule::PPP_ShutdownModuleFunc>( + base::GetFunctionPointerFromNativeLibrary(library, + "PPP_ShutdownModule")); + + return true; +} + +} // namespace + +PluginModule::EntryPoints::EntryPoints() + : get_interface(NULL), + initialize_module(NULL), + shutdown_module(NULL) { +} + +// PluginModule ---------------------------------------------------------------- + +PluginModule::PluginModule() : library_(NULL) { + pp_module_ = ResourceTracker::Get()->AddModule(this); + GetMainThreadMessageLoop(); // Initialize the main thread message loop. + GetLivePluginSet()->insert(this); +} + +PluginModule::~PluginModule() { + // Free all the plugin objects. This will automatically clear the back- + // pointer from the NPObject so WebKit can't call into the plugin any more. + // + // Swap out the set so we can delete from it (the objects will try to + // unregister themselves inside the delete call). + PluginObjectSet plugin_object_copy; + live_plugin_objects_.swap(plugin_object_copy); + for (PluginObjectSet::iterator i = live_plugin_objects_.begin(); + i != live_plugin_objects_.end(); ++i) + delete *i; + + // When the module is being deleted, there should be no more instances still + // holding a reference to us. + DCHECK(instances_.empty()); + + GetLivePluginSet()->erase(this); + + if (entry_points_.shutdown_module) + entry_points_.shutdown_module(); + + if (library_) + base::UnloadNativeLibrary(library_); + + ResourceTracker::Get()->ModuleDeleted(pp_module_); +} + +bool PluginModule::InitAsInternalPlugin(const EntryPoints& entry_points) { + entry_points_ = entry_points; + return InitializeModule(); +} + +bool PluginModule::InitAsLibrary(const FilePath& path) { + base::NativeLibrary library = base::LoadNativeLibrary(path); + if (!library) + return false; + + if (!LoadEntryPointsFromLibrary(library, &entry_points_) || + !InitializeModule()) { + base::UnloadNativeLibrary(library); + return false; + } + + library_ = library; + return true; +} + +void PluginModule::InitAsProxied( + PluginDelegate::OutOfProcessProxy* out_of_process_proxy) { + DCHECK(!out_of_process_proxy_.get()); + out_of_process_proxy_.reset(out_of_process_proxy); +} + +// static +const PPB_Core* PluginModule::GetCore() { + return &core_interface; +} + +// static +PluginModule::GetInterfaceFunc PluginModule::GetLocalGetInterfaceFunc() { + return &GetInterface; +} + +PluginInstance* PluginModule::CreateInstance(PluginDelegate* delegate) { + const PPP_Instance* plugin_instance_interface = + reinterpret_cast<const PPP_Instance*>(GetPluginInterface( + PPP_INSTANCE_INTERFACE)); + if (!plugin_instance_interface) { + LOG(WARNING) << "Plugin doesn't support instance interface, failing."; + return NULL; + } + PluginInstance* instance = new PluginInstance(delegate, this, + plugin_instance_interface); + if (out_of_process_proxy_.get()) + out_of_process_proxy_->AddInstance(instance->pp_instance()); + return instance; +} + +PluginInstance* PluginModule::GetSomeInstance() const { + // This will generally crash later if there is not actually any instance to + // return, so we force a crash now to make bugs easier to track down. + CHECK(!instances_.empty()); + return *instances_.begin(); +} + +const void* PluginModule::GetPluginInterface(const char* name) const { + if (out_of_process_proxy_.get()) + return out_of_process_proxy_->GetProxiedInterface(name); + + // In-process plugins. + if (!entry_points_.get_interface) + return NULL; + return entry_points_.get_interface(name); +} + +void PluginModule::InstanceCreated(PluginInstance* instance) { + instances_.insert(instance); +} + +void PluginModule::InstanceDeleted(PluginInstance* instance) { + if (out_of_process_proxy_.get()) + out_of_process_proxy_->RemoveInstance(instance->pp_instance()); + instances_.erase(instance); +} + +void PluginModule::AddNPObjectVar(ObjectVar* object_var) { + DCHECK(np_object_to_object_var_.find(object_var->np_object()) == + np_object_to_object_var_.end()) << "ObjectVar already in map"; + np_object_to_object_var_[object_var->np_object()] = object_var; +} + +void PluginModule::RemoveNPObjectVar(ObjectVar* object_var) { + NPObjectToObjectVarMap::iterator found = + np_object_to_object_var_.find(object_var->np_object()); + if (found == np_object_to_object_var_.end()) { + NOTREACHED() << "ObjectVar not registered."; + return; + } + if (found->second != object_var) { + NOTREACHED() << "ObjectVar doesn't match."; + return; + } + np_object_to_object_var_.erase(found); +} + +ObjectVar* PluginModule::ObjectVarForNPObject(NPObject* np_object) const { + NPObjectToObjectVarMap::const_iterator found = + np_object_to_object_var_.find(np_object); + if (found == np_object_to_object_var_.end()) + return NULL; + return found->second; +} + +void PluginModule::AddPluginObject(PluginObject* plugin_object) { + DCHECK(live_plugin_objects_.find(plugin_object) == + live_plugin_objects_.end()); + live_plugin_objects_.insert(plugin_object); +} + +void PluginModule::RemovePluginObject(PluginObject* plugin_object) { + // Don't actually verify that the object is in the set since during module + // deletion we'll be in the process of freeing them. + live_plugin_objects_.erase(plugin_object); +} + +bool PluginModule::InitializeModule() { + DCHECK(!out_of_process_proxy_.get()) << "Don't call for proxied modules."; + int retval = entry_points_.initialize_module(pp_module(), &GetInterface); + if (retval != 0) { + LOG(WARNING) << "PPP_InitializeModule returned failure " << retval; + return false; + } + return true; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/plugin_module.h b/webkit/plugins/ppapi/plugin_module.h new file mode 100644 index 0000000..39b5f1d --- /dev/null +++ b/webkit/plugins/ppapi/plugin_module.h @@ -0,0 +1,182 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PLUGIN_MODULE_H_ +#define WEBKIT_PLUGINS_PPAPI_PLUGIN_MODULE_H_ + +#include <map> +#include <set> + +#include "base/basictypes.h" +#include "base/native_library.h" +#include "base/process.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/weak_ptr.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/ppb.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" + +class FilePath; +class MessageLoop; +typedef struct NPObject NPObject; +struct PPB_Core; +typedef void* NPIdentifier; + +namespace base { +class WaitableEvent; +} + +namespace pp { +namespace proxy { +class HostDispatcher; +} // proxy +} // pp + +namespace IPC { +struct ChannelHandle; +} + +namespace webkit { +namespace ppapi { + +class ObjectVar; +class PluginDelegate; +class PluginInstance; +class PluginObject; + +// Represents one plugin library loaded into one renderer. This library may +// have multiple instances. +// +// Note: to get from a PP_Instance to a PluginInstance*, use the +// ResourceTracker. +class PluginModule : public base::RefCounted<PluginModule>, + public base::SupportsWeakPtr<PluginModule> { + public: + typedef const void* (*GetInterfaceFunc)(const char*); + typedef int (*PPP_InitializeModuleFunc)(PP_Module, PPB_GetInterface); + typedef void (*PPP_ShutdownModuleFunc)(); + + struct EntryPoints { + // This structure is POD, with the constructor initializing to NULL. + EntryPoints(); + + GetInterfaceFunc get_interface; + PPP_InitializeModuleFunc initialize_module; + PPP_ShutdownModuleFunc shutdown_module; // Optional, may be NULL. + }; + + // You must call one of the Init functions to create a module of the type + // you desire. + PluginModule(); + + ~PluginModule(); + + // Initializes this module as an internal plugin with the given entrypoints. + // This is used for "plugins" compiled into Chrome. Returns true on success. + // False means that the plugin can not be used. + bool InitAsInternalPlugin(const EntryPoints& entry_points); + + // Initializes this module using the given library path as the plugin. + // Returns true on success. False means that the plugin can not be used. + bool InitAsLibrary(const FilePath& path); + + // Initializes this module for the given out of process proxy. This takes + // ownership of the given pointer, even in the failure case. + void InitAsProxied(PluginDelegate::OutOfProcessProxy* out_of_process_proxy); + + static const PPB_Core* GetCore(); + + // Returns a pointer to the local GetInterface function for retrieving + // PPB interfaces. + static GetInterfaceFunc GetLocalGetInterfaceFunc(); + + // Returns the module handle. This may be used before Init() is called (the + // proxy needs this information to set itself up properly). + PP_Module pp_module() const { return pp_module_; } + + void set_name(const std::string& name) { name_ = name; } + const std::string& name() const { return name_; } + + PluginInstance* CreateInstance(PluginDelegate* delegate); + + // Returns "some" plugin instance associated with this module. This is not + // guaranteed to be any one in particular. This is normally used to execute + // callbacks up to the browser layer that are not inherently per-instance, + // but the delegate lives only on the plugin instance so we need one of them. + PluginInstance* GetSomeInstance() const; + + // Calls the plugin's GetInterface and returns the given interface pointer, + // which could be NULL. + const void* GetPluginInterface(const char* name) const; + + // This module is associated with a set of instances. The PluginInstance + // object declares its association with this module in its destructor and + // releases us in its destructor. + void InstanceCreated(PluginInstance* instance); + void InstanceDeleted(PluginInstance* instance); + + // Tracks all live ObjectVar. This is so we can map between PluginModule + + // NPObject and get the ObjectVar corresponding to it. This Add/Remove + // function should be called by the ObjectVar when it is created and + // destroyed. + void AddNPObjectVar(ObjectVar* object_var); + void RemoveNPObjectVar(ObjectVar* object_var); + + // Looks up a previously registered ObjectVar for the given NPObject and + // module. Returns NULL if there is no ObjectVar corresponding to the given + // NPObject for the given module. See AddNPObjectVar above. + ObjectVar* ObjectVarForNPObject(NPObject* np_object) const; + + // Tracks all live PluginObjects. + void AddPluginObject(PluginObject* plugin_object); + void RemovePluginObject(PluginObject* plugin_object); + + private: + // Calls the InitializeModule entrypoint. The entrypoint must have been + // set and the plugin must not be out of process (we don't maintain + // entrypoints in that case). + bool InitializeModule(); + + PP_Module pp_module_; + + // Manages the out of process proxy interface. The presence of this + // pointer indicates that the plugin is running out of process and that the + // entry_points_ aren't valid. + scoped_ptr<PluginDelegate::OutOfProcessProxy> out_of_process_proxy_; + + // Holds a reference to the base::NativeLibrary handle if this PluginModule + // instance wraps functions loaded from a library. Can be NULL. If + // |library_| is non-NULL, PluginModule will attempt to unload the library + // during destruction. + base::NativeLibrary library_; + + // Contains pointers to the entry points of the actual plugin implementation. + // These will be NULL for out-of-process plugins, which is indicated by the + // presence of the out_of_process_proxy_ value. + EntryPoints entry_points_; + + // The name of the module. + std::string name_; + + // Non-owning pointers to all instances associated with this module. When + // there are no more instances, this object should be deleted. + typedef std::set<PluginInstance*> PluginInstanceSet; + PluginInstanceSet instances_; + + // Tracks all live ObjectVars used by this module so we can map NPObjects to + // the corresponding object. These are non-owning references. + typedef std::map<NPObject*, ObjectVar*> NPObjectToObjectVarMap;; + NPObjectToObjectVarMap np_object_to_object_var_; + + typedef std::set<PluginObject*> PluginObjectSet; + PluginObjectSet live_plugin_objects_; + + DISALLOW_COPY_AND_ASSIGN(PluginModule); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PLUGIN_MODULE_H_ diff --git a/webkit/plugins/ppapi/plugin_object.cc b/webkit/plugins/ppapi/plugin_object.cc new file mode 100644 index 0000000..516f255 --- /dev/null +++ b/webkit/plugins/ppapi/plugin_object.cc @@ -0,0 +1,333 @@ +// 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 "webkit/plugins/ppapi/plugin_object.h" + +#include "base/logging.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "third_party/npapi/bindings/npapi.h" +#include "third_party/npapi/bindings/npruntime.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_class.h" +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" +#include "webkit/plugins/ppapi/npapi_glue.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/resource.h" +#include "webkit/plugins/ppapi/string.h" +#include "webkit/plugins/ppapi/var.h" +#include "webkit/plugins/ppapi/var_object_class.h" + +using WebKit::WebBindings; + +namespace webkit { +namespace ppapi { + +namespace { + +const char kInvalidValueException[] = "Error: Invalid value"; + +// NPObject implementation in terms of PPP_Class_Deprecated -------------------- + +NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) { + return PluginObject::AllocateObjectWrapper(); +} + +void WrapperClass_Deallocate(NPObject* np_object) { + PluginObject* plugin_object = PluginObject::FromNPObject(np_object); + if (!plugin_object) + return; + plugin_object->ppp_class()->Deallocate(plugin_object->ppp_class_data()); + delete plugin_object; +} + +void WrapperClass_Invalidate(NPObject* object) { +} + +bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) { + NPObjectAccessorWithIdentifier accessor(object, method_name, false); + if (!accessor.is_valid()) + return false; + + PPResultAndExceptionToNPResult result_converter( + accessor.object()->GetNPObject(), NULL); + bool rv = accessor.object()->ppp_class()->HasMethod( + accessor.object()->ppp_class_data(), accessor.identifier(), + result_converter.exception()); + result_converter.CheckExceptionForNoResult(); + return rv; +} + +bool WrapperClass_Invoke(NPObject* object, NPIdentifier method_name, + const NPVariant* argv, uint32_t argc, + NPVariant* result) { + NPObjectAccessorWithIdentifier accessor(object, method_name, false); + if (!accessor.is_valid()) + return false; + + PPResultAndExceptionToNPResult result_converter( + accessor.object()->GetNPObject(), result); + PPVarArrayFromNPVariantArray args(accessor.object()->module(), argc, argv); + + return result_converter.SetResult(accessor.object()->ppp_class()->Call( + accessor.object()->ppp_class_data(), accessor.identifier(), + argc, args.array(), result_converter.exception())); +} + +bool WrapperClass_InvokeDefault(NPObject* np_object, const NPVariant* argv, + uint32_t argc, NPVariant* result) { + PluginObject* obj = PluginObject::FromNPObject(np_object); + if (!obj) + return false; + + PPVarArrayFromNPVariantArray args(obj->module(), argc, argv); + PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result); + + result_converter.SetResult(obj->ppp_class()->Call( + obj->ppp_class_data(), PP_MakeUndefined(), argc, args.array(), + result_converter.exception())); + return result_converter.success(); +} + +bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) { + NPObjectAccessorWithIdentifier accessor(object, property_name, true); + if (!accessor.is_valid()) + return false; + + PPResultAndExceptionToNPResult result_converter( + accessor.object()->GetNPObject(), NULL); + bool rv = accessor.object()->ppp_class()->HasProperty( + accessor.object()->ppp_class_data(), accessor.identifier(), + result_converter.exception()); + result_converter.CheckExceptionForNoResult(); + return rv; +} + +bool WrapperClass_GetProperty(NPObject* object, NPIdentifier property_name, + NPVariant* result) { + NPObjectAccessorWithIdentifier accessor(object, property_name, true); + if (!accessor.is_valid()) + return false; + + PPResultAndExceptionToNPResult result_converter( + accessor.object()->GetNPObject(), result); + return result_converter.SetResult(accessor.object()->ppp_class()->GetProperty( + accessor.object()->ppp_class_data(), accessor.identifier(), + result_converter.exception())); +} + +bool WrapperClass_SetProperty(NPObject* object, NPIdentifier property_name, + const NPVariant* value) { + NPObjectAccessorWithIdentifier accessor(object, property_name, true); + if (!accessor.is_valid()) + return false; + + PPResultAndExceptionToNPResult result_converter( + accessor.object()->GetNPObject(), NULL); + PP_Var value_var = Var::NPVariantToPPVar(accessor.object()->module(), value); + accessor.object()->ppp_class()->SetProperty( + accessor.object()->ppp_class_data(), accessor.identifier(), value_var, + result_converter.exception()); + Var::PluginReleasePPVar(value_var); + return result_converter.CheckExceptionForNoResult(); +} + +bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) { + NPObjectAccessorWithIdentifier accessor(object, property_name, true); + if (!accessor.is_valid()) + return false; + + PPResultAndExceptionToNPResult result_converter( + accessor.object()->GetNPObject(), NULL); + accessor.object()->ppp_class()->RemoveProperty( + accessor.object()->ppp_class_data(), accessor.identifier(), + result_converter.exception()); + return result_converter.CheckExceptionForNoResult(); +} + +bool WrapperClass_Enumerate(NPObject* object, NPIdentifier** values, + uint32_t* count) { + *values = NULL; + *count = 0; + PluginObject* obj = PluginObject::FromNPObject(object); + if (!obj) + return false; + + uint32_t property_count = 0; + PP_Var* properties = NULL; // Must be freed! + PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), NULL); + obj->ppp_class()->GetAllPropertyNames(obj->ppp_class_data(), + &property_count, &properties, + result_converter.exception()); + + // Convert the array of PP_Var to an array of NPIdentifiers. If any + // conversions fail, we will set the exception. + if (!result_converter.has_exception()) { + if (property_count > 0) { + *values = static_cast<NPIdentifier*>( + malloc(sizeof(NPIdentifier) * property_count)); + *count = 0; // Will be the number of items successfully converted. + for (uint32_t i = 0; i < property_count; ++i) { + if (!((*values)[i] = Var::PPVarToNPIdentifier(properties[i]))) { + // Throw an exception for the failed convertion. + *result_converter.exception() = StringVar::StringToPPVar( + obj->module(), kInvalidValueException); + break; + } + (*count)++; + } + + if (result_converter.has_exception()) { + // We don't actually have to free the identifiers we converted since + // all identifiers leak anyway :( . + free(*values); + *values = NULL; + *count = 0; + } + } + } + + // This will actually throw the exception, either from GetAllPropertyNames, + // or if anything was set during the conversion process. + result_converter.CheckExceptionForNoResult(); + + // Release the PP_Var that the plugin allocated. On success, they will all + // be converted to NPVariants, and on failure, we want them to just go away. + for (uint32_t i = 0; i < property_count; ++i) + Var::PluginReleasePPVar(properties[i]); + free(properties); + return result_converter.success(); +} + +bool WrapperClass_Construct(NPObject* object, const NPVariant* argv, + uint32_t argc, NPVariant* result) { + PluginObject* obj = PluginObject::FromNPObject(object); + if (!obj) + return false; + + PPVarArrayFromNPVariantArray args(obj->module(), argc, argv); + PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result); + return result_converter.SetResult(obj->ppp_class()->Construct( + obj->ppp_class_data(), argc, args.array(), + result_converter.exception())); +} + +const NPClass wrapper_class = { + NP_CLASS_STRUCT_VERSION, + WrapperClass_Allocate, + WrapperClass_Deallocate, + WrapperClass_Invalidate, + WrapperClass_HasMethod, + WrapperClass_Invoke, + WrapperClass_InvokeDefault, + WrapperClass_HasProperty, + WrapperClass_GetProperty, + WrapperClass_SetProperty, + WrapperClass_RemoveProperty, + WrapperClass_Enumerate, + WrapperClass_Construct +}; + +} // namespace + +// PluginObject ---------------------------------------------------------------- + +struct PluginObject::NPObjectWrapper : public NPObject { + // Points to the var object that owns this wrapper. This value may be NULL + // if there is no var owning this wrapper. This can happen if the plugin + // releases all references to the var, but a reference to the underlying + // NPObject is still held by script on the page. + PluginObject* obj; +}; + +PluginObject::PluginObject(PluginModule* module, + NPObjectWrapper* object_wrapper, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) + : module_(module), + object_wrapper_(object_wrapper), + ppp_class_(ppp_class), + ppp_class_data_(ppp_class_data) { + // Make the object wrapper refer back to this class so our NPObject + // implementation can call back into the Pepper layer. + object_wrapper_->obj = this; + module_->AddPluginObject(this); +} + +PluginObject::~PluginObject() { + // The wrapper we made for this NPObject may still have a reference to it + // from JavaScript, so we clear out its ObjectVar back pointer which will + // cause all calls "up" to the plugin to become NOPs. Our ObjectVar base + // class will release our reference to the object, which may or may not + // delete the NPObject. + DCHECK(object_wrapper_->obj == this); + object_wrapper_->obj = NULL; + module_->RemovePluginObject(this); +} + +PP_Var PluginObject::Create(PluginModule* module, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + // This will internally end up calling our AllocateObjectWrapper via the + // WrapperClass_Allocated function which will have created an object wrapper + // appropriate for this class (derived from NPObject). + NPObjectWrapper* wrapper = static_cast<NPObjectWrapper*>( + WebBindings::createObject(NULL, const_cast<NPClass*>(&wrapper_class))); + + // This object will register itself both with the NPObject and with the + // PluginModule. The NPObject will normally handle its lifetime, and it + // will get deleted in the destroy method. It may also get deleted when the + // plugin module is deallocated. + new PluginObject(module, wrapper, ppp_class, ppp_class_data); + + // We can just use a normal ObjectVar to refer to this object from the + // plugin. It will hold a ref to the underlying NPObject which will in turn + // hold our pluginObject. + return ObjectVar::NPObjectToPPVar(module, wrapper); +} + +NPObject* PluginObject::GetNPObject() const { + return object_wrapper_; +} + +// static +bool PluginObject::IsInstanceOf(NPObject* np_object, + const PPP_Class_Deprecated* ppp_class, + void** ppp_class_data) { + // Validate that this object is implemented by our wrapper class before + // trying to get the PluginObject. + if (np_object->_class != &wrapper_class) + return false; + + PluginObject* plugin_object = FromNPObject(np_object); + if (!plugin_object) + return false; // Object is no longer alive. + + if (plugin_object->ppp_class() != ppp_class) + return false; + if (ppp_class_data) + *ppp_class_data = plugin_object->ppp_class_data(); + return true; +} + +// static +PluginObject* PluginObject::FromNPObject(NPObject* object) { + return static_cast<NPObjectWrapper*>(object)->obj; +} + +// static +NPObject* PluginObject::AllocateObjectWrapper() { + NPObjectWrapper* wrapper = new NPObjectWrapper; + memset(wrapper, 0, sizeof(NPObjectWrapper)); + return wrapper; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/plugin_object.h b/webkit/plugins/ppapi/plugin_object.h new file mode 100644 index 0000000..01637e5 --- /dev/null +++ b/webkit/plugins/ppapi/plugin_object.h @@ -0,0 +1,91 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PLUGIN_OBJECT_H_ +#define WEBKIT_PLUGINS_PPAPI_PLUGIN_OBJECT_H_ + +#include <string> + +#include "base/basictypes.h" + +struct PP_Var; +struct PPP_Class_Deprecated; +typedef struct NPObject NPObject; +typedef struct _NPVariant NPVariant; + +namespace webkit { +namespace ppapi { + +class PluginModule; + +class PluginObject { + public: + virtual ~PluginObject(); + + // Allocates a new PluginObject and returns it as a PP_Var with a + // refcount of 1. + static PP_Var Create(PluginModule* module, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data); + + PluginModule* module() const { return module_; } + + const PPP_Class_Deprecated* ppp_class() { return ppp_class_; } + void* ppp_class_data() { return ppp_class_data_; }; + + NPObject* GetNPObject() const; + + // Returns true if the given var is an object implemented by the same plugin + // that owns the var object, and that the class matches. If it matches, + // returns true and places the class data into |*ppp_class_data| (which can + // optionally be NULL if no class data is desired). + static bool IsInstanceOf(NPObject* np_object, + const PPP_Class_Deprecated* ppp_class, + void** ppp_class_data); + + // Converts the given NPObject to the corresponding ObjectVar. + // + // The given NPObject must be one corresponding to a PluginObject or this + // will crash. If the object is a PluginObject but the plugin has gone + // away (the object could still be alive because of a reference from JS), + // then the return value will be NULL. + static PluginObject* FromNPObject(NPObject* object); + + // Allocates a plugin wrapper object and returns it as an NPObject. This is + // used internally only. + static NPObject* AllocateObjectWrapper(); + + private: + struct NPObjectWrapper; + + // This object must be created using the CreateObject function of the which + // will set up the correct NPObject. + // + // The NPObjectWrapper (an NPObject) should already have the reference + // incremented on it, and this class will take ownership of that reference. + PluginObject(PluginModule* module, + NPObjectWrapper* object_wrapper, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data); + + PluginModule* module_; + + // Holds a pointer to the NPObject wrapper backing the var. This class + // derives from NPObject and we hold a reference to it, so it must be + // refcounted. When the type is not an object, this value will be NULL. + // + // We don't actually own this pointer, it's the NPObject that actually + // owns us. + NPObjectWrapper* object_wrapper_; + + const PPP_Class_Deprecated* ppp_class_; + void* ppp_class_data_; + + DISALLOW_COPY_AND_ASSIGN(PluginObject); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PLUGIN_OBJECT_H_ diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc new file mode 100644 index 0000000..3b7aff9 --- /dev/null +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc @@ -0,0 +1,1186 @@ +// 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 "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +#include "base/logging.h" +#include "base/metrics/histogram.h" +#include "base/scoped_ptr.h" +#include "base/utf_string_conversions.h" +#include "gfx/rect.h" +#include "gfx/skia_util.h" +#include "ppapi/c/dev/ppb_find_dev.h" +#include "ppapi/c/dev/ppb_fullscreen_dev.h" +#include "ppapi/c/dev/ppb_zoom_dev.h" +#include "ppapi/c/dev/ppp_find_dev.h" +#include "ppapi/c/dev/ppp_selection_dev.h" +#include "ppapi/c/dev/ppp_zoom_dev.h" +#include "ppapi/c/pp_input_event.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/ppb_instance.h" +#include "ppapi/c/ppp_instance.h" +#include "printing/native_metafile.h" +#include "printing/units.h" +#include "skia/ext/vector_platform_device.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebElement.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/event_conversion.h" +#include "webkit/plugins/ppapi/fullscreen_container.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppb_buffer_impl.h" +#include "webkit/plugins/ppapi/ppb_graphics_2d_impl.h" +#include "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" +#include "webkit/plugins/ppapi/ppb_url_loader_impl.h" +#include "webkit/plugins/ppapi/ppp_pdf.h" +#include "webkit/plugins/ppapi/string.h" +#include "webkit/plugins/ppapi/var.h" + +#if defined(OS_MACOSX) +#include "base/mac_util.h" +#include "base/mac/scoped_cftyperef.h" +#endif + +#if defined(OS_WIN) +#include "gfx/codec/jpeg_codec.h" +#include "gfx/gdi_util.h" +#endif + +using WebKit::WebBindings; +using WebKit::WebCanvas; +using WebKit::WebCursorInfo; +using WebKit::WebDocument; +using WebKit::WebFrame; +using WebKit::WebInputEvent; +using WebKit::WebPluginContainer; +using WebKit::WebString; +using WebKit::WebURLRequest; +using WebKit::WebView; + +namespace webkit { +namespace ppapi { + +#if defined(OS_WIN) +// Exported by pdf.dll +typedef bool (*RenderPDFPageToDCProc)( + const unsigned char* pdf_buffer, int buffer_size, int page_number, HDC dc, + int dpi_x, int dpi_y, int bounds_origin_x, int bounds_origin_y, + int bounds_width, int bounds_height, bool fit_to_bounds, + bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds); +#endif // defined(OS_WIN) + +namespace { + +#define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, np_name) \ + COMPILE_ASSERT(int(WebCursorInfo::webkit_name) == int(np_name), \ + mismatching_enums) + +COMPILE_ASSERT_MATCHING_ENUM(TypePointer, PP_CURSORTYPE_POINTER); +COMPILE_ASSERT_MATCHING_ENUM(TypeCross, PP_CURSORTYPE_CROSS); +COMPILE_ASSERT_MATCHING_ENUM(TypeHand, PP_CURSORTYPE_HAND); +COMPILE_ASSERT_MATCHING_ENUM(TypeIBeam, PP_CURSORTYPE_IBEAM); +COMPILE_ASSERT_MATCHING_ENUM(TypeWait, PP_CURSORTYPE_WAIT); +COMPILE_ASSERT_MATCHING_ENUM(TypeHelp, PP_CURSORTYPE_HELP); +COMPILE_ASSERT_MATCHING_ENUM(TypeEastResize, PP_CURSORTYPE_EASTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthResize, PP_CURSORTYPE_NORTHRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastResize, + PP_CURSORTYPE_NORTHEASTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestResize, + PP_CURSORTYPE_NORTHWESTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeSouthResize, PP_CURSORTYPE_SOUTHRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastResize, + PP_CURSORTYPE_SOUTHEASTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestResize, + PP_CURSORTYPE_SOUTHWESTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeWestResize, PP_CURSORTYPE_WESTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthSouthResize, + PP_CURSORTYPE_NORTHSOUTHRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeEastWestResize, PP_CURSORTYPE_EASTWESTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastSouthWestResize, + PP_CURSORTYPE_NORTHEASTSOUTHWESTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestSouthEastResize, + PP_CURSORTYPE_NORTHWESTSOUTHEASTRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeColumnResize, PP_CURSORTYPE_COLUMNRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeRowResize, PP_CURSORTYPE_ROWRESIZE); +COMPILE_ASSERT_MATCHING_ENUM(TypeMiddlePanning, PP_CURSORTYPE_MIDDLEPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeEastPanning, PP_CURSORTYPE_EASTPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthPanning, PP_CURSORTYPE_NORTHPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastPanning, + PP_CURSORTYPE_NORTHEASTPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestPanning, + PP_CURSORTYPE_NORTHWESTPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeSouthPanning, PP_CURSORTYPE_SOUTHPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastPanning, + PP_CURSORTYPE_SOUTHEASTPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestPanning, + PP_CURSORTYPE_SOUTHWESTPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeWestPanning, PP_CURSORTYPE_WESTPANNING); +COMPILE_ASSERT_MATCHING_ENUM(TypeMove, PP_CURSORTYPE_MOVE); +COMPILE_ASSERT_MATCHING_ENUM(TypeVerticalText, PP_CURSORTYPE_VERTICALTEXT); +COMPILE_ASSERT_MATCHING_ENUM(TypeCell, PP_CURSORTYPE_CELL); +COMPILE_ASSERT_MATCHING_ENUM(TypeContextMenu, PP_CURSORTYPE_CONTEXTMENU); +COMPILE_ASSERT_MATCHING_ENUM(TypeAlias, PP_CURSORTYPE_ALIAS); +COMPILE_ASSERT_MATCHING_ENUM(TypeProgress, PP_CURSORTYPE_PROGRESS); +COMPILE_ASSERT_MATCHING_ENUM(TypeNoDrop, PP_CURSORTYPE_NODROP); +COMPILE_ASSERT_MATCHING_ENUM(TypeCopy, PP_CURSORTYPE_COPY); +COMPILE_ASSERT_MATCHING_ENUM(TypeNone, PP_CURSORTYPE_NONE); +COMPILE_ASSERT_MATCHING_ENUM(TypeNotAllowed, PP_CURSORTYPE_NOTALLOWED); +COMPILE_ASSERT_MATCHING_ENUM(TypeZoomIn, PP_CURSORTYPE_ZOOMIN); +COMPILE_ASSERT_MATCHING_ENUM(TypeZoomOut, PP_CURSORTYPE_ZOOMOUT); +COMPILE_ASSERT_MATCHING_ENUM(TypeCustom, PP_CURSORTYPE_CUSTOM); + +void RectToPPRect(const gfx::Rect& input, PP_Rect* output) { + *output = PP_MakeRectFromXYWH(input.x(), input.y(), + input.width(), input.height()); +} + +PP_Var GetWindowObject(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_MakeUndefined(); + return instance->GetWindowObject(); +} + +PP_Var GetOwnerElementObject(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_MakeUndefined(); + return instance->GetOwnerElementObject(); +} + +PP_Bool BindGraphics(PP_Instance instance_id, PP_Resource graphics_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + return BoolToPPBool(instance->BindGraphics(graphics_id)); +} + +PP_Bool IsFullFrame(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + return BoolToPPBool(instance->full_frame()); +} + +PP_Var ExecuteScript(PP_Instance instance_id, + PP_Var script, + PP_Var* exception) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_MakeUndefined(); + return instance->ExecuteScript(script, exception); +} + +const PPB_Instance ppb_instance = { + &GetWindowObject, + &GetOwnerElementObject, + &BindGraphics, + &IsFullFrame, + &ExecuteScript, +}; + +void NumberOfFindResultsChanged(PP_Instance instance_id, + int32_t total, + PP_Bool final_result) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return; + + DCHECK_NE(instance->find_identifier(), -1); + instance->delegate()->NumberOfFindResultsChanged( + instance->find_identifier(), total, PPBoolToBool(final_result)); +} + +void SelectedFindResultChanged(PP_Instance instance_id, + int32_t index) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return; + + DCHECK_NE(instance->find_identifier(), -1); + instance->delegate()->SelectedFindResultChanged( + instance->find_identifier(), index); +} + +const PPB_Find_Dev ppb_find = { + &NumberOfFindResultsChanged, + &SelectedFindResultChanged, +}; + +PP_Bool IsFullscreen(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + return BoolToPPBool(instance->IsFullscreen()); +} + +PP_Bool SetFullscreen(PP_Instance instance_id, PP_Bool fullscreen) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + return BoolToPPBool(instance->SetFullscreen(PPBoolToBool(fullscreen))); +} + +const PPB_Fullscreen_Dev ppb_fullscreen = { + &IsFullscreen, + &SetFullscreen, +}; + +void ZoomChanged(PP_Instance instance_id, double factor) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return; + + // We only want to tell the page to change its zoom if the whole page is the + // PDF. If we're in an iframe, then don't do anything. + WebFrame* frame = instance->container()->element().document().frame(); + if (!frame->view()->mainFrame()->document().isPluginDocument()) + return; + + double zoom_level = WebView::zoomFactorToZoomLevel(factor); + // The conversino from zoom level to factor, and back, can introduce rounding + // errors. i.e. WebKit originally tells us 3.0, but by the time we tell the + // plugin and it tells us back, the level becomes 3.000000000004. Need to + // round or else otherwise if the user zooms out, it will go to 3.0 instead of + // 2.0. + int rounded = + static_cast<int>(zoom_level + (zoom_level > 0 ? 0.001 : -0.001)); + if (abs(rounded - zoom_level) < 0.001) + zoom_level = rounded; + instance->container()->zoomLevelChanged(zoom_level); +} + +void ZoomLimitsChanged(PP_Instance instance_id, + double minimum_factor, + double maximium_factor) { + if (minimum_factor > maximium_factor) { + NOTREACHED(); + return; + } + + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return; + instance->delegate()->ZoomLimitsChanged(minimum_factor, maximium_factor); +} + +const PPB_Zoom_Dev ppb_zoom = { + &ZoomChanged, + &ZoomLimitsChanged +}; + +} // namespace + +PluginInstance::PluginInstance(PluginDelegate* delegate, + PluginModule* module, + const PPP_Instance* instance_interface) + : delegate_(delegate), + module_(module), + instance_interface_(instance_interface), + pp_instance_(0), + container_(NULL), + full_frame_(false), + has_webkit_focus_(false), + has_content_area_focus_(false), + find_identifier_(-1), + plugin_find_interface_(NULL), + plugin_pdf_interface_(NULL), + plugin_selection_interface_(NULL), + plugin_zoom_interface_(NULL), +#if defined (OS_LINUX) + num_pages_(0), + pdf_output_done_(false), +#endif // defined (OS_LINUX) + plugin_print_interface_(NULL), + plugin_graphics_3d_interface_(NULL), + always_on_top_(false), + fullscreen_container_(NULL) { + pp_instance_ = ResourceTracker::Get()->AddInstance(this); + + memset(¤t_print_settings_, 0, sizeof(current_print_settings_)); + DCHECK(delegate); + module_->InstanceCreated(this); + delegate_->InstanceCreated(this); +} + +PluginInstance::~PluginInstance() { + FOR_EACH_OBSERVER(Observer, observers_, InstanceDestroyed(this)); + + delegate_->InstanceDeleted(this); + module_->InstanceDeleted(this); + + ResourceTracker::Get()->InstanceDeleted(pp_instance_); +} + +// static +const PPB_Instance* PluginInstance::GetInterface() { + return &ppb_instance; +} + +// static +const PPB_Find_Dev* PluginInstance::GetFindInterface() { + return &ppb_find; +} + +// static +const PPB_Fullscreen_Dev* PluginInstance::GetFullscreenInterface() { + return &ppb_fullscreen; +} + +// static +const PPB_Zoom_Dev* PluginInstance::GetZoomInterface() { + return &ppb_zoom; +} + +void PluginInstance::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void PluginInstance::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +void PluginInstance::Paint(WebCanvas* canvas, + const gfx::Rect& plugin_rect, + const gfx::Rect& paint_rect) { + if (bound_graphics_2d()) + bound_graphics_2d()->Paint(canvas, plugin_rect, paint_rect); +} + +void PluginInstance::InvalidateRect(const gfx::Rect& rect) { + if (fullscreen_container_) { + if (rect.IsEmpty()) + fullscreen_container_->Invalidate(); + else + fullscreen_container_->InvalidateRect(rect); + } else { + if (!container_ || position_.IsEmpty()) + return; // Nothing to do. + if (rect.IsEmpty()) + container_->invalidate(); + else + container_->invalidateRect(rect); + } +} + +void PluginInstance::ScrollRect(int dx, int dy, const gfx::Rect& rect) { + if (fullscreen_container_) { + fullscreen_container_->ScrollRect(dx, dy, rect); + } else { + if (full_frame_) { + container_->scrollRect(dx, dy, rect); + } else { + // Can't do optimized scrolling since there could be other elements on top + // of us. + InvalidateRect(rect); + } + } +} + +unsigned PluginInstance::GetBackingTextureId() { + if (!bound_graphics_3d()) + return 0; + + return bound_graphics_3d()->GetBackingTextureId(); +} + +void PluginInstance::CommitBackingTexture() { + container_->commitBackingTexture(); +} + +PP_Var PluginInstance::GetWindowObject() { + if (!container_) + return PP_MakeUndefined(); + + WebFrame* frame = container_->element().document().frame(); + if (!frame) + return PP_MakeUndefined(); + + return ObjectVar::NPObjectToPPVar(module(), frame->windowObject()); +} + +PP_Var PluginInstance::GetOwnerElementObject() { + if (!container_) + return PP_MakeUndefined(); + return ObjectVar::NPObjectToPPVar(module(), + container_->scriptableObjectForElement()); +} + +bool PluginInstance::BindGraphics(PP_Resource graphics_id) { + if (!graphics_id) { + // Special-case clearing the current device. + if (bound_graphics_.get()) { + if (bound_graphics_2d()) { + bound_graphics_2d()->BindToInstance(NULL); + } else if (bound_graphics_.get()) { + bound_graphics_3d()->SetSwapBuffersCallback(NULL); + bound_graphics_3d()->BindToInstance(NULL); + } + InvalidateRect(gfx::Rect()); + } + bound_graphics_ = NULL; + return true; + } + + scoped_refptr<PPB_Graphics2D_Impl> graphics_2d = + Resource::GetAs<PPB_Graphics2D_Impl>(graphics_id); + scoped_refptr<PPB_Graphics3D_Impl> graphics_3d = + Resource::GetAs<PPB_Graphics3D_Impl>(graphics_id); + + if (graphics_2d) { + if (!graphics_2d->BindToInstance(this)) + return false; // Can't bind to more than one instance. + + // See http://crbug.com/49403: this can be further optimized by keeping the + // old device around and painting from it. + if (bound_graphics_2d()) { + // Start the new image with the content of the old image until the plugin + // repaints. + const SkBitmap* old_backing_bitmap = + bound_graphics_2d()->image_data()->GetMappedBitmap(); + SkRect old_size = SkRect::MakeWH( + SkScalar(static_cast<float>(old_backing_bitmap->width())), + SkScalar(static_cast<float>(old_backing_bitmap->height()))); + + SkCanvas canvas(*graphics_2d->image_data()->GetMappedBitmap()); + canvas.drawBitmap(*old_backing_bitmap, 0, 0); + + // Fill in any extra space with white. + canvas.clipRect(old_size, SkRegion::kDifference_Op); + canvas.drawARGB(255, 255, 255, 255); + } + + bound_graphics_ = graphics_2d; + // BindToInstance will have invalidated the plugin if necessary. + } else if (graphics_3d) { + if (!graphics_3d->BindToInstance(this)) + return false; + + bound_graphics_ = graphics_3d; + bound_graphics_3d()->SetSwapBuffersCallback( + NewCallback(this, &PluginInstance::CommitBackingTexture)); + } + + return true; +} + +bool PluginInstance::SetCursor(PP_CursorType_Dev type) { + cursor_.reset(new WebCursorInfo(static_cast<WebCursorInfo::Type>(type))); + return true; +} + +PP_Var PluginInstance::ExecuteScript(PP_Var script, PP_Var* exception) { + TryCatch try_catch(module(), exception); + if (try_catch.has_exception()) + return PP_MakeUndefined(); + + // Convert the script into an inconvenient NPString object. + scoped_refptr<StringVar> script_string(StringVar::FromPPVar(script)); + if (!script_string) { + try_catch.SetException("Script param to ExecuteScript must be a string."); + return PP_MakeUndefined(); + } + NPString np_script; + np_script.UTF8Characters = script_string->value().c_str(); + np_script.UTF8Length = script_string->value().length(); + + // Get the current frame to pass to the evaluate function. + WebFrame* frame = container_->element().document().frame(); + if (!frame) { + try_catch.SetException("No frame to execute script in."); + return PP_MakeUndefined(); + } + + NPVariant result; + bool ok = WebBindings::evaluate(NULL, frame->windowObject(), &np_script, + &result); + if (!ok) { + // TODO(brettw) bug 54011: The TryCatch isn't working properly and + // doesn't actually catch this exception. + try_catch.SetException("Exception caught"); + WebBindings::releaseVariantValue(&result); + return PP_MakeUndefined(); + } + + PP_Var ret = Var::NPVariantToPPVar(module_, &result); + WebBindings::releaseVariantValue(&result); + return ret; +} + +void PluginInstance::Delete() { + instance_interface_->DidDestroy(pp_instance()); + + if (fullscreen_container_) { + fullscreen_container_->Destroy(); + fullscreen_container_ = NULL; + } + container_ = NULL; +} + +bool PluginInstance::Initialize(WebPluginContainer* container, + const std::vector<std::string>& arg_names, + const std::vector<std::string>& arg_values, + bool full_frame) { + container_ = container; + full_frame_ = full_frame; + + size_t argc = 0; + scoped_array<const char*> argn(new const char*[arg_names.size()]); + scoped_array<const char*> argv(new const char*[arg_names.size()]); + for (size_t i = 0; i < arg_names.size(); ++i) { + argn[argc] = arg_names[i].c_str(); + argv[argc] = arg_values[i].c_str(); + argc++; + } + + return PPBoolToBool(instance_interface_->DidCreate(pp_instance(), + argc, + argn.get(), + argv.get())); +} + +bool PluginInstance::HandleDocumentLoad(PPB_URLLoader_Impl* loader) { + Resource::ScopedResourceId resource(loader); + return PPBoolToBool(instance_interface_->HandleDocumentLoad(pp_instance(), + resource.id)); +} + +bool PluginInstance::HandleInputEvent(const WebKit::WebInputEvent& event, + WebCursorInfo* cursor_info) { + std::vector<PP_InputEvent> pp_events; + CreatePPEvent(event, &pp_events); + + // Each input event may generate more than one PP_InputEvent. + bool rv = false; + for (size_t i = 0; i < pp_events.size(); i++) { + rv |= PPBoolToBool(instance_interface_->HandleInputEvent(pp_instance(), + &pp_events[i])); + } + + if (cursor_.get()) + *cursor_info = *cursor_; + return rv; +} + +PP_Var PluginInstance::GetInstanceObject() { + return instance_interface_->GetInstanceObject(pp_instance()); +} + +void PluginInstance::ViewChanged(const gfx::Rect& position, + const gfx::Rect& clip) { + if (position.size() != position_.size() && bound_graphics_3d()) { + // TODO(apatrick): This is a hack to force the back buffer to resize. + // It is obviously wrong to call SwapBuffers when a partial frame has + // potentially been rendered. Plan is to embed resize commands in the + // command buffer just before ViewChanged is called. + bound_graphics_3d()->ResizeBackingTexture(position.size()); + bound_graphics_3d()->SwapBuffers(); + } + + position_ = position; + + if (clip.IsEmpty()) { + // WebKit can give weird (x,y) positions for empty clip rects (since the + // position technically doesn't matter). But we want to make these + // consistent since this is given to the plugin, so force everything to 0 + // in the "everything is clipped" case. + clip_ = gfx::Rect(); + } else { + clip_ = clip; + } + + PP_Rect pp_position, pp_clip; + RectToPPRect(position_, &pp_position); + RectToPPRect(clip_, &pp_clip); + instance_interface_->DidChangeView(pp_instance(), &pp_position, &pp_clip); +} + +void PluginInstance::SetWebKitFocus(bool has_focus) { + if (has_webkit_focus_ == has_focus) + return; + + bool old_plugin_focus = PluginHasFocus(); + has_webkit_focus_ = has_focus; + if (PluginHasFocus() != old_plugin_focus) { + instance_interface_->DidChangeFocus(pp_instance(), + BoolToPPBool(PluginHasFocus())); + } +} + +void PluginInstance::SetContentAreaFocus(bool has_focus) { + if (has_content_area_focus_ == has_focus) + return; + + bool old_plugin_focus = PluginHasFocus(); + has_content_area_focus_ = has_focus; + if (PluginHasFocus() != old_plugin_focus) { + instance_interface_->DidChangeFocus(pp_instance(), + BoolToPPBool(PluginHasFocus())); + } +} + +void PluginInstance::ViewInitiatedPaint() { + if (bound_graphics_2d()) + bound_graphics_2d()->ViewInitiatedPaint(); +} + +void PluginInstance::ViewFlushedPaint() { + if (bound_graphics_2d()) + bound_graphics_2d()->ViewFlushedPaint(); +} + +bool PluginInstance::GetBitmapForOptimizedPluginPaint( + const gfx::Rect& paint_bounds, + TransportDIB** dib, + gfx::Rect* location, + gfx::Rect* clip) { + if (!always_on_top_) + return false; + if (!bound_graphics_2d() || !bound_graphics_2d()->is_always_opaque()) + return false; + + // We specifically want to compare against the area covered by the backing + // store when seeing if we cover the given paint bounds, since the backing + // store could be smaller than the declared plugin area. + PPB_ImageData_Impl* image_data = bound_graphics_2d()->image_data(); + gfx::Rect plugin_backing_store_rect(position_.origin(), + gfx::Size(image_data->width(), + image_data->height())); + gfx::Rect clip_page(clip_); + clip_page.Offset(position_.origin()); + gfx::Rect plugin_paint_rect = plugin_backing_store_rect.Intersect(clip_page); + if (!plugin_paint_rect.Contains(paint_bounds)) + return false; + + *dib = image_data->platform_image()->GetTransportDIB(); + *location = plugin_backing_store_rect; + *clip = clip_page; + return true; +} + +string16 PluginInstance::GetSelectedText(bool html) { + if (!LoadSelectionInterface()) + return string16(); + + PP_Var rv = plugin_selection_interface_->GetSelectedText(pp_instance(), + BoolToPPBool(html)); + scoped_refptr<StringVar> string(StringVar::FromPPVar(rv)); + Var::PluginReleasePPVar(rv); // Release the ref the plugin transfered to us. + if (!string) + return string16(); + return UTF8ToUTF16(string->value()); +} + +string16 PluginInstance::GetLinkAtPosition(const gfx::Point& point) { + if (!LoadPdfInterface()) + return string16(); + + PP_Point p; + p.x = point.x(); + p.y = point.y(); + PP_Var rv = plugin_pdf_interface_->GetLinkAtPosition(pp_instance(), p); + scoped_refptr<StringVar> string(StringVar::FromPPVar(rv)); + Var::PluginReleasePPVar(rv); // Release the ref the plugin transfered to us. + if (!string) + return string16(); + return UTF8ToUTF16(string->value()); +} + +void PluginInstance::Zoom(double factor, bool text_only) { + if (!LoadZoomInterface()) + return; + plugin_zoom_interface_->Zoom(pp_instance(), factor, BoolToPPBool(text_only)); +} + +bool PluginInstance::StartFind(const string16& search_text, + bool case_sensitive, + int identifier) { + if (!LoadFindInterface()) + return false; + find_identifier_ = identifier; + return PPBoolToBool( + plugin_find_interface_->StartFind( + pp_instance(), + UTF16ToUTF8(search_text.c_str()).c_str(), + BoolToPPBool(case_sensitive))); +} + +void PluginInstance::SelectFindResult(bool forward) { + if (LoadFindInterface()) + plugin_find_interface_->SelectFindResult(pp_instance(), + BoolToPPBool(forward)); +} + +void PluginInstance::StopFind() { + if (!LoadFindInterface()) + return; + find_identifier_ = -1; + plugin_find_interface_->StopFind(pp_instance()); +} + +bool PluginInstance::LoadFindInterface() { + if (!plugin_find_interface_) { + plugin_find_interface_ = + reinterpret_cast<const PPP_Find_Dev*>(module_->GetPluginInterface( + PPP_FIND_DEV_INTERFACE)); + } + + return !!plugin_find_interface_; +} + +bool PluginInstance::LoadPdfInterface() { + if (!plugin_pdf_interface_) { + plugin_pdf_interface_ = + reinterpret_cast<const PPP_Pdf*>(module_->GetPluginInterface( + PPP_PDF_INTERFACE)); + } + + return !!plugin_pdf_interface_; +} + +bool PluginInstance::LoadSelectionInterface() { + if (!plugin_selection_interface_) { + plugin_selection_interface_ = + reinterpret_cast<const PPP_Selection_Dev*>(module_->GetPluginInterface( + PPP_SELECTION_DEV_INTERFACE)); + } + + return !!plugin_selection_interface_; +} + +bool PluginInstance::LoadZoomInterface() { + if (!plugin_zoom_interface_) { + plugin_zoom_interface_ = + reinterpret_cast<const PPP_Zoom_Dev*>(module_->GetPluginInterface( + PPP_ZOOM_DEV_INTERFACE)); + } + + return !!plugin_zoom_interface_; +} + +bool PluginInstance::PluginHasFocus() const { + return has_webkit_focus_ && has_content_area_focus_; +} + +bool PluginInstance::GetPreferredPrintOutputFormat( + PP_PrintOutputFormat_Dev* format) { + if (!plugin_print_interface_) { + plugin_print_interface_ = + reinterpret_cast<const PPP_Printing_Dev*>(module_->GetPluginInterface( + PPP_PRINTING_DEV_INTERFACE)); + } + if (!plugin_print_interface_) + return false; + uint32_t format_count = 0; + PP_PrintOutputFormat_Dev* supported_formats = + plugin_print_interface_->QuerySupportedFormats(pp_instance(), + &format_count); + if (!supported_formats) + return false; + + bool found_supported_format = false; + for (uint32_t index = 0; index < format_count; index++) { + if (supported_formats[index] == PP_PRINTOUTPUTFORMAT_PDF) { + // If we found PDF, we are done. + found_supported_format = true; + *format = PP_PRINTOUTPUTFORMAT_PDF; + break; + } else if (supported_formats[index] == PP_PRINTOUTPUTFORMAT_RASTER) { + // We found raster. Keep looking. + found_supported_format = true; + *format = PP_PRINTOUTPUTFORMAT_RASTER; + } + } + PluginModule::GetCore()->MemFree(supported_formats); + return found_supported_format; +} + +bool PluginInstance::SupportsPrintInterface() { + PP_PrintOutputFormat_Dev format; + return GetPreferredPrintOutputFormat(&format); +} + +int PluginInstance::PrintBegin(const gfx::Rect& printable_area, + int printer_dpi) { + PP_PrintOutputFormat_Dev format; + if (!GetPreferredPrintOutputFormat(&format)) { + // PrintBegin should not have been called since SupportsPrintInterface + // would have returned false; + NOTREACHED(); + return 0; + } + + PP_PrintSettings_Dev print_settings; + RectToPPRect(printable_area, &print_settings.printable_area); + print_settings.dpi = printer_dpi; + print_settings.orientation = PP_PRINTORIENTATION_NORMAL; + print_settings.grayscale = PP_FALSE; + print_settings.format = format; + int num_pages = plugin_print_interface_->Begin(pp_instance(), + &print_settings); + if (!num_pages) + return 0; + current_print_settings_ = print_settings; +#if defined (OS_LINUX) + num_pages_ = num_pages; + pdf_output_done_ = false; +#endif // (OS_LINUX) + return num_pages; +} + +bool PluginInstance::PrintPage(int page_number, WebKit::WebCanvas* canvas) { + DCHECK(plugin_print_interface_); + PP_PrintPageNumberRange_Dev page_range; +#if defined(OS_LINUX) + if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF) { + // On Linux we will try and output all pages as PDF in the first call to + // PrintPage. This is a temporary hack. + // TODO(sanjeevr): Remove this hack and fix this by changing the print + // interfaces for WebFrame and WebPlugin. + if (page_number != 0) + return pdf_output_done_; + page_range.first_page_number = 0; + page_range.last_page_number = num_pages_ - 1; + } +#else // defined(OS_LINUX) + page_range.first_page_number = page_range.last_page_number = page_number; +#endif // defined(OS_LINUX) + + PP_Resource print_output = + plugin_print_interface_->PrintPages(pp_instance(), &page_range, 1); + + if (!print_output) + return false; + + bool ret = false; + + if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF) + ret = PrintPDFOutput(print_output, canvas); + else if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_RASTER) + ret = PrintRasterOutput(print_output, canvas); + + // Now we need to release the print output resource. + PluginModule::GetCore()->ReleaseResource(print_output); + + return ret; +} + +void PluginInstance::PrintEnd() { + DCHECK(plugin_print_interface_); + if (plugin_print_interface_) + plugin_print_interface_->End(pp_instance()); + memset(¤t_print_settings_, 0, sizeof(current_print_settings_)); +#if defined(OS_MACOSX) + last_printed_page_ = NULL; +#elif defined(OS_LINUX) + num_pages_ = 0; + pdf_output_done_ = false; +#endif // defined(OS_LINUX) +} + +bool PluginInstance::IsFullscreen() { + return fullscreen_container_ != NULL; +} + +bool PluginInstance::SetFullscreen(bool fullscreen) { + bool is_fullscreen = (fullscreen_container_ != NULL); + if (fullscreen == is_fullscreen) + return true; + VLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off"); + if (fullscreen) { + fullscreen_container_ = delegate_->CreateFullscreenContainer(this); + } else { + fullscreen_container_->Destroy(); + fullscreen_container_ = NULL; + // TODO(piman): currently the fullscreen container resizes the plugin to the + // fullscreen size so we need to reset the size here. Eventually it will + // transparently scale and this won't be necessary. + if (container_) { + container_->reportGeometry(); + container_->invalidate(); + } + } + return true; +} + +bool PluginInstance::NavigateToURL(const char* url, const char* target) { + if (!url || !target || !container_) + return false; + + WebDocument document = container_->element().document(); + GURL complete_url = document.completeURL(WebString::fromUTF8(url)); + // Don't try to deal with the security issues of javascript. + if (complete_url.SchemeIs("javascript")) + return false; + + WebURLRequest request(complete_url); + document.frame()->setReferrerForRequest(request, GURL()); + request.setHTTPMethod(WebString::fromUTF8("GET")); + request.setFirstPartyForCookies(document.firstPartyForCookies()); + + WebString target_str = WebString::fromUTF8(target); + container_->loadFrameRequest(request, target_str, false, NULL); + return true; +} + +bool PluginInstance::PrintPDFOutput(PP_Resource print_output, + WebKit::WebCanvas* canvas) { + scoped_refptr<PPB_Buffer_Impl> buffer( + Resource::GetAs<PPB_Buffer_Impl>(print_output)); + if (!buffer.get() || !buffer->is_mapped() || !buffer->size()) { + NOTREACHED(); + return false; + } +#if defined(OS_WIN) + // For Windows, we need the PDF DLL to render the output PDF to a DC. + HMODULE pdf_module = GetModuleHandle(L"pdf.dll"); + if (!pdf_module) + return false; + RenderPDFPageToDCProc render_proc = + reinterpret_cast<RenderPDFPageToDCProc>( + GetProcAddress(pdf_module, "RenderPDFPageToDC")); + if (!render_proc) + return false; +#endif // defined(OS_WIN) + + bool ret = false; +#if defined(OS_LINUX) + // On Linux we need to get the backing PdfPsMetafile and write the bits + // directly. + cairo_t* context = canvas->beginPlatformPaint(); + printing::NativeMetafile* metafile = + printing::NativeMetafile::FromCairoContext(context); + DCHECK(metafile); + if (metafile) { + ret = metafile->SetRawData(buffer->mapped_buffer(), buffer->size()); + if (ret) + pdf_output_done_ = true; + } + canvas->endPlatformPaint(); +#elif defined(OS_MACOSX) + printing::NativeMetafile metafile; + // Create a PDF metafile and render from there into the passed in context. + if (metafile.Init(buffer->mapped_buffer(), buffer->size())) { + // Flip the transform. + CGContextSaveGState(canvas); + CGContextTranslateCTM(canvas, 0, + current_print_settings_.printable_area.size.height); + CGContextScaleCTM(canvas, 1.0, -1.0); + CGRect page_rect; + page_rect.origin.x = current_print_settings_.printable_area.point.x; + page_rect.origin.y = current_print_settings_.printable_area.point.y; + page_rect.size.width = current_print_settings_.printable_area.size.width; + page_rect.size.height = current_print_settings_.printable_area.size.height; + + ret = metafile.RenderPage(1, canvas, page_rect, true, false, true, true); + CGContextRestoreGState(canvas); + } +#elif defined(OS_WIN) + // On Windows, we now need to render the PDF to the DC that backs the + // supplied canvas. + skia::VectorPlatformDevice& device = + static_cast<skia::VectorPlatformDevice&>( + canvas->getTopPlatformDevice()); + HDC dc = device.getBitmapDC(); + gfx::Size size_in_pixels; + size_in_pixels.set_width( + printing::ConvertUnit(current_print_settings_.printable_area.size.width, + static_cast<int>(printing::kPointsPerInch), + current_print_settings_.dpi)); + size_in_pixels.set_height( + printing::ConvertUnit(current_print_settings_.printable_area.size.height, + static_cast<int>(printing::kPointsPerInch), + current_print_settings_.dpi)); + // We need to render using the actual printer DPI (rendering to a smaller + // set of pixels leads to a blurry output). However, we need to counter the + // scaling up that will happen in the browser. + XFORM xform = {0}; + xform.eM11 = xform.eM22 = static_cast<float>(printing::kPointsPerInch) / + static_cast<float>(current_print_settings_.dpi); + ModifyWorldTransform(dc, &xform, MWT_LEFTMULTIPLY); + + ret = render_proc(buffer->mapped_buffer(), buffer->size(), 0, dc, + current_print_settings_.dpi, current_print_settings_.dpi, + 0, 0, size_in_pixels.width(), + size_in_pixels.height(), true, false, true, true); +#endif // defined(OS_WIN) + + return ret; +} + +bool PluginInstance::PrintRasterOutput(PP_Resource print_output, + WebKit::WebCanvas* canvas) { + scoped_refptr<PPB_ImageData_Impl> image( + Resource::GetAs<PPB_ImageData_Impl>(print_output)); + if (!image.get() || !image->is_mapped()) + return false; + + const SkBitmap* bitmap = image->GetMappedBitmap(); + if (!bitmap) + return false; + + // Draw the printed image into the supplied canvas. + SkIRect src_rect; + src_rect.set(0, 0, bitmap->width(), bitmap->height()); + SkRect dest_rect; + dest_rect.set( + SkIntToScalar(current_print_settings_.printable_area.point.x), + SkIntToScalar(current_print_settings_.printable_area.point.y), + SkIntToScalar(current_print_settings_.printable_area.point.x + + current_print_settings_.printable_area.size.width), + SkIntToScalar(current_print_settings_.printable_area.point.y + + current_print_settings_.printable_area.size.height)); + bool draw_to_canvas = true; + gfx::Rect dest_rect_gfx; + dest_rect_gfx.set_x(current_print_settings_.printable_area.point.x); + dest_rect_gfx.set_y(current_print_settings_.printable_area.point.y); + dest_rect_gfx.set_width(current_print_settings_.printable_area.size.width); + dest_rect_gfx.set_height(current_print_settings_.printable_area.size.height); + +#if defined(OS_WIN) + // Since this is a raster output, the size of the bitmap can be + // huge (especially at high printer DPIs). On Windows, this can + // result in a HUGE EMF (on Mac and Linux the output goes to PDF + // which appears to Flate compress the bitmap). So, if this bitmap + // is larger than 20 MB, we save the bitmap as a JPEG into the EMF + // DC. Note: We chose JPEG over PNG because JPEG compression seems + // way faster (about 4 times faster). + static const int kCompressionThreshold = 20 * 1024 * 1024; + if (bitmap->getSize() > kCompressionThreshold) { + DrawJPEGToPlatformDC(*bitmap, dest_rect_gfx, canvas); + draw_to_canvas = false; + } +#endif // defined(OS_WIN) +#if defined(OS_MACOSX) + draw_to_canvas = false; + DrawSkBitmapToCanvas(*bitmap, canvas, dest_rect_gfx, + current_print_settings_.printable_area.size.height); + // See comments in the header file. + last_printed_page_ = image; +#else // defined(OS_MACOSX) + if (draw_to_canvas) + canvas->drawBitmapRect(*bitmap, &src_rect, dest_rect); +#endif // defined(OS_MACOSX) + return true; +} + +#if defined(OS_WIN) +bool PluginInstance::DrawJPEGToPlatformDC( + const SkBitmap& bitmap, + const gfx::Rect& printable_area, + WebKit::WebCanvas* canvas) { + skia::VectorPlatformDevice& device = + static_cast<skia::VectorPlatformDevice&>( + canvas->getTopPlatformDevice()); + HDC dc = device.getBitmapDC(); + // TODO(sanjeevr): This is a temporary hack. If we output a JPEG + // to the EMF, the EnumEnhMetaFile call fails in the browser + // process. The failure also happens if we output nothing here. + // We need to investigate the reason for this failure and fix it. + // In the meantime this temporary hack of drawing an empty + // rectangle in the DC gets us by. + Rectangle(dc, 0, 0, 0, 0); + + // Ideally we should add JPEG compression to the VectorPlatformDevice class + // However, Skia currently has no JPEG compression code and we cannot + // depend on gfx/jpeg_codec.h in Skia. So we do the compression here. + SkAutoLockPixels lock(bitmap); + DCHECK(bitmap.getConfig() == SkBitmap::kARGB_8888_Config); + const uint32_t* pixels = + static_cast<const uint32_t*>(bitmap.getPixels()); + std::vector<unsigned char> compressed_image; + base::TimeTicks start_time = base::TimeTicks::Now(); + bool encoded = gfx::JPEGCodec::Encode( + reinterpret_cast<const unsigned char*>(pixels), + gfx::JPEGCodec::FORMAT_BGRA, bitmap.width(), bitmap.height(), + static_cast<int>(bitmap.rowBytes()), 100, &compressed_image); + UMA_HISTOGRAM_TIMES("PepperPluginPrint.RasterBitmapCompressTime", + base::TimeTicks::Now() - start_time); + if (!encoded) { + NOTREACHED(); + return false; + } + BITMAPINFOHEADER bmi = {0}; + gfx::CreateBitmapHeader(bitmap.width(), bitmap.height(), &bmi); + bmi.biCompression = BI_JPEG; + bmi.biSizeImage = compressed_image.size(); + bmi.biHeight = -bmi.biHeight; + StretchDIBits(dc, printable_area.x(), printable_area.y(), + printable_area.width(), printable_area.height(), + 0, 0, bitmap.width(), bitmap.height(), + &compressed_image.front(), + reinterpret_cast<const BITMAPINFO*>(&bmi), + DIB_RGB_COLORS, SRCCOPY); + return true; +} +#endif // OS_WIN + +#if defined(OS_MACOSX) +void PluginInstance::DrawSkBitmapToCanvas( + const SkBitmap& bitmap, WebKit::WebCanvas* canvas, + const gfx::Rect& dest_rect, + int canvas_height) { + SkAutoLockPixels lock(bitmap); + DCHECK(bitmap.getConfig() == SkBitmap::kARGB_8888_Config); + base::mac::ScopedCFTypeRef<CGDataProviderRef> data_provider( + CGDataProviderCreateWithData( + NULL, bitmap.getAddr32(0, 0), + bitmap.rowBytes() * bitmap.height(), NULL)); + base::mac::ScopedCFTypeRef<CGImageRef> image( + CGImageCreate( + bitmap.width(), bitmap.height(), + 8, 32, bitmap.rowBytes(), + mac_util::GetSystemColorSpace(), + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, + data_provider, NULL, false, kCGRenderingIntentDefault)); + + // Flip the transform + CGContextSaveGState(canvas); + CGContextTranslateCTM(canvas, 0, canvas_height); + CGContextScaleCTM(canvas, 1.0, -1.0); + + CGRect bounds; + bounds.origin.x = dest_rect.x(); + bounds.origin.y = canvas_height - dest_rect.y() - dest_rect.height(); + bounds.size.width = dest_rect.width(); + bounds.size.height = dest_rect.height(); + + CGContextDrawImage(canvas, bounds, image); + CGContextRestoreGState(canvas); +} +#endif // defined(OS_MACOSX) + +PPB_Graphics2D_Impl* PluginInstance::bound_graphics_2d() const { + if (bound_graphics_.get() == NULL) + return NULL; + + return bound_graphics_->Cast<PPB_Graphics2D_Impl>(); +} + +PPB_Graphics3D_Impl* PluginInstance::bound_graphics_3d() const { + if (bound_graphics_.get() == NULL) + return NULL; + + return bound_graphics_->Cast<PPB_Graphics3D_Impl>(); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.h b/webkit/plugins/ppapi/ppapi_plugin_instance.h new file mode 100644 index 0000000..c2a87f5 --- /dev/null +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.h @@ -0,0 +1,320 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPAPI_PLUGIN_INSTANCE_H_ +#define WEBKIT_PLUGINS_PPAPI_PPAPI_PLUGIN_INSTANCE_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/observer_list.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "gfx/rect.h" +#include "ppapi/c/dev/pp_cursor_type_dev.h" +#include "ppapi/c/dev/ppp_graphics_3d_dev.h" +#include "ppapi/c/dev/ppp_printing_dev.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h" + +struct PP_Var; +struct PPB_Instance; +struct PPB_Find_Dev; +struct PPB_Fullscreen_Dev; +struct PPB_Zoom_Dev; +struct PPP_Find_Dev; +struct PPP_Instance; +struct PPP_Pdf; +struct PPP_Selection_Dev; +struct PPP_Zoom_Dev; + +class SkBitmap; +class TransportDIB; + +namespace gfx { +class Rect; +} + +namespace WebKit { +struct WebCursorInfo; +class WebInputEvent; +class WebPluginContainer; +} + +namespace webkit { +namespace ppapi { + +class FullscreenContainer; +class PluginDelegate; +class PluginModule; +class PPB_Graphics2D_Impl; +class PPB_Graphics3D_Impl; +class PPB_ImageData_Impl; +class PPB_URLLoader_Impl; +class Resource; + +// Represents one time a plugin appears on one web page. +// +// Note: to get from a PP_Instance to a PluginInstance*, use the +// ResourceTracker. +class PluginInstance : public base::RefCounted<PluginInstance> { + public: + class Observer { + public: + // Indicates that the instance is being destroyed. This will be called from + // the instance's destructor so don't do anything in this callback that + // uses the instance. + virtual void InstanceDestroyed(PluginInstance* instance) = 0; + }; + + PluginInstance(PluginDelegate* delegate, + PluginModule* module, + const PPP_Instance* instance_interface); + ~PluginInstance(); + + static const PPB_Instance* GetInterface(); + + // Returns a pointer to the interface implementing PPB_Find that is + // exposed to the plugin. + static const PPB_Find_Dev* GetFindInterface(); + static const PPB_Fullscreen_Dev* GetFullscreenInterface(); + static const PPB_Zoom_Dev* GetZoomInterface(); + + PluginDelegate* delegate() const { return delegate_; } + PluginModule* module() const { return module_.get(); } + + WebKit::WebPluginContainer* container() const { return container_; } + + const gfx::Rect& position() const { return position_; } + const gfx::Rect& clip() const { return clip_; } + + int find_identifier() const { return find_identifier_; } + + void set_always_on_top(bool on_top) { always_on_top_ = on_top; } + + // Returns the PP_Instance uniquely identifying this instance. Guaranteed + // nonzero. + PP_Instance pp_instance() const { return pp_instance_; } + + // Other classes can register an observer for instance events. These pointers + // are NOT owned by the Instance. If the object implementing the observer + // goes away, it must take care to unregister itself. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Paints the current backing store to the web page. + void Paint(WebKit::WebCanvas* canvas, + const gfx::Rect& plugin_rect, + const gfx::Rect& paint_rect); + + // Schedules a paint of the page for the given region. The coordinates are + // relative to the top-left of the plugin. This does nothing if the plugin + // has not yet been positioned. You can supply an empty gfx::Rect() to + // invalidate the entire plugin. + void InvalidateRect(const gfx::Rect& rect); + + // Schedules a scroll of the plugin. This uses optimized scrolling only for + // full-frame plugins, as otherwise there could be other elements on top. The + // slow path can also be triggered if there is an overlapping frame. + void ScrollRect(int dx, int dy, const gfx::Rect& rect); + + // If the plugin instance is backed by a texture, return its texture ID in the + // compositor's namespace. Otherwise return 0. Returns 0 by default. + virtual unsigned GetBackingTextureId(); + + // Commit the backing texture to the screen once the side effects some + // rendering up to an offscreen SwapBuffers are visible. + void CommitBackingTexture(); + + // PPB_Instance implementation. + PP_Var GetWindowObject(); + PP_Var GetOwnerElementObject(); + bool BindGraphics(PP_Resource graphics_id); + bool full_frame() const { return full_frame_; } + bool SetCursor(PP_CursorType_Dev type); + PP_Var ExecuteScript(PP_Var script, PP_Var* exception); + + // PPP_Instance pass-through. + void Delete(); + bool Initialize(WebKit::WebPluginContainer* container, + const std::vector<std::string>& arg_names, + const std::vector<std::string>& arg_values, + bool full_frame); + bool HandleDocumentLoad(PPB_URLLoader_Impl* loader); + bool HandleInputEvent(const WebKit::WebInputEvent& event, + WebKit::WebCursorInfo* cursor_info); + PP_Var GetInstanceObject(); + void ViewChanged(const gfx::Rect& position, const gfx::Rect& clip); + + // Notifications about focus changes, see has_webkit_focus_ below. + void SetWebKitFocus(bool has_focus); + void SetContentAreaFocus(bool has_focus); + + // Notifications that the view has rendered the page and that it has been + // flushed to the screen. These messages are used to send Flush callbacks to + // the plugin for DeviceContext2D. + void ViewInitiatedPaint(); + void ViewFlushedPaint(); + + // If this plugin can be painted merely by copying the backing store to the + // screen, and the plugin bounds encloses the given paint bounds, returns + // true. In this case, the location, clipping, and ID of the backing store + // will be filled into the given output parameters. + bool GetBitmapForOptimizedPluginPaint( + const gfx::Rect& paint_bounds, + TransportDIB** dib, + gfx::Rect* dib_bounds, + gfx::Rect* clip); + + string16 GetSelectedText(bool html); + string16 GetLinkAtPosition(const gfx::Point& point); + void Zoom(double factor, bool text_only); + bool StartFind(const string16& search_text, + bool case_sensitive, + int identifier); + void SelectFindResult(bool forward); + void StopFind(); + + bool SupportsPrintInterface(); + int PrintBegin(const gfx::Rect& printable_area, int printer_dpi); + bool PrintPage(int page_number, WebKit::WebCanvas* canvas); + void PrintEnd(); + + void Graphics3DContextLost(); + + // Implementation of PPB_Fullscreen_Dev. + bool IsFullscreen(); + bool SetFullscreen(bool fullscreen); + + // Implementation of PPB_Flash. + bool NavigateToURL(const char* url, const char* target); + + private: + bool LoadFindInterface(); + bool LoadPdfInterface(); + bool LoadSelectionInterface(); + bool LoadZoomInterface(); + + // Determines if we think the plugin has focus, both content area and webkit + // (see has_webkit_focus_ below). + bool PluginHasFocus() const; + + // Queries the plugin for supported print formats and sets |format| to the + // best format to use. Returns false if the plugin does not support any + // print format that we can handle (we can handle raster and PDF). + bool GetPreferredPrintOutputFormat(PP_PrintOutputFormat_Dev* format); + bool PrintPDFOutput(PP_Resource print_output, WebKit::WebCanvas* canvas); + bool PrintRasterOutput(PP_Resource print_output, WebKit::WebCanvas* canvas); +#if defined(OS_WIN) + bool DrawJPEGToPlatformDC(const SkBitmap& bitmap, + const gfx::Rect& printable_area, + WebKit::WebCanvas* canvas); +#elif defined(OS_MACOSX) + // Draws the given kARGB_8888_Config bitmap to the specified canvas starting + // at the specified destination rect. + void DrawSkBitmapToCanvas(const SkBitmap& bitmap, WebKit::WebCanvas* canvas, + const gfx::Rect& dest_rect, int canvas_height); +#endif // OS_MACOSX + + // Get the bound graphics context as a concrete 2D graphics context or returns + // null if the context is not 2D. + PPB_Graphics2D_Impl* bound_graphics_2d() const; + + // Get the bound graphics context as a concrete 3D graphics context or returns + // null if the context is not 3D. + PPB_Graphics3D_Impl* bound_graphics_3d() const; + + PluginDelegate* delegate_; + scoped_refptr<PluginModule> module_; + const PPP_Instance* instance_interface_; + + PP_Instance pp_instance_; + + // NULL until we have been initialized. + WebKit::WebPluginContainer* container_; + + // Indicates whether this is a full frame instance, which means it represents + // an entire document rather than an embed tag. + bool full_frame_; + + // Position in the viewport (which moves as the page is scrolled) of this + // plugin. This will be a 0-sized rectangle if the plugin has not yet been + // laid out. + gfx::Rect position_; + + // Current clip rect. This will be empty if the plugin is not currently + // visible. This is in the plugin's coordinate system, so fully visible will + // be (0, 0, w, h) regardless of scroll position. + gfx::Rect clip_; + + // The current device context for painting in 2D or 3D. + scoped_refptr<Resource> bound_graphics_; + + // We track two types of focus, one from WebKit, which is the focus among + // all elements of the page, one one from the browser, which is whether the + // tab/window has focus. We tell the plugin it has focus only when both of + // these values are set to true. + bool has_webkit_focus_; + bool has_content_area_focus_; + + // The id of the current find operation, or -1 if none is in process. + int find_identifier_; + + // The plugin-provided interfaces. + const PPP_Find_Dev* plugin_find_interface_; + const PPP_Pdf* plugin_pdf_interface_; + const PPP_Selection_Dev* plugin_selection_interface_; + const PPP_Zoom_Dev* plugin_zoom_interface_; + + // This is only valid between a successful PrintBegin call and a PrintEnd + // call. + PP_PrintSettings_Dev current_print_settings_; +#if defined(OS_MACOSX) + // On the Mac, when we draw the bitmap to the PDFContext, it seems necessary + // to keep the pixels valid until CGContextEndPage is called. We use this + // variable to hold on to the pixels. + scoped_refptr<PPB_ImageData_Impl> last_printed_page_; +#elif defined(OS_LINUX) + // On Linux, we always send all pages from the renderer to the browser. + // So, if the plugin supports printPagesAsPDF we print the entire output + // in one shot in the first call to PrintPage. + // (This is a temporary hack until we change the WebFrame and WebPlugin print + // interfaces). + // Specifies the total number of pages to be printed. It it set in PrintBegin. + int32 num_pages_; + // Specifies whether we have already output all pages. This is used to ignore + // subsequent PrintPage requests. + bool pdf_output_done_; +#endif // defined(OS_LINUX) + + // The plugin print interface. + const PPP_Printing_Dev* plugin_print_interface_; + + // The plugin 3D interface. + const PPP_Graphics3D_Dev* plugin_graphics_3d_interface_; + + // Containes the cursor if it's set by the plugin. + scoped_ptr<WebKit::WebCursorInfo> cursor_; + + // Set to true if this plugin thinks it will always be on top. This allows us + // to use a more optimized painting path in some cases. + bool always_on_top_; + + // Plugin container for fullscreen mode. NULL if not in fullscreen mode. + FullscreenContainer* fullscreen_container_; + + // Non-owning pointers to all active observers. + ObserverList<Observer, false> observers_; + + DISALLOW_COPY_AND_ASSIGN(PluginInstance); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPAPI_PLUGIN_INSTANCE_H_ diff --git a/webkit/plugins/ppapi/ppapi_unittest.cc b/webkit/plugins/ppapi/ppapi_unittest.cc new file mode 100644 index 0000000..12cb99d --- /dev/null +++ b/webkit/plugins/ppapi/ppapi_unittest.cc @@ -0,0 +1,113 @@ +// 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 "webkit/plugins/ppapi/ppapi_unittest.h" + +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppp_instance.h" +#include "webkit/plugins/ppapi/mock_plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PpapiUnittest* current_unittest = NULL; + +const void* MockGetInterface(const char* interface_name) { + return current_unittest->GetMockInterface(interface_name); +} + +int MockInitializeModule(PP_Module, PPB_GetInterface) { + return PP_OK; +} + +// PPP_Instance implementation ------------------------------------------------ + +PP_Bool Instance_DidCreate(PP_Instance pp_instance, + uint32_t argc, + const char* argn[], + const char* argv[]) { + return PP_TRUE; +} + +void Instance_DidDestroy(PP_Instance instance) { +} + +void Instance_DidChangeView(PP_Instance pp_instance, + const PP_Rect* position, + const PP_Rect* clip) { +} + +void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) { +} + +PP_Bool Instance_HandleInputEvent(PP_Instance pp_instance, + const PP_InputEvent* event) { + return PP_FALSE; +} + +PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance, + PP_Resource pp_url_loader) { + return PP_FALSE; +} + +PP_Var Instance_GetInstanceObject(PP_Instance pp_instance) { + return PP_MakeUndefined(); +} + +static PPP_Instance mock_instance_interface = { + &Instance_DidCreate, + &Instance_DidDestroy, + &Instance_DidChangeView, + &Instance_DidChangeFocus, + &Instance_HandleInputEvent, + &Instance_HandleDocumentLoad, + &Instance_GetInstanceObject +}; + +} // namespace + +// PpapiUnittest -------------------------------------------------------------- + +PpapiUnittest::PpapiUnittest() { + DCHECK(!current_unittest); + current_unittest = this; +} + +PpapiUnittest::~PpapiUnittest() { + DCHECK(current_unittest == this); + current_unittest = NULL; +} + +void PpapiUnittest::SetUp() { + delegate_.reset(new MockPluginDelegate); + + // Initialize the mock module. + module_ = new PluginModule; + PluginModule::EntryPoints entry_points; + entry_points.get_interface = &MockGetInterface; + entry_points.initialize_module = &MockInitializeModule; + ASSERT_TRUE(module_->InitAsInternalPlugin(entry_points)); + + // Initialize the mock instance. + instance_ = new PluginInstance(delegate_.get(), module(), + static_cast<const PPP_Instance*>( + GetMockInterface(PPP_INSTANCE_INTERFACE))); +} + +void PpapiUnittest::TearDown() { +} + +const void* PpapiUnittest::GetMockInterface(const char* interface_name) const { + if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) + return &mock_instance_interface; + return NULL; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppapi_unittest.h b/webkit/plugins/ppapi/ppapi_unittest.h new file mode 100644 index 0000000..ae15467 --- /dev/null +++ b/webkit/plugins/ppapi/ppapi_unittest.h @@ -0,0 +1,48 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPAPI_UNITTEST_H_ +#define WEBKIT_PLUGINS_PPAPI_PPAPI_UNITTEST_H_ + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace webkit { +namespace ppapi { + +class MockPluginDelegate; +class PluginInstance; +class PluginModule; + +class PpapiUnittest : public testing::Test { + public: + PpapiUnittest(); + virtual ~PpapiUnittest(); + + virtual void SetUp(); + virtual void TearDown(); + + PluginModule* module() const { return module_.get(); } + PluginInstance* instance() const { return instance_.get(); } + + // Provides access to the interfaces implemented by the test. The default one + // implements PPP_INSTANCE. + virtual const void* GetMockInterface(const char* interface_name) const; + + private: + scoped_ptr<MockPluginDelegate> delegate_; + + // Note: module must be declared first since we want it to get destroyed last. + scoped_refptr<PluginModule> module_; + scoped_refptr<PluginInstance> instance_; + + DISALLOW_COPY_AND_ASSIGN(PpapiUnittest); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_GLUE_PPAPI_PLUGINS_PPAPI_UNITTEST_H_ diff --git a/webkit/plugins/ppapi/ppapi_webplugin_impl.cc b/webkit/plugins/ppapi/ppapi_webplugin_impl.cc new file mode 100644 index 0000000..e760198 --- /dev/null +++ b/webkit/plugins/ppapi/ppapi_webplugin_impl.cc @@ -0,0 +1,229 @@ +// 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 "webkit/plugins/ppapi/ppapi_webplugin_impl.h" + +#include <cmath> + +#include "base/message_loop.h" +#include "ppapi/c/pp_var.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPoint.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_url_loader_impl.h" +#include "webkit/plugins/ppapi/var.h" + +using WebKit::WebCanvas; +using WebKit::WebPluginContainer; +using WebKit::WebPluginParams; +using WebKit::WebPoint; +using WebKit::WebRect; +using WebKit::WebString; +using WebKit::WebURL; +using WebKit::WebVector; +using WebKit::WebView; + +namespace webkit { +namespace ppapi { + +struct WebPluginImpl::InitData { + scoped_refptr<PluginModule> module; + base::WeakPtr<PluginDelegate> delegate; + std::vector<std::string> arg_names; + std::vector<std::string> arg_values; +}; + +WebPluginImpl::WebPluginImpl( + PluginModule* plugin_module, + const WebPluginParams& params, + const base::WeakPtr<PluginDelegate>& plugin_delegate) + : init_data_(new InitData()), + full_frame_(params.loadManually) { + DCHECK(plugin_module); + init_data_->module = plugin_module; + init_data_->delegate = plugin_delegate; + for (size_t i = 0; i < params.attributeNames.size(); ++i) { + init_data_->arg_names.push_back(params.attributeNames[i].utf8()); + init_data_->arg_values.push_back(params.attributeValues[i].utf8()); + } +} + +WebPluginImpl::~WebPluginImpl() { +} + +bool WebPluginImpl::initialize(WebPluginContainer* container) { + // The plugin delegate may have gone away. + if (!init_data_->delegate) + return false; + + instance_ = init_data_->module->CreateInstance(init_data_->delegate); + if (!instance_) + return false; + + bool success = instance_->Initialize(container, + init_data_->arg_names, + init_data_->arg_values, + full_frame_); + if (!success) { + instance_->Delete(); + instance_ = NULL; + return false; + } + + init_data_.reset(); + return true; +} + +void WebPluginImpl::destroy() { + if (instance_) { + instance_->Delete(); + instance_ = NULL; + } + + MessageLoop::current()->DeleteSoon(FROM_HERE, this); +} + +NPObject* WebPluginImpl::scriptableObject() { + scoped_refptr<ObjectVar> object( + ObjectVar::FromPPVar(instance_->GetInstanceObject())); + if (object) + return object->np_object(); + return NULL; +} + +void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& rect) { + if (!instance_->IsFullscreen()) + instance_->Paint(canvas, plugin_rect_, rect); +} + +void WebPluginImpl::updateGeometry( + const WebRect& window_rect, + const WebRect& clip_rect, + const WebVector<WebRect>& cut_outs_rects, + bool is_visible) { + plugin_rect_ = window_rect; + if (!instance_->IsFullscreen()) + instance_->ViewChanged(plugin_rect_, clip_rect); +} + +unsigned WebPluginImpl::getBackingTextureId() { + return instance_->GetBackingTextureId(); +} + +void WebPluginImpl::updateFocus(bool focused) { + instance_->SetWebKitFocus(focused); +} + +void WebPluginImpl::updateVisibility(bool visible) { +} + +bool WebPluginImpl::acceptsInputEvents() { + return true; +} + +bool WebPluginImpl::handleInputEvent(const WebKit::WebInputEvent& event, + WebKit::WebCursorInfo& cursor_info) { + if (instance_->IsFullscreen()) + return false; + return instance_->HandleInputEvent(event, &cursor_info); +} + +void WebPluginImpl::didReceiveResponse( + const WebKit::WebURLResponse& response) { + DCHECK(!document_loader_); + + document_loader_ = new PPB_URLLoader_Impl(instance_, true); + document_loader_->didReceiveResponse(NULL, response); + + if (!instance_->HandleDocumentLoad(document_loader_)) + document_loader_ = NULL; +} + +void WebPluginImpl::didReceiveData(const char* data, int data_length) { + if (document_loader_) + document_loader_->didReceiveData(NULL, data, data_length); +} + +void WebPluginImpl::didFinishLoading() { + if (document_loader_) { + document_loader_->didFinishLoading(NULL, 0); + document_loader_ = NULL; + } +} + +void WebPluginImpl::didFailLoading(const WebKit::WebURLError& error) { + if (document_loader_) { + document_loader_->didFail(NULL, error); + document_loader_ = NULL; + } +} + +void WebPluginImpl::didFinishLoadingFrameRequest(const WebKit::WebURL& url, + void* notify_data) { +} + +void WebPluginImpl::didFailLoadingFrameRequest( + const WebKit::WebURL& url, + void* notify_data, + const WebKit::WebURLError& error) { +} + +bool WebPluginImpl::hasSelection() const { + return !selectionAsText().isEmpty(); +} + +WebString WebPluginImpl::selectionAsText() const { + return instance_->GetSelectedText(false); +} + +WebString WebPluginImpl::selectionAsMarkup() const { + return instance_->GetSelectedText(true); +} + +WebURL WebPluginImpl::linkAtPosition(const WebPoint& position) const { + return GURL(instance_->GetLinkAtPosition(position)); +} + +void WebPluginImpl::setZoomLevel(double level, bool text_only) { + instance_->Zoom(WebView::zoomLevelToZoomFactor(level), text_only); +} + +bool WebPluginImpl::startFind(const WebKit::WebString& search_text, + bool case_sensitive, + int identifier) { + return instance_->StartFind(search_text, case_sensitive, identifier); +} + +void WebPluginImpl::selectFindResult(bool forward) { + instance_->SelectFindResult(forward); +} + +void WebPluginImpl::stopFind() { + instance_->StopFind(); +} + +bool WebPluginImpl::supportsPaginatedPrint() { + return instance_->SupportsPrintInterface(); +} + +int WebPluginImpl::printBegin(const WebKit::WebRect& printable_area, + int printer_dpi) { + return instance_->PrintBegin(printable_area, printer_dpi); +} + +bool WebPluginImpl::printPage(int page_number, + WebKit::WebCanvas* canvas) { + return instance_->PrintPage(page_number, canvas); +} + +void WebPluginImpl::printEnd() { + return instance_->PrintEnd(); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppapi_webplugin_impl.h b/webkit/plugins/ppapi/ppapi_webplugin_impl.h new file mode 100644 index 0000000..0f86ca6 --- /dev/null +++ b/webkit/plugins/ppapi/ppapi_webplugin_impl.h @@ -0,0 +1,97 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPAPI_WEBPLUGIN_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPAPI_WEBPLUGIN_IMPL_H_ + +#include <string> +#include <vector> + +#include "base/weak_ptr.h" +#include "base/scoped_ptr.h" +#include "base/task.h" +#include "gfx/rect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPlugin.h" + +namespace WebKit { +struct WebPluginParams; +} + +namespace webkit { +namespace ppapi { + +class PluginDelegate; +class PluginInstance; +class PluginModule; +class PPB_URLLoader_Impl; + +class WebPluginImpl : public WebKit::WebPlugin { + public: + WebPluginImpl(PluginModule* module, + const WebKit::WebPluginParams& params, + const base::WeakPtr<PluginDelegate>& plugin_delegate); + + private: + friend class DeleteTask<WebPluginImpl>; + + ~WebPluginImpl(); + + // WebKit::WebPlugin implementation. + virtual bool initialize(WebKit::WebPluginContainer* container); + virtual void destroy(); + virtual NPObject* scriptableObject(); + virtual void paint(WebKit::WebCanvas* canvas, const WebKit::WebRect& rect); + virtual void updateGeometry( + const WebKit::WebRect& frame_rect, + const WebKit::WebRect& clip_rect, + const WebKit::WebVector<WebKit::WebRect>& cut_outs_rects, + bool is_visible); + virtual unsigned getBackingTextureId(); + virtual void updateFocus(bool focused); + virtual void updateVisibility(bool visible); + virtual bool acceptsInputEvents(); + virtual bool handleInputEvent(const WebKit::WebInputEvent& event, + WebKit::WebCursorInfo& cursor_info); + virtual void didReceiveResponse(const WebKit::WebURLResponse& response); + virtual void didReceiveData(const char* data, int data_length); + virtual void didFinishLoading(); + virtual void didFailLoading(const WebKit::WebURLError&); + virtual void didFinishLoadingFrameRequest(const WebKit::WebURL& url, + void* notify_data); + virtual void didFailLoadingFrameRequest(const WebKit::WebURL& url, + void* notify_data, + const WebKit::WebURLError& error); + virtual bool hasSelection() const; + virtual WebKit::WebString selectionAsText() const; + virtual WebKit::WebString selectionAsMarkup() const; + virtual WebKit::WebURL linkAtPosition(const WebKit::WebPoint& position) const; + virtual void setZoomLevel(double level, bool text_only); + virtual bool startFind(const WebKit::WebString& search_text, + bool case_sensitive, + int identifier); + virtual void selectFindResult(bool forward); + virtual void stopFind(); + virtual bool supportsPaginatedPrint(); + virtual int printBegin(const WebKit::WebRect& printable_area, + int printer_dpi); + virtual bool printPage(int page_number, WebKit::WebCanvas* canvas); + virtual void printEnd(); + + struct InitData; + + scoped_ptr<InitData> init_data_; // Cleared upon successful initialization. + // True if the instance represents the entire document in a frame instead of + // being an embedded resource. + bool full_frame_; + scoped_refptr<PluginInstance> instance_; + scoped_refptr<PPB_URLLoader_Impl> document_loader_; + gfx::Rect plugin_rect_; + + DISALLOW_COPY_AND_ASSIGN(WebPluginImpl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPAPI_WEBPLUGIN_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_audio_impl.cc b/webkit/plugins/ppapi/ppb_audio_impl.cc new file mode 100644 index 0000000..db11eba --- /dev/null +++ b/webkit/plugins/ppapi/ppb_audio_impl.cc @@ -0,0 +1,365 @@ +// 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 "webkit/plugins/ppapi/ppb_audio_impl.h" + +#include "base/logging.h" +#include "ppapi/c/dev/ppb_audio_dev.h" +#include "ppapi/c/dev/ppb_audio_trusted_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "webkit/plugins/ppapi/common.h" + +namespace webkit { +namespace ppapi { + +namespace { + +// PPB_AudioConfig ------------------------------------------------------------- + +uint32_t RecommendSampleFrameCount(uint32_t requested_sample_frame_count); + +PP_Resource CreateStereo16bit(PP_Module module_id, + PP_AudioSampleRate_Dev sample_rate, + uint32_t sample_frame_count) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + + // TODO(brettw): Currently we don't actually check what the hardware + // supports, so just allow sample rates of the "guaranteed working" ones. + if (sample_rate != PP_AUDIOSAMPLERATE_44100 && + sample_rate != PP_AUDIOSAMPLERATE_48000) + return 0; + + // TODO(brettw): Currently we don't actually query to get a value from the + // hardware, so just validate the range. + if (RecommendSampleFrameCount(sample_frame_count) != sample_frame_count) + return 0; + + scoped_refptr<PPB_AudioConfig_Impl> config( + new PPB_AudioConfig_Impl(module, sample_rate, sample_frame_count)); + return config->GetReference(); +} + +uint32_t RecommendSampleFrameCount(uint32_t requested_sample_frame_count) { + // TODO(brettw) Currently we don't actually query to get a value from the + // hardware, so we always return the input for in-range values. + if (requested_sample_frame_count < PP_AUDIOMINSAMPLEFRAMECOUNT) + return PP_AUDIOMINSAMPLEFRAMECOUNT; + if (requested_sample_frame_count > PP_AUDIOMAXSAMPLEFRAMECOUNT) + return PP_AUDIOMAXSAMPLEFRAMECOUNT; + return requested_sample_frame_count; +} + +PP_Bool IsAudioConfig(PP_Resource resource) { + scoped_refptr<PPB_AudioConfig_Impl> config = + Resource::GetAs<PPB_AudioConfig_Impl>(resource); + return BoolToPPBool(!!config); +} + +PP_AudioSampleRate_Dev GetSampleRate(PP_Resource config_id) { + scoped_refptr<PPB_AudioConfig_Impl> config = + Resource::GetAs<PPB_AudioConfig_Impl>(config_id); + return config ? config->sample_rate() : PP_AUDIOSAMPLERATE_NONE; +} + +uint32_t GetSampleFrameCount(PP_Resource config_id) { + scoped_refptr<PPB_AudioConfig_Impl> config = + Resource::GetAs<PPB_AudioConfig_Impl>(config_id); + return config ? config->sample_frame_count() : 0; +} + +const PPB_AudioConfig_Dev ppb_audioconfig = { + &CreateStereo16bit, + &RecommendSampleFrameCount, + &IsAudioConfig, + &GetSampleRate, + &GetSampleFrameCount +}; + +// PPB_Audio ------------------------------------------------------------------- + +PP_Resource Create(PP_Instance instance_id, PP_Resource config_id, + PPB_Audio_Callback user_callback, void* user_data) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return 0; + if (!user_callback) + return 0; + scoped_refptr<PPB_Audio_Impl> audio( + new PPB_Audio_Impl(instance->module(), instance_id)); + if (!audio->Init(instance->delegate(), config_id, + user_callback, user_data)) + return 0; + return audio->GetReference(); +} + +PP_Bool IsAudio(PP_Resource resource) { + scoped_refptr<PPB_Audio_Impl> audio = + Resource::GetAs<PPB_Audio_Impl>(resource); + return BoolToPPBool(!!audio); +} + +PP_Resource GetCurrentConfig(PP_Resource audio_id) { + scoped_refptr<PPB_Audio_Impl> audio = Resource::GetAs<PPB_Audio_Impl>(audio_id); + return audio ? audio->GetCurrentConfig() : 0; +} + +PP_Bool StartPlayback(PP_Resource audio_id) { + scoped_refptr<PPB_Audio_Impl> audio = + Resource::GetAs<PPB_Audio_Impl>(audio_id); + return audio ? BoolToPPBool(audio->StartPlayback()) : PP_FALSE; +} + +PP_Bool StopPlayback(PP_Resource audio_id) { + scoped_refptr<PPB_Audio_Impl> audio = + Resource::GetAs<PPB_Audio_Impl>(audio_id); + return audio ? BoolToPPBool(audio->StopPlayback()) : PP_FALSE; +} + +const PPB_Audio_Dev ppb_audio = { + &Create, + &IsAudio, + &GetCurrentConfig, + &StartPlayback, + &StopPlayback, +}; + +// PPB_AudioTrusted ------------------------------------------------------------ + +PP_Resource CreateTrusted(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return 0; + scoped_refptr<PPB_Audio_Impl> audio(new PPB_Audio_Impl(instance->module(), instance_id)); + return audio->GetReference(); +} + +int32_t Open(PP_Resource audio_id, + PP_Resource config_id, + PP_CompletionCallback created) { + scoped_refptr<PPB_Audio_Impl> audio = + Resource::GetAs<PPB_Audio_Impl>(audio_id); + if (!audio) + return PP_ERROR_BADRESOURCE; + if (!created.func) + return PP_ERROR_BADARGUMENT; + PP_Instance instance_id = audio->pp_instance(); + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_ERROR_FAILED; + return audio->Open(instance->delegate(), config_id, created); +} + +int32_t GetSyncSocket(PP_Resource audio_id, int* sync_socket) { + scoped_refptr<PPB_Audio_Impl> audio = + Resource::GetAs<PPB_Audio_Impl>(audio_id); + if (audio) + return audio->GetSyncSocket(sync_socket); + return PP_ERROR_BADRESOURCE; +} + +int32_t GetSharedMemory(PP_Resource audio_id, + int* shm_handle, + uint32_t* shm_size) { + scoped_refptr<PPB_Audio_Impl> audio = + Resource::GetAs<PPB_Audio_Impl>(audio_id); + if (audio) + return audio->GetSharedMemory(shm_handle, shm_size); + return PP_ERROR_BADRESOURCE; +} + +const PPB_AudioTrusted_Dev ppb_audiotrusted = { + &CreateTrusted, + &Open, + &GetSyncSocket, + &GetSharedMemory, +}; + +} // namespace + +// PPB_AudioConfig_Impl -------------------------------------------------------- + +PPB_AudioConfig_Impl::PPB_AudioConfig_Impl( + PluginModule* module, + PP_AudioSampleRate_Dev sample_rate, + uint32_t sample_frame_count) + : Resource(module), + sample_rate_(sample_rate), + sample_frame_count_(sample_frame_count) { +} + +const PPB_AudioConfig_Dev* PPB_AudioConfig_Impl::GetInterface() { + return &ppb_audioconfig; +} + +size_t PPB_AudioConfig_Impl::BufferSize() { + // TODO(audio): as more options become available, we'll need to + // have additional code here to correctly calculate the size in + // bytes of an audio buffer. For now, only support two channel + // int16_t sample buffers. + const int kChannels = 2; + const int kSizeOfSample = sizeof(int16_t); + return static_cast<size_t>(sample_frame_count_ * kSizeOfSample * kChannels); +} + +PPB_AudioConfig_Impl* PPB_AudioConfig_Impl::AsPPB_AudioConfig_Impl() { + return this; +} + +// PPB_Audio_Impl -------------------------------------------------------------- + +PPB_Audio_Impl::PPB_Audio_Impl(PluginModule* module, PP_Instance instance_id) + : Resource(module), + pp_instance_(instance_id), + audio_(NULL), + create_callback_pending_(false) { + create_callback_ = PP_MakeCompletionCallback(NULL, NULL); +} + +PPB_Audio_Impl::~PPB_Audio_Impl() { + // Calling ShutDown() makes sure StreamCreated cannot be called anymore. + audio_->ShutDown(); + audio_ = NULL; + + // If the completion callback hasn't fired yet, do so here + // with an error condition. + if (create_callback_pending_) { + PP_RunCompletionCallback(&create_callback_, PP_ERROR_ABORTED); + create_callback_pending_ = false; + } +} + +const PPB_Audio_Dev* PPB_Audio_Impl::GetInterface() { + return &ppb_audio; +} + +const PPB_AudioTrusted_Dev* PPB_Audio_Impl::GetTrustedInterface() { + return &ppb_audiotrusted; +} + +PPB_Audio_Impl* PPB_Audio_Impl::AsPPB_Audio_Impl() { + return this; +} + +bool PPB_Audio_Impl::Init(PluginDelegate* plugin_delegate, + PP_Resource config_id, + PPB_Audio_Callback callback, void* user_data) { + CHECK(!audio_); + config_ = Resource::GetAs<PPB_AudioConfig_Impl>(config_id); + if (!config_) + return false; + SetCallback(callback, user_data); + + // When the stream is created, we'll get called back on StreamCreated(). + audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), + config_->sample_frame_count(), + this); + return audio_ != NULL; +} + +PP_Resource PPB_Audio_Impl::GetCurrentConfig() { + return config_->GetReference(); +} + +bool PPB_Audio_Impl::StartPlayback() { + if (playing()) + return true; + SetStartPlaybackState(); + return audio_->StartPlayback(); +} + +bool PPB_Audio_Impl::StopPlayback() { + if (!playing()) + return true; + if (!audio_->StopPlayback()) + return false; + SetStopPlaybackState(); + return true; +} + +int32_t PPB_Audio_Impl::Open(PluginDelegate* plugin_delegate, + PP_Resource config_id, + PP_CompletionCallback create_callback) { + DCHECK(!audio_); + config_ = Resource::GetAs<PPB_AudioConfig_Impl>(config_id); + if (!config_) + return PP_ERROR_BADRESOURCE; + + // When the stream is created, we'll get called back on StreamCreated(). + audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), + config_->sample_frame_count(), + this); + if (!audio_) + return PP_ERROR_FAILED; + + // At this point, we are guaranteeing ownership of the completion + // callback. Audio promises to fire the completion callback + // once and only once. + create_callback_ = create_callback; + create_callback_pending_ = true; + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_Audio_Impl::GetSyncSocket(int* sync_socket) { + if (socket_for_create_callback_.get()) { +#if defined(OS_POSIX) + *sync_socket = socket_for_create_callback_->handle(); +#elif defined(OS_WIN) + *sync_socket = reinterpret_cast<int>(socket_for_create_callback_->handle()); +#else + #error "Platform not supported." +#endif + return PP_OK; + } + return PP_ERROR_FAILED; +} + +int32_t PPB_Audio_Impl::GetSharedMemory(int* shm_handle, uint32_t* shm_size) { + if (shared_memory_for_create_callback_.get()) { +#if defined(OS_POSIX) + *shm_handle = shared_memory_for_create_callback_->handle().fd; +#elif defined(OS_WIN) + *shm_handle = reinterpret_cast<int>( + shared_memory_for_create_callback_->handle()); +#else + #error "Platform not supported." +#endif + *shm_size = shared_memory_size_for_create_callback_; + return PP_OK; + } + return PP_ERROR_FAILED; +} + +void PPB_Audio_Impl::StreamCreated( + base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size, + base::SyncSocket::Handle socket_handle) { + if (create_callback_pending_) { + // Trusted side of proxy can specify a callback to recieve handles. In + // this case we don't need to map any data or start the thread since it + // will be handled by the proxy. + shared_memory_for_create_callback_.reset( + new base::SharedMemory(shared_memory_handle, false)); + shared_memory_size_for_create_callback_ = shared_memory_size; + socket_for_create_callback_.reset(new base::SyncSocket(socket_handle)); + + PP_RunCompletionCallback(&create_callback_, 0); + create_callback_pending_ = false; + + // It might be nice to close the handles here to free up some system + // resources, but we can't since there's a race condition. The handles must + // be valid until they're sent over IPC, which is done from the I/O thread + // which will often get done after this code executes. We could do + // something more elaborate like an ACK from the plugin or post a task to + // the I/O thread and back, but this extra complexity doesn't seem worth it + // just to clean up these handles faster. + } else { + SetStreamInfo(shared_memory_handle, shared_memory_size, socket_handle); + } +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_audio_impl.h b/webkit/plugins/ppapi/ppb_audio_impl.h new file mode 100644 index 0000000..bcab4a4 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_audio_impl.h @@ -0,0 +1,116 @@ +// 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 WEBKIT_PLUGINS_PPAPI_DEVICE_CONTEXT_AUDIO_H_ +#define WEBKIT_PLUGINS_PPAPI_DEVICE_CONTEXT_AUDIO_H_ + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "base/shared_memory.h" +#include "base/sync_socket.h" +#include "ppapi/c/dev/ppb_audio_dev.h" +#include "ppapi/c/dev/ppb_audio_config_dev.h" +#include "ppapi/c/dev/ppb_audio_trusted_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/shared_impl/audio_impl.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace webkit { +namespace ppapi { + +class PluginInstance; +class PluginModule; + +class PPB_AudioConfig_Impl : public Resource { + public: + PPB_AudioConfig_Impl(PluginModule* module, + PP_AudioSampleRate_Dev sample_rate, + uint32_t sample_frame_count); + size_t BufferSize(); + static const PPB_AudioConfig_Dev* GetInterface(); + + PP_AudioSampleRate_Dev sample_rate() { return sample_rate_; } + uint32_t sample_frame_count() { return sample_frame_count_; } + + private: + // Resource override. + virtual PPB_AudioConfig_Impl* AsPPB_AudioConfig_Impl(); + + PP_AudioSampleRate_Dev sample_rate_; + uint32_t sample_frame_count_; +}; + +// Some of the backend functionality of this class is implemented by the +// AudioImpl so it can be shared with the proxy. +class PPB_Audio_Impl : public Resource, + public pp::shared_impl::AudioImpl, + public PluginDelegate::PlatformAudio::Client { + public: + explicit PPB_Audio_Impl(PluginModule* module, PP_Instance instance_id); + virtual ~PPB_Audio_Impl(); + + static const PPB_Audio_Dev* GetInterface(); + static const PPB_AudioTrusted_Dev* GetTrustedInterface(); + + PP_Instance pp_instance() { + return pp_instance_; + } + + // PPB_Audio implementation. + bool Init(PluginDelegate* plugin_delegate, + PP_Resource config_id, + PPB_Audio_Callback user_callback, void* user_data); + PP_Resource GetCurrentConfig(); + bool StartPlayback(); + bool StopPlayback(); + + // PPB_Audio_Trusted implementation. + int32_t Open(PluginDelegate* plugin_delegate, + PP_Resource config_id, + PP_CompletionCallback create_callback); + int32_t GetSyncSocket(int* sync_socket); + int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size); + + // Resource override. + virtual PPB_Audio_Impl* AsPPB_Audio_Impl(); + + private: + // PluginDelegate::PlatformAudio::Client implementation. + virtual void StreamCreated(base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size_, + base::SyncSocket::Handle socket); + + // AudioConfig used for creating this Audio object. + scoped_refptr<PPB_AudioConfig_Impl> config_; + + // Plugin instance that owns this audio object. + PP_Instance pp_instance_; + + // PluginDelegate audio object that we delegate audio IPC through. + PluginDelegate::PlatformAudio* audio_; + + // Is a create callback pending to fire? + bool create_callback_pending_; + + // Trusted callback invoked from StreamCreated. + PP_CompletionCallback create_callback_; + + // When a create callback is being issued, these will save the info for + // querying from the callback. The proxy uses this to get the handles to the + // other process instead of mapping them in the renderer. These will be + // invalid all other times. + scoped_ptr<base::SharedMemory> shared_memory_for_create_callback_; + size_t shared_memory_size_for_create_callback_; + scoped_ptr<base::SyncSocket> socket_for_create_callback_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Audio_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_DEVICE_CONTEXT_AUDIO_H_ diff --git a/webkit/plugins/ppapi/ppb_buffer_impl.cc b/webkit/plugins/ppapi/ppb_buffer_impl.cc new file mode 100644 index 0000000..1c67ec3 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_buffer_impl.cc @@ -0,0 +1,121 @@ +// 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 "webkit/plugins/ppapi/ppb_buffer_impl.h" + +#include <algorithm> + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "ppapi/c/dev/ppb_buffer_dev.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Resource Create(PP_Module module_id, uint32_t size) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + + scoped_refptr<PPB_Buffer_Impl> buffer(new PPB_Buffer_Impl(module)); + if (!buffer->Init(size)) + return 0; + + return buffer->GetReference(); +} + +PP_Bool IsPPB_Buffer_Impl(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_Buffer_Impl>(resource)); +} + +PP_Bool Describe(PP_Resource resource, uint32_t* size_in_bytes) { + scoped_refptr<PPB_Buffer_Impl> buffer( + Resource::GetAs<PPB_Buffer_Impl>(resource)); + if (!buffer) + return PP_FALSE; + buffer->Describe(size_in_bytes); + return PP_TRUE; +} + +void* Map(PP_Resource resource) { + scoped_refptr<PPB_Buffer_Impl> buffer( + Resource::GetAs<PPB_Buffer_Impl>(resource)); + if (!buffer) + return NULL; + return buffer->Map(); +} + +void Unmap(PP_Resource resource) { + scoped_refptr<PPB_Buffer_Impl> buffer( + Resource::GetAs<PPB_Buffer_Impl>(resource)); + if (!buffer) + return; + return buffer->Unmap(); +} + +const PPB_Buffer_Dev ppb_buffer = { + &Create, + &IsPPB_Buffer_Impl, + &Describe, + &Map, + &Unmap, +}; + +} // namespace + +PPB_Buffer_Impl::PPB_Buffer_Impl(PluginModule* module) + : Resource(module), + size_(0) { +} + +PPB_Buffer_Impl::~PPB_Buffer_Impl() { +} + +// static +const PPB_Buffer_Dev* PPB_Buffer_Impl::GetInterface() { + return &ppb_buffer; +} + +PPB_Buffer_Impl* PPB_Buffer_Impl::AsPPB_Buffer_Impl() { + return this; +} + +bool PPB_Buffer_Impl::Init(uint32_t size) { + if (size == 0) + return false; + Unmap(); + size_ = size; + return true; +} + +void PPB_Buffer_Impl::Describe(uint32_t* size_in_bytes) const { + *size_in_bytes = size_; +} + +void* PPB_Buffer_Impl::Map() { + if (size_ == 0) + return NULL; + + if (!is_mapped()) { + mem_buffer_.reset(new unsigned char[size_]); + memset(mem_buffer_.get(), 0, size_); + } + return mem_buffer_.get(); +} + +void PPB_Buffer_Impl::Unmap() { + mem_buffer_.reset(); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_buffer_impl.h b/webkit/plugins/ppapi/ppb_buffer_impl.h new file mode 100644 index 0000000..9642e51 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_buffer_impl.h @@ -0,0 +1,55 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_BUFFER_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_BUFFER_IMPL_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PPB_Buffer_Dev; + +namespace webkit { +namespace ppapi { + +class PluginInstance; + +class PPB_Buffer_Impl : public Resource { + public: + explicit PPB_Buffer_Impl(PluginModule* module); + virtual ~PPB_Buffer_Impl(); + + uint32_t size() const { return size_; } + unsigned char* mapped_buffer() { return mem_buffer_.get(); } + + // Returns true if this buffer is mapped. False means that the buffer is + // either invalid or not mapped. + bool is_mapped() const { return !!mem_buffer_.get(); } + + // Returns a pointer to the interface implementing PPB_PPB_Buffer_Impl that is + // exposed to the plugin. + static const PPB_Buffer_Dev* GetInterface(); + + // Resource overrides. + virtual PPB_Buffer_Impl* AsPPB_Buffer_Impl(); + + // PPB_PPB_Buffer_Impl implementation. + bool Init(uint32_t size); + void Describe(uint32_t* size_in_bytes) const; + void* Map(); + void Unmap(); + + private: + uint32_t size_; + scoped_array<unsigned char> mem_buffer_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Buffer_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_BUFFER_IMPL_H_ + diff --git a/webkit/plugins/ppapi/ppb_char_set_impl.cc b/webkit/plugins/ppapi/ppb_char_set_impl.cc new file mode 100644 index 0000000..edab32e --- /dev/null +++ b/webkit/plugins/ppapi/ppb_char_set_impl.cc @@ -0,0 +1,169 @@ +// 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 "webkit/plugins/ppapi/ppb_char_set_impl.h" + +#include <stdlib.h> + +#include "base/i18n/icu_string_conversions.h" +#include "ppapi/c/dev/ppb_char_set_dev.h" +#include "unicode/ucnv.h" +#include "unicode/ucnv_cb.h" +#include "unicode/ucnv_err.h" +#include "unicode/ustring.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/var.h" + +namespace webkit { +namespace ppapi { + +namespace { + +// Converts the given PP error handling behavior to the version in base, +// placing the result in |*result| and returning true on success. Returns false +// if the enum is invalid. +bool PPToBaseConversionError(PP_CharSet_ConversionError on_error, + base::OnStringConversionError::Type* result) { + switch (on_error) { + case PP_CHARSET_CONVERSIONERROR_FAIL: + *result = base::OnStringConversionError::FAIL; + return true; + case PP_CHARSET_CONVERSIONERROR_SKIP: + *result = base::OnStringConversionError::SKIP; + return true; + case PP_CHARSET_CONVERSIONERROR_SUBSTITUTE: + *result = base::OnStringConversionError::SUBSTITUTE; + return true; + default: + return false; + } +} + +// The "substitution" behavior of this function does not match the +// implementation in base, so we partially duplicate the code from +// icu_string_conversions.cc with the correct error handling setup required +// by this PPAPI interface. +char* UTF16ToCharSet(const uint16_t* utf16, uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length) { + *output_length = 0; + + UErrorCode status = U_ZERO_ERROR; + UConverter* converter = ucnv_open(output_char_set, &status); + if (!U_SUCCESS(status)) + return NULL; + + int encoded_max_length = UCNV_GET_MAX_BYTES_FOR_STRING(utf16_len, + ucnv_getMaxCharSize(converter)); + + // Setup our error handler. + switch (on_error) { + case PP_CHARSET_CONVERSIONERROR_FAIL: + ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_STOP, 0, + NULL, NULL, &status); + break; + case PP_CHARSET_CONVERSIONERROR_SKIP: + ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SKIP, 0, + NULL, NULL, &status); + break; + case PP_CHARSET_CONVERSIONERROR_SUBSTITUTE: { + // ICU sets the substitution char for some character sets (like latin1) + // to be the ASCII "substitution character" (26). We want to use '?' + // instead for backwards-compat with Windows behavior. + char subst_chars[32]; + int8_t subst_chars_len = 32; + ucnv_getSubstChars(converter, subst_chars, &subst_chars_len, &status); + if (subst_chars_len == 1 && subst_chars[0] == 26) { + // Override to the question mark character if possible. When using + // setSubstString, the input is a Unicode character. The function will + // try to convert it to the destination character set and fail if that + // can not be converted to the destination character set. + // + // We just ignore any failure. If the dest char set has no + // representation for '?', then we'll just stick to the ICU default + // substitution character. + UErrorCode subst_status = U_ZERO_ERROR; + UChar question_mark = '?'; + ucnv_setSubstString(converter, &question_mark, 1, &subst_status); + } + + ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SUBSTITUTE, 0, + NULL, NULL, &status); + break; + } + default: + return NULL; + } + + // ucnv_fromUChars returns size not including terminating null. + char* encoded = static_cast<char*>(malloc(encoded_max_length + 1)); + int actual_size = ucnv_fromUChars(converter, encoded, + encoded_max_length, reinterpret_cast<const UChar*>(utf16), utf16_len, + &status); + ucnv_close(converter); + if (!U_SUCCESS(status)) { + free(encoded); + return NULL; + } + encoded[actual_size] = 0; + *output_length = actual_size; + return encoded; +} + +uint16_t* CharSetToUTF16(const char* input, uint32_t input_len, + const char* input_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length) { + *output_length = 0; + + base::OnStringConversionError::Type base_on_error; + if (!PPToBaseConversionError(on_error, &base_on_error)) + return NULL; // Invalid enum value. + + // We can convert this call to the implementation in base to avoid code + // duplication, although this does introduce an extra copy of the data. + string16 output; + if (!base::CodepageToUTF16(std::string(input, input_len), input_char_set, + base_on_error, &output)) + return NULL; + + uint16_t* ret_buf = static_cast<uint16_t*>( + malloc((output.size() + 1) * sizeof(uint16_t))); + if (!ret_buf) + return NULL; + + *output_length = static_cast<uint32_t>(output.size()); + memcpy(ret_buf, output.c_str(), (output.size() + 1) * sizeof(uint16_t)); + return ret_buf; +} + +PP_Var GetDefaultCharSet(PP_Module pp_module) { + PluginModule* module = ResourceTracker::Get()->GetModule(pp_module); + if (!module) + return PP_MakeUndefined(); + + std::string encoding = + module->GetSomeInstance()->delegate()->GetDefaultEncoding(); + return StringVar::StringToPPVar(module, encoding); +} + +const PPB_CharSet_Dev ppb_charset = { + &UTF16ToCharSet, + &CharSetToUTF16, + &GetDefaultCharSet +}; + +} // namespace + +// static +const struct PPB_CharSet_Dev* PPB_CharSet_Impl::GetInterface() { + return &ppb_charset; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_char_set_impl.h b/webkit/plugins/ppapi/ppb_char_set_impl.h new file mode 100644 index 0000000..9c16e05 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_char_set_impl.h @@ -0,0 +1,23 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_CHAR_SET_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_CHAR_SET_IMPL_H_ + +struct PPB_CharSet_Dev; + +namespace webkit { +namespace ppapi { + +class PPB_CharSet_Impl { + public: + // Returns a pointer to the interface implementing PPB_CharSet that is + // exposed to the plugin. + static const PPB_CharSet_Dev* GetInterface(); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_CHAR_SET_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_cursor_control_impl.cc b/webkit/plugins/ppapi/ppb_cursor_control_impl.cc new file mode 100644 index 0000000..d7b5119 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_cursor_control_impl.cc @@ -0,0 +1,94 @@ +// 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 "webkit/plugins/ppapi/ppb_cursor_control_impl.h" + +#include "base/logging.h" +#include "base/ref_counted.h" +#include "ppapi/c/dev/pp_cursor_type_dev.h" +#include "ppapi/c/dev/ppb_cursor_control_dev.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_resource.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Bool SetCursor(PP_Instance instance_id, + PP_CursorType_Dev type, + PP_Resource custom_image_id, + const PP_Point* hot_spot) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + + scoped_refptr<PPB_ImageData_Impl> custom_image( + Resource::GetAs<PPB_ImageData_Impl>(custom_image_id)); + if (custom_image.get()) { + // TODO(neb): implement custom cursors. + NOTIMPLEMENTED(); + return PP_FALSE; + } + + return BoolToPPBool(instance->SetCursor(type)); +} + +PP_Bool LockCursor(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + + // TODO(neb): implement cursor locking. + return PP_FALSE; +} + +PP_Bool UnlockCursor(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + + // TODO(neb): implement cursor locking. + return PP_FALSE; +} + +PP_Bool HasCursorLock(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + + // TODO(neb): implement cursor locking. + return PP_FALSE; +} + +PP_Bool CanLockCursor(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_FALSE; + + // TODO(neb): implement cursor locking. + return PP_FALSE; +} + +const PPB_CursorControl_Dev cursor_control_interface = { + &SetCursor, + &LockCursor, + &UnlockCursor, + &HasCursorLock, + &CanLockCursor +}; + +} // namespace + +const PPB_CursorControl_Dev* GetCursorControlInterface() { + return &cursor_control_interface; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_cursor_control_impl.h b/webkit/plugins/ppapi/ppb_cursor_control_impl.h new file mode 100644 index 0000000..dcce132a --- /dev/null +++ b/webkit/plugins/ppapi/ppb_cursor_control_impl.h @@ -0,0 +1,21 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_CURSOR_CONTROL_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_CURSOR_CONTROL_IMPL_H_ + +struct PPB_CursorControl_Dev; + +namespace webkit { +namespace ppapi { + +// There's no class implementing CursorControl so we just expose a getter for +// the interface implemented in the .cc file here. +const PPB_CursorControl_Dev* GetCursorControlInterface(); + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_CURSOR_CONTROL_IMPL_H_ + diff --git a/webkit/plugins/ppapi/ppb_directory_reader_impl.cc b/webkit/plugins/ppapi/ppb_directory_reader_impl.cc new file mode 100644 index 0000000..1f5c97c --- /dev/null +++ b/webkit/plugins/ppapi/ppb_directory_reader_impl.cc @@ -0,0 +1,167 @@ +// 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 "webkit/plugins/ppapi/ppb_directory_reader_impl.h" + +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/dev/ppb_directory_reader_dev.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/file_callbacks.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" +#include "webkit/plugins/ppapi/ppb_file_system_impl.h" +#include "webkit/plugins/ppapi/resource_tracker.h" + +namespace webkit { +namespace ppapi { + +namespace { + +std::string FilePathStringToUTF8String(const FilePath::StringType& str) { +#if defined(OS_WIN) + return WideToUTF8(str); +#elif defined(OS_POSIX) + return str; +#else +#error "Unsupported platform." +#endif +} + +FilePath::StringType UTF8StringToFilePathString(const std::string& str) { +#if defined(OS_WIN) + return UTF8ToWide(str); +#elif defined(OS_POSIX) + return str; +#else +#error "Unsupported platform." +#endif +} + +PP_Resource Create(PP_Resource directory_ref_id) { + scoped_refptr<PPB_FileRef_Impl> directory_ref( + Resource::GetAs<PPB_FileRef_Impl>(directory_ref_id)); + if (!directory_ref) + return 0; + + PPB_DirectoryReader_Impl* reader = new PPB_DirectoryReader_Impl(directory_ref); + return reader->GetReference(); +} + +PP_Bool IsDirectoryReader(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_DirectoryReader_Impl>(resource)); +} + +int32_t GetNextEntry(PP_Resource reader_id, + PP_DirectoryEntry_Dev* entry, + PP_CompletionCallback callback) { + scoped_refptr<PPB_DirectoryReader_Impl> reader( + Resource::GetAs<PPB_DirectoryReader_Impl>(reader_id)); + if (!reader) + return PP_ERROR_BADRESOURCE; + + return reader->GetNextEntry(entry, callback); +} + +const PPB_DirectoryReader_Dev ppb_directoryreader = { + &Create, + &IsDirectoryReader, + &GetNextEntry +}; + +} // namespace + +PPB_DirectoryReader_Impl::PPB_DirectoryReader_Impl( + PPB_FileRef_Impl* directory_ref) + : Resource(directory_ref->module()), + directory_ref_(directory_ref), + has_more_(true), + entry_(NULL) { +} + +PPB_DirectoryReader_Impl::~PPB_DirectoryReader_Impl() { +} + +const PPB_DirectoryReader_Dev* PPB_DirectoryReader_Impl::GetInterface() { + return &ppb_directoryreader; +} + +PPB_DirectoryReader_Impl* +PPB_DirectoryReader_Impl::AsPPB_DirectoryReader_Impl() { + return this; +} + +int32_t PPB_DirectoryReader_Impl::GetNextEntry( + PP_DirectoryEntry_Dev* entry, + PP_CompletionCallback callback) { + if (directory_ref_->GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL) + return PP_ERROR_FAILED; + + entry_ = entry; + if (FillUpEntry()) { + entry_ = NULL; + return PP_OK; + } + + PluginInstance* instance = directory_ref_->GetFileSystem()->instance(); + if (!instance->delegate()->ReadDirectory( + directory_ref_->GetSystemPath(), + new FileCallbacks(instance->module()->AsWeakPtr(), + callback, NULL, NULL, this))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +void PPB_DirectoryReader_Impl::AddNewEntries( + const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more) { + DCHECK(!entries.empty()); + has_more_ = has_more; + std::string dir_path = directory_ref_->GetPath(); + if (dir_path[dir_path.size() - 1] != '/') + dir_path += '/'; + FilePath::StringType dir_file_path = UTF8StringToFilePathString(dir_path); + for (std::vector<base::FileUtilProxy::Entry>::const_iterator it = + entries.begin(); it != entries.end(); it++) { + base::FileUtilProxy::Entry entry; + entry.name = dir_file_path + it->name; + entry.is_directory = it->is_directory; + entries_.push(entry); + } + + FillUpEntry(); + entry_ = NULL; +} + +bool PPB_DirectoryReader_Impl::FillUpEntry() { + DCHECK(entry_); + if (!entries_.empty()) { + base::FileUtilProxy::Entry dir_entry = entries_.front(); + entries_.pop(); + if (entry_->file_ref) + ResourceTracker::Get()->UnrefResource(entry_->file_ref); + PPB_FileRef_Impl* file_ref = + new PPB_FileRef_Impl(module(), directory_ref_->GetFileSystem(), + FilePathStringToUTF8String(dir_entry.name)); + entry_->file_ref = file_ref->GetReference(); + entry_->file_type = + (dir_entry.is_directory ? PP_FILETYPE_DIRECTORY : PP_FILETYPE_REGULAR); + return true; + } + + if (!has_more_) { + entry_->file_ref = 0; + return true; + } + + return false; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_directory_reader_impl.h b/webkit/plugins/ppapi/ppb_directory_reader_impl.h new file mode 100644 index 0000000..6e6dfdf --- /dev/null +++ b/webkit/plugins/ppapi/ppb_directory_reader_impl.h @@ -0,0 +1,53 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_DIRECTORY_READER_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_DIRECTORY_READER_IMPL_H_ + +#include <queue> + +#include "base/file_util_proxy.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PP_CompletionCallback; +struct PP_DirectoryEntry_Dev; +struct PPB_DirectoryReader_Dev; + +namespace webkit { +namespace ppapi { + +class PPB_FileRef_Impl; + +class PPB_DirectoryReader_Impl : public Resource { + public: + explicit PPB_DirectoryReader_Impl(PPB_FileRef_Impl* directory_ref); + virtual ~PPB_DirectoryReader_Impl(); + + // Returns a pointer to the interface implementing PPB_DirectoryReader that + // is exposed to the plugin. + static const PPB_DirectoryReader_Dev* GetInterface(); + + // Resource overrides. + virtual PPB_DirectoryReader_Impl* AsPPB_DirectoryReader_Impl(); + + // PPB_DirectoryReader implementation. + int32_t GetNextEntry(PP_DirectoryEntry_Dev* entry, + PP_CompletionCallback callback); + + void AddNewEntries(const std::vector<base::FileUtilProxy::Entry>& entries, + bool has_more); + + private: + bool FillUpEntry(); + + scoped_refptr<PPB_FileRef_Impl> directory_ref_; + std::queue<base::FileUtilProxy::Entry> entries_; + bool has_more_; + PP_DirectoryEntry_Dev* entry_; +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_DIRECTORY_READER_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_file_chooser_impl.cc b/webkit/plugins/ppapi/ppb_file_chooser_impl.cc new file mode 100644 index 0000000..b8e4a79 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_file_chooser_impl.cc @@ -0,0 +1,169 @@ +// 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 "webkit/plugins/ppapi/ppb_file_chooser_impl.h" + +#include <string> +#include <vector> + +#include "base/logging.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFileChooserCompletion.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFileChooserParams.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebVector.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/resource_tracker.h" +#include "webkit/glue/webkit_glue.h" + +using WebKit::WebCString; +using WebKit::WebFileChooserCompletion; +using WebKit::WebFileChooserParams; +using WebKit::WebString; +using WebKit::WebVector; + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Resource Create(PP_Instance instance_id, + const PP_FileChooserOptions_Dev* options) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return 0; + + if ((options->mode != PP_FILECHOOSERMODE_OPEN) && + (options->mode != PP_FILECHOOSERMODE_OPENMULTIPLE)) + return 0; + + PPB_FileChooser_Impl* chooser = new PPB_FileChooser_Impl(instance, options); + return chooser->GetReference(); +} + +PP_Bool IsFileChooser(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_FileChooser_Impl>(resource)); +} + +int32_t Show(PP_Resource chooser_id, PP_CompletionCallback callback) { + scoped_refptr<PPB_FileChooser_Impl> chooser( + Resource::GetAs<PPB_FileChooser_Impl>(chooser_id)); + if (!chooser) + return PP_ERROR_BADRESOURCE; + + return chooser->Show(callback); +} + +PP_Resource GetNextChosenFile(PP_Resource chooser_id) { + scoped_refptr<PPB_FileChooser_Impl> chooser( + Resource::GetAs<PPB_FileChooser_Impl>(chooser_id)); + if (!chooser) + return 0; + + scoped_refptr<PPB_FileRef_Impl> file_ref(chooser->GetNextChosenFile()); + if (!file_ref) + return 0; + + return file_ref->GetReference(); +} + +const PPB_FileChooser_Dev ppb_filechooser = { + &Create, + &IsFileChooser, + &Show, + &GetNextChosenFile +}; + +class FileChooserCompletionImpl : public WebFileChooserCompletion { + public: + FileChooserCompletionImpl(PPB_FileChooser_Impl* file_chooser) + : file_chooser_(file_chooser) { + DCHECK(file_chooser_); + } + + virtual ~FileChooserCompletionImpl() {} + + virtual void didChooseFile(const WebVector<WebString>& file_names) { + std::vector<std::string> files; + for (size_t i = 0; i < file_names.size(); i++) + files.push_back(file_names[i].utf8().data()); + + file_chooser_->StoreChosenFiles(files); + } + + private: + PPB_FileChooser_Impl* file_chooser_; +}; + +} // namespace + +PPB_FileChooser_Impl::PPB_FileChooser_Impl(PluginInstance* instance, + const PP_FileChooserOptions_Dev* options) + : Resource(instance->module()), + delegate_(instance->delegate()), + mode_(options->mode), + accept_mime_types_(options->accept_mime_types), + completion_callback_() { +} + +PPB_FileChooser_Impl::~PPB_FileChooser_Impl() { +} + +// static +const PPB_FileChooser_Dev* PPB_FileChooser_Impl::GetInterface() { + return &ppb_filechooser; +} + +PPB_FileChooser_Impl* PPB_FileChooser_Impl::AsPPB_FileChooser_Impl() { + return this; +} + +void PPB_FileChooser_Impl::StoreChosenFiles( + const std::vector<std::string>& files) { + next_chosen_file_index_ = 0; + std::vector<std::string>::const_iterator end_it = files.end(); + for (std::vector<std::string>::const_iterator it = files.begin(); + it != end_it; it++) { + chosen_files_.push_back(make_scoped_refptr( + new PPB_FileRef_Impl(module(), FilePath().AppendASCII(*it)))); + } + + if (!completion_callback_.func) + return; + + PP_CompletionCallback callback = {0}; + std::swap(callback, completion_callback_); + PP_RunCompletionCallback(&callback, 0); +} + +int32_t PPB_FileChooser_Impl::Show(PP_CompletionCallback callback) { + DCHECK((mode_ == PP_FILECHOOSERMODE_OPEN) || + (mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE)); + DCHECK(!completion_callback_.func); + completion_callback_ = callback; + + WebFileChooserParams params; + params.multiSelect = (mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE); + params.acceptTypes = WebString::fromUTF8(accept_mime_types_); + params.directory = false; + + return delegate_->RunFileChooser( + params, new FileChooserCompletionImpl(this)); +} + +scoped_refptr<PPB_FileRef_Impl> PPB_FileChooser_Impl::GetNextChosenFile() { + if (next_chosen_file_index_ >= chosen_files_.size()) + return NULL; + + return chosen_files_[next_chosen_file_index_++]; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_file_chooser_impl.h b/webkit/plugins/ppapi/ppb_file_chooser_impl.h new file mode 100644 index 0000000..d60b503 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_file_chooser_impl.h @@ -0,0 +1,55 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_FILE_CHOOSER_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_FILE_CHOOSER_IMPL_H_ + +#include <string> +#include <vector> + +#include "base/scoped_ptr.h" +#include "ppapi/c/dev/ppb_file_chooser_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace webkit { +namespace ppapi { + +class PluginDelegate; +class PluginInstance; +class PPB_FileRef_Impl; + +class PPB_FileChooser_Impl : public Resource { + public: + PPB_FileChooser_Impl(PluginInstance* instance, + const PP_FileChooserOptions_Dev* options); + virtual ~PPB_FileChooser_Impl(); + + // Returns a pointer to the interface implementing PPB_FileChooser that is + // exposed to the plugin. + static const PPB_FileChooser_Dev* GetInterface(); + + // Resource overrides. + virtual PPB_FileChooser_Impl* AsPPB_FileChooser_Impl(); + + // Stores the list of selected files. + void StoreChosenFiles(const std::vector<std::string>& files); + + // PPB_FileChooser implementation. + int32_t Show(PP_CompletionCallback callback); + scoped_refptr<PPB_FileRef_Impl> GetNextChosenFile(); + + private: + PluginDelegate* delegate_; + PP_FileChooserMode_Dev mode_; + std::string accept_mime_types_; + PP_CompletionCallback completion_callback_; + std::vector< scoped_refptr<PPB_FileRef_Impl> > chosen_files_; + size_t next_chosen_file_index_; +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_FILE_CHOOSER_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_file_io_impl.cc b/webkit/plugins/ppapi/ppb_file_io_impl.cc new file mode 100644 index 0000000..4597809 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_file_io_impl.cc @@ -0,0 +1,443 @@ +// 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 "webkit/plugins/ppapi/ppb_file_io_impl.h" + +#include "base/callback.h" +#include "base/file_util.h" +#include "base/file_util_proxy.h" +#include "base/message_loop_proxy.h" +#include "base/platform_file.h" +#include "base/logging.h" +#include "base/time.h" +#include "ppapi/c/dev/ppb_file_io_dev.h" +#include "ppapi/c/dev/ppb_file_io_trusted_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" +#include "webkit/plugins/ppapi/resource_tracker.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Resource Create(PP_Module module_id) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + + PPB_FileIO_Impl* file_io = new PPB_FileIO_Impl(module); + return file_io->GetReference(); +} + +PP_Bool IsFileIO(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_FileIO_Impl>(resource)); +} + +int32_t Open(PP_Resource file_io_id, + PP_Resource file_ref_id, + int32_t open_flags, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_ERROR_BADRESOURCE; + + return file_io->Open(file_ref, open_flags, callback); +} + +int32_t Query(PP_Resource file_io_id, + PP_FileInfo_Dev* info, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->Query(info, callback); +} + +int32_t Touch(PP_Resource file_io_id, + PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->Touch(last_access_time, last_modified_time, callback); +} + +int32_t Read(PP_Resource file_io_id, + int64_t offset, + char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->Read(offset, buffer, bytes_to_read, callback); +} + +int32_t Write(PP_Resource file_io_id, + int64_t offset, + const char* buffer, + int32_t bytes_to_write, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->Write(offset, buffer, bytes_to_write, callback); +} + +int32_t SetLength(PP_Resource file_io_id, + int64_t length, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->SetLength(length, callback); +} + +int32_t Flush(PP_Resource file_io_id, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->Flush(callback); +} + +void Close(PP_Resource file_io_id) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return; + file_io->Close(); +} + +const PPB_FileIO_Dev ppb_fileio = { + &Create, + &IsFileIO, + &Open, + &Query, + &Touch, + &Read, + &Write, + &SetLength, + &Flush, + &Close +}; + +int32_t GetOSFileDescriptor(PP_Resource file_io_id) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->GetOSFileDescriptor(); +} + +int32_t WillWrite(PP_Resource file_io_id, + int64_t offset, + int32_t bytes_to_write, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->WillWrite(offset, bytes_to_write, callback); +} + +int32_t WillSetLength(PP_Resource file_io_id, + int64_t length, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileIO_Impl> file_io(Resource::GetAs<PPB_FileIO_Impl>(file_io_id)); + if (!file_io) + return PP_ERROR_BADRESOURCE; + return file_io->WillSetLength(length, callback); +} + +const PPB_FileIOTrusted_Dev ppb_fileiotrusted = { + &GetOSFileDescriptor, + &WillWrite, + &WillSetLength +}; + +int PlatformFileErrorToPepperError(base::PlatformFileError error_code) { + switch (error_code) { + case base::PLATFORM_FILE_OK: + return PP_OK; + case base::PLATFORM_FILE_ERROR_EXISTS: + return PP_ERROR_FILEEXISTS; + case base::PLATFORM_FILE_ERROR_NOT_FOUND: + return PP_ERROR_FILENOTFOUND; + case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: + return PP_ERROR_NOACCESS; + case base::PLATFORM_FILE_ERROR_NO_MEMORY: + return PP_ERROR_NOMEMORY; + case base::PLATFORM_FILE_ERROR_NO_SPACE: + return PP_ERROR_NOSPACE; + case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY: + NOTREACHED(); + return PP_ERROR_FAILED; + default: + return PP_ERROR_FAILED; + } +} + +} // namespace + +PPB_FileIO_Impl::PPB_FileIO_Impl(PluginModule* module) + : Resource(module), + delegate_(module->GetSomeInstance()->delegate()), + ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)), + file_(base::kInvalidPlatformFileValue), + callback_(), + info_(NULL) { +} + +PPB_FileIO_Impl::~PPB_FileIO_Impl() { + Close(); +} + +// static +const PPB_FileIO_Dev* PPB_FileIO_Impl::GetInterface() { + return &ppb_fileio; +} + +// static +const PPB_FileIOTrusted_Dev* PPB_FileIO_Impl::GetTrustedInterface() { + return &ppb_fileiotrusted; +} + +PPB_FileIO_Impl* PPB_FileIO_Impl::AsPPB_FileIO_Impl() { + return this; +} + +int32_t PPB_FileIO_Impl::Open(PPB_FileRef_Impl* file_ref, + int32_t open_flags, + PP_CompletionCallback callback) { + if (file_ != base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + DCHECK(!callback_.func); + callback_ = callback; + + int flags = 0; + if (open_flags & PP_FILEOPENFLAG_READ) + flags |= base::PLATFORM_FILE_READ; + if (open_flags & PP_FILEOPENFLAG_WRITE) { + flags |= base::PLATFORM_FILE_WRITE; + flags |= base::PLATFORM_FILE_WRITE_ATTRIBUTES; + } + + if (open_flags & PP_FILEOPENFLAG_TRUNCATE) { + DCHECK(open_flags & PP_FILEOPENFLAG_WRITE); + flags |= base::PLATFORM_FILE_TRUNCATE; + } else if (open_flags & PP_FILEOPENFLAG_CREATE) { + if (open_flags & PP_FILEOPENFLAG_EXCLUSIVE) + flags |= base::PLATFORM_FILE_CREATE; + else + flags |= base::PLATFORM_FILE_OPEN_ALWAYS; + } else + flags |= base::PLATFORM_FILE_OPEN; + + file_system_type_ = file_ref->GetFileSystemType(); + if (!delegate_->AsyncOpenFile( + file_ref->GetSystemPath(), flags, + callback_factory_.NewCallback(&PPB_FileIO_Impl::AsyncOpenFileCallback))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_FileIO_Impl::Query(PP_FileInfo_Dev* info, + PP_CompletionCallback callback) { + if (file_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + DCHECK(!callback_.func); + callback_ = callback; + + DCHECK(!info_); + DCHECK(info); + info_ = info; + + if (!base::FileUtilProxy::GetFileInfoFromPlatformFile( + delegate_->GetFileThreadMessageLoopProxy(), file_, + callback_factory_.NewCallback(&PPB_FileIO_Impl::QueryInfoCallback))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_FileIO_Impl::Touch(PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback) { + if (file_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + DCHECK(!callback_.func); + callback_ = callback; + + if (!base::FileUtilProxy::Touch( + delegate_->GetFileThreadMessageLoopProxy(), + file_, base::Time::FromDoubleT(last_access_time), + base::Time::FromDoubleT(last_modified_time), + callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_FileIO_Impl::Read(int64_t offset, + char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) { + if (file_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + DCHECK(!callback_.func); + callback_ = callback; + + if (!base::FileUtilProxy::Read( + delegate_->GetFileThreadMessageLoopProxy(), + file_, offset, buffer, bytes_to_read, + callback_factory_.NewCallback(&PPB_FileIO_Impl::ReadWriteCallback))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_FileIO_Impl::Write(int64_t offset, + const char* buffer, + int32_t bytes_to_write, + PP_CompletionCallback callback) { + if (file_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + DCHECK(!callback_.func); + callback_ = callback; + + if (!base::FileUtilProxy::Write( + delegate_->GetFileThreadMessageLoopProxy(), + file_, offset, buffer, bytes_to_write, + callback_factory_.NewCallback(&PPB_FileIO_Impl::ReadWriteCallback))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_FileIO_Impl::SetLength(int64_t length, + PP_CompletionCallback callback) { + if (file_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + DCHECK(!callback_.func); + callback_ = callback; + + if (!base::FileUtilProxy::Truncate( + delegate_->GetFileThreadMessageLoopProxy(), + file_, length, + callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_FileIO_Impl::Flush(PP_CompletionCallback callback) { + if (file_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + DCHECK(!callback_.func); + callback_ = callback; + + if (!base::FileUtilProxy::Flush( + delegate_->GetFileThreadMessageLoopProxy(), file_, + callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +void PPB_FileIO_Impl::Close() { + if (file_ != base::kInvalidPlatformFileValue) + base::FileUtilProxy::Close( + delegate_->GetFileThreadMessageLoopProxy(), file_, NULL); +} + +int32_t PPB_FileIO_Impl::GetOSFileDescriptor() { +#if defined(OS_POSIX) + return file_; +#elif defined(OS_WIN) + return reinterpret_cast<uintptr_t>(file_); +#else +#error "Platform not supported." +#endif +} + +int32_t PPB_FileIO_Impl::WillWrite(int64_t offset, + int32_t bytes_to_write, + PP_CompletionCallback callback) { + // TODO(dumi): implement me + return PP_OK; +} + +int32_t PPB_FileIO_Impl::WillSetLength(int64_t length, + PP_CompletionCallback callback) { + // TODO(dumi): implement me + return PP_OK; +} + +void PPB_FileIO_Impl::RunPendingCallback(int result) { + if (!callback_.func) + return; + + PP_CompletionCallback callback = {0}; + std::swap(callback, callback_); + PP_RunCompletionCallback(&callback, result); +} + +void PPB_FileIO_Impl::StatusCallback(base::PlatformFileError error_code) { + RunPendingCallback(PlatformFileErrorToPepperError(error_code)); +} + +void PPB_FileIO_Impl::AsyncOpenFileCallback( + base::PlatformFileError error_code, + base::PlatformFile file) { + DCHECK(file_ == base::kInvalidPlatformFileValue); + file_ = file; + RunPendingCallback(PlatformFileErrorToPepperError(error_code)); +} + +void PPB_FileIO_Impl::QueryInfoCallback( + base::PlatformFileError error_code, + const base::PlatformFileInfo& file_info) { + DCHECK(info_); + if (error_code == base::PLATFORM_FILE_OK) { + info_->size = file_info.size; + info_->creation_time = file_info.creation_time.ToDoubleT(); + info_->last_access_time = file_info.last_accessed.ToDoubleT(); + info_->last_modified_time = file_info.last_modified.ToDoubleT(); + info_->system_type = file_system_type_; + if (file_info.is_directory) + info_->type = PP_FILETYPE_DIRECTORY; + else + info_->type = PP_FILETYPE_REGULAR; + } + RunPendingCallback(PlatformFileErrorToPepperError(error_code)); +} + +void PPB_FileIO_Impl::ReadWriteCallback(base::PlatformFileError error_code, + int bytes_read_or_written) { + if (error_code != base::PLATFORM_FILE_OK) + RunPendingCallback(PlatformFileErrorToPepperError(error_code)); + else + RunPendingCallback(bytes_read_or_written); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_file_io_impl.h b/webkit/plugins/ppapi/ppb_file_io_impl.h new file mode 100644 index 0000000..be3865e --- /dev/null +++ b/webkit/plugins/ppapi/ppb_file_io_impl.h @@ -0,0 +1,100 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_FILE_IO_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_FILE_IO_IMPL_H_ + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/platform_file.h" +#include "base/scoped_callback_factory.h" +#include "base/scoped_ptr.h" +#include "ppapi/c/dev/pp_file_info_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_time.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PP_CompletionCallback; +struct PPB_FileIO_Dev; +struct PPB_FileIOTrusted_Dev; + +namespace webkit { +namespace ppapi { + +class PluginModule; +class PPB_FileRef_Impl; + +class PPB_FileIO_Impl : public Resource { + public: + explicit PPB_FileIO_Impl(PluginModule* module); + virtual ~PPB_FileIO_Impl(); + + // Returns a pointer to the interface implementing PPB_FileIO that is exposed + // to the plugin. + static const PPB_FileIO_Dev* GetInterface(); + + // Returns a pointer to the interface implementing PPB_FileIOTrusted that is + // exposed to the plugin. + static const PPB_FileIOTrusted_Dev* GetTrustedInterface(); + + // Resource overrides. + virtual PPB_FileIO_Impl* AsPPB_FileIO_Impl(); + + // PPB_FileIO implementation. + int32_t Open(PPB_FileRef_Impl* file_ref, + int32_t open_flags, + PP_CompletionCallback callback); + int32_t Query(PP_FileInfo_Dev* info, + PP_CompletionCallback callback); + int32_t Touch(PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback); + int32_t Read(int64_t offset, + char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback); + int32_t Write(int64_t offset, + const char* buffer, + int32_t bytes_to_write, + PP_CompletionCallback callback); + int32_t SetLength(int64_t length, + PP_CompletionCallback callback); + int32_t Flush(PP_CompletionCallback callback); + void Close(); + + // PPB_FileIOTrusted implementation. + int32_t GetOSFileDescriptor(); + int32_t WillWrite(int64_t offset, + int32_t bytes_to_write, + PP_CompletionCallback callback); + int32_t WillSetLength(int64_t length, + PP_CompletionCallback callback); + + void RunPendingCallback(int result); + void StatusCallback(base::PlatformFileError error_code); + void AsyncOpenFileCallback(base::PlatformFileError error_code, + base::PlatformFile file); + void QueryInfoCallback(base::PlatformFileError error_code, + const base::PlatformFileInfo& file_info); + void ReadWriteCallback(base::PlatformFileError error_code, + int bytes_read_or_written); + + private: + PluginDelegate* delegate_; + base::ScopedCallbackFactory<PPB_FileIO_Impl> callback_factory_; + + base::PlatformFile file_; + PP_FileSystemType_Dev file_system_type_; + + PP_CompletionCallback callback_; + PP_FileInfo_Dev* info_; + + DISALLOW_COPY_AND_ASSIGN(PPB_FileIO_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_FILE_IO_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_file_ref_impl.cc b/webkit/plugins/ppapi/ppb_file_ref_impl.cc new file mode 100644 index 0000000..79676df --- /dev/null +++ b/webkit/plugins/ppapi/ppb_file_ref_impl.cc @@ -0,0 +1,359 @@ +// 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 "webkit/plugins/ppapi/ppb_file_ref_impl.h" + +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "ppapi/c/pp_errors.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/file_callbacks.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_directory_reader_impl.h" +#include "webkit/plugins/ppapi/ppb_file_system_impl.h" +#include "webkit/plugins/ppapi/var.h" + +namespace webkit { +namespace ppapi { + +namespace { + +bool IsValidLocalPath(const std::string& path) { + // The path must start with '/' + if (path.empty() || path[0] != '/') + return false; + + // The path must contain valid UTF-8 characters. + if (!IsStringUTF8(path)) + return false; + + return true; +} + +void TrimTrailingSlash(std::string* path) { + // If this path ends with a slash, then normalize it away unless path is the + // root path. + if (path->size() > 1 && path->at(path->size() - 1) == '/') + path->erase(path->size() - 1, 1); +} + +PP_Resource Create(PP_Resource file_system_id, const char* path) { + scoped_refptr<PPB_FileSystem_Impl> file_system( + Resource::GetAs<PPB_FileSystem_Impl>(file_system_id)); + if (!file_system) + return 0; + + if (!file_system->instance()) + return 0; + + std::string validated_path(path); + if (!IsValidLocalPath(validated_path)) + return 0; + TrimTrailingSlash(&validated_path); + + PPB_FileRef_Impl* file_ref = + new PPB_FileRef_Impl(file_system->instance()->module(), + file_system, validated_path); + return file_ref->GetReference(); +} + +PP_Bool IsFileRef(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_FileRef_Impl>(resource)); +} + +PP_FileSystemType_Dev GetFileSystemType(PP_Resource file_ref_id) { + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_FILESYSTEMTYPE_EXTERNAL; + return file_ref->GetFileSystemType(); +} + +PP_Var GetName(PP_Resource file_ref_id) { + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_MakeUndefined(); + return StringVar::StringToPPVar(file_ref->module(), file_ref->GetName()); +} + +PP_Var GetPath(PP_Resource file_ref_id) { + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_MakeUndefined(); + + if (file_ref->GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL) + return PP_MakeUndefined(); + + return StringVar::StringToPPVar(file_ref->module(), file_ref->GetPath()); +} + +PP_Resource GetParent(PP_Resource file_ref_id) { + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return 0; + + if (file_ref->GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL) + return 0; + + scoped_refptr<PPB_FileRef_Impl> parent_ref(file_ref->GetParent()); + if (!parent_ref) + return 0; + + return parent_ref->GetReference(); +} + +int32_t MakeDirectory(PP_Resource directory_ref_id, + PP_Bool make_ancestors, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileRef_Impl> directory_ref( + Resource::GetAs<PPB_FileRef_Impl>(directory_ref_id)); + if (!directory_ref) + return PP_ERROR_BADRESOURCE; + + scoped_refptr<PPB_FileSystem_Impl> file_system = directory_ref->GetFileSystem(); + if (!file_system || !file_system->opened() || + (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL)) + return PP_ERROR_NOACCESS; + + PluginInstance* instance = file_system->instance(); + if (!instance->delegate()->MakeDirectory( + directory_ref->GetSystemPath(), PPBoolToBool(make_ancestors), + new FileCallbacks(instance->module()->AsWeakPtr(), + callback, NULL, NULL, NULL))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t Query(PP_Resource file_ref_id, + PP_FileInfo_Dev* info, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_ERROR_BADRESOURCE; + + scoped_refptr<PPB_FileSystem_Impl> file_system = file_ref->GetFileSystem(); + if (!file_system || !file_system->opened() || + (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL)) + return PP_ERROR_NOACCESS; + + PluginInstance* instance = file_system->instance(); + if (!instance->delegate()->Query( + file_ref->GetSystemPath(), + new FileCallbacks(instance->module()->AsWeakPtr(), + callback, info, file_system, NULL))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t Touch(PP_Resource file_ref_id, + PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_ERROR_BADRESOURCE; + + scoped_refptr<PPB_FileSystem_Impl> file_system = file_ref->GetFileSystem(); + if (!file_system || !file_system->opened() || + (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL)) + return PP_ERROR_NOACCESS; + + PluginInstance* instance = file_system->instance(); + if (!instance->delegate()->Touch( + file_ref->GetSystemPath(), base::Time::FromDoubleT(last_access_time), + base::Time::FromDoubleT(last_modified_time), + new FileCallbacks(instance->module()->AsWeakPtr(), + callback, NULL, NULL, NULL))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t Delete(PP_Resource file_ref_id, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_ERROR_BADRESOURCE; + + scoped_refptr<PPB_FileSystem_Impl> file_system = file_ref->GetFileSystem(); + if (!file_system || !file_system->opened() || + (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL)) + return PP_ERROR_NOACCESS; + + PluginInstance* instance = file_system->instance(); + if (!instance->delegate()->Delete( + file_ref->GetSystemPath(), + new FileCallbacks(instance->module()->AsWeakPtr(), + callback, NULL, NULL, NULL))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +int32_t Rename(PP_Resource file_ref_id, + PP_Resource new_file_ref_id, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_ERROR_BADRESOURCE; + + scoped_refptr<PPB_FileRef_Impl> new_file_ref( + Resource::GetAs<PPB_FileRef_Impl>(new_file_ref_id)); + if (!new_file_ref) + return PP_ERROR_BADRESOURCE; + + scoped_refptr<PPB_FileSystem_Impl> file_system = file_ref->GetFileSystem(); + if (!file_system || !file_system->opened() || + (file_system != new_file_ref->GetFileSystem()) || + (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL)) + return PP_ERROR_NOACCESS; + + PluginInstance* instance = file_system->instance(); + if (!instance->delegate()->Rename( + file_ref->GetSystemPath(), new_file_ref->GetSystemPath(), + new FileCallbacks(instance->module()->AsWeakPtr(), + callback, NULL, NULL, NULL))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +const PPB_FileRef_Dev ppb_fileref = { + &Create, + &IsFileRef, + &GetFileSystemType, + &GetName, + &GetPath, + &GetParent, + &MakeDirectory, + &Query, + &Touch, + &Delete, + &Rename +}; + +} // namespace + +PPB_FileRef_Impl::PPB_FileRef_Impl() + : Resource(NULL), + file_system_(NULL) { +} + +PPB_FileRef_Impl::PPB_FileRef_Impl(PluginModule* module, + scoped_refptr<PPB_FileSystem_Impl> file_system, + const std::string& validated_path) + : Resource(module), + file_system_(file_system), + virtual_path_(validated_path) { +} + +PPB_FileRef_Impl::PPB_FileRef_Impl(PluginModule* module, + const FilePath& external_file_path) + : Resource(module), + file_system_(NULL), + system_path_(external_file_path) { +} + +PPB_FileRef_Impl::~PPB_FileRef_Impl() { +} + +// static +const PPB_FileRef_Dev* PPB_FileRef_Impl::GetInterface() { + return &ppb_fileref; +} + +PPB_FileRef_Impl* PPB_FileRef_Impl::AsPPB_FileRef_Impl() { + return this; +} + +std::string PPB_FileRef_Impl::GetName() const { + if (GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL) { + FilePath::StringType path = system_path_.value(); + size_t pos = path.rfind(FilePath::kSeparators[0]); + DCHECK(pos != FilePath::StringType::npos); +#if defined(OS_WIN) + return WideToUTF8(path.substr(pos + 1)); +#elif defined(OS_POSIX) + return path.substr(pos + 1); +#else +#error "Unsupported platform." +#endif + } + + if (virtual_path_.size() == 1 && virtual_path_[0] == '/') + return virtual_path_; + + // There should always be a leading slash at least! + size_t pos = virtual_path_.rfind('/'); + DCHECK(pos != std::string::npos); + + return virtual_path_.substr(pos + 1); +} + +scoped_refptr<PPB_FileRef_Impl> PPB_FileRef_Impl::GetParent() { + if (GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL) + return new PPB_FileRef_Impl(); + + // There should always be a leading slash at least! + size_t pos = virtual_path_.rfind('/'); + DCHECK(pos != std::string::npos); + + // If the path is "/foo", then we want to include the slash. + if (pos == 0) + pos++; + std::string parent_path = virtual_path_.substr(0, pos); + + PPB_FileRef_Impl* parent_ref = new PPB_FileRef_Impl(module(), file_system_, + parent_path); + return parent_ref; +} + +scoped_refptr<PPB_FileSystem_Impl> PPB_FileRef_Impl::GetFileSystem() const { + return file_system_; +} + +PP_FileSystemType_Dev PPB_FileRef_Impl::GetFileSystemType() const { + if (!file_system_) + return PP_FILESYSTEMTYPE_EXTERNAL; + + return file_system_->type(); +} + +std::string PPB_FileRef_Impl::GetPath() const { + return virtual_path_; +} + +FilePath PPB_FileRef_Impl::GetSystemPath() const { + if (GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL) + return system_path_; + + // Since |virtual_path_| starts with a '/', it is considered an absolute path + // on POSIX systems. We need to remove the '/' before calling Append() or we + // will run into a DCHECK. + FilePath virtual_file_path( +#if defined(OS_WIN) + UTF8ToWide(virtual_path_.substr(1)) +#elif defined(OS_POSIX) + virtual_path_.substr(1) +#else +#error "Unsupported platform." +#endif + ); + return file_system_->root_path().Append(virtual_file_path); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_file_ref_impl.h b/webkit/plugins/ppapi/ppb_file_ref_impl.h new file mode 100644 index 0000000..40924e7 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_file_ref_impl.h @@ -0,0 +1,66 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_FILE_REF_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_FILE_REF_IMPL_H_ + +#include <string> + +#include "base/file_path.h" +#include "ppapi/c/dev/ppb_file_ref_dev.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace webkit { +namespace ppapi { + +class PPB_FileSystem_Impl; +class PluginInstance; +class PluginModule; + +class PPB_FileRef_Impl : public Resource { + public: + PPB_FileRef_Impl(); + PPB_FileRef_Impl(PluginModule* module, + scoped_refptr<PPB_FileSystem_Impl> file_system, + const std::string& validated_path); + PPB_FileRef_Impl(PluginModule* module, + const FilePath& external_file_path); + virtual ~PPB_FileRef_Impl(); + + // Returns a pointer to the interface implementing PPB_FileRef that is + // exposed to the plugin. + static const PPB_FileRef_Dev* GetInterface(); + + // Resource overrides. + virtual PPB_FileRef_Impl* AsPPB_FileRef_Impl(); + + // PPB_FileRef implementation. + std::string GetName() const; + scoped_refptr<PPB_FileRef_Impl> GetParent(); + + // Returns the file system to which this PPB_FileRef_Impl belongs. + scoped_refptr<PPB_FileSystem_Impl> GetFileSystem() const; + + // Returns the type of the file system to which this PPB_FileRef_Impl belongs. + PP_FileSystemType_Dev GetFileSystemType() const; + + // Returns the virtual path (i.e., the path that the pepper plugin sees) + // corresponding to this file. + std::string GetPath() const; + + // Returns the system path corresponding to this file. + FilePath GetSystemPath() const; + + private: + scoped_refptr<PPB_FileSystem_Impl> file_system_; + std::string virtual_path_; // UTF-8 encoded + FilePath system_path_; + + DISALLOW_COPY_AND_ASSIGN(PPB_FileRef_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_FILE_REF_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_file_system_impl.cc b/webkit/plugins/ppapi/ppb_file_system_impl.cc new file mode 100644 index 0000000..fea8327 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_file_system_impl.cc @@ -0,0 +1,94 @@ +// 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 "webkit/plugins/ppapi/ppb_file_system_impl.h" + +#include "base/ref_counted.h" +#include "ppapi/c/dev/ppb_file_system_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebElement.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h" +#include "webkit/fileapi/file_system_types.h" +#include "webkit/plugins/ppapi/file_callbacks.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_directory_reader_impl.h" +#include "webkit/plugins/ppapi/resource.h" +#include "webkit/plugins/ppapi/resource_tracker.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Resource Create(PP_Instance instance, PP_FileSystemType_Dev type) { + PluginInstance* plugin_instance = + ResourceTracker::Get()->GetInstance(instance); + if (!plugin_instance) + return 0; + + PPB_FileSystem_Impl* file_system = + new PPB_FileSystem_Impl(plugin_instance, type); + return file_system->GetReference(); +} + +int32_t Open(PP_Resource file_system_id, + int64 expected_size, + PP_CompletionCallback callback) { + scoped_refptr<PPB_FileSystem_Impl> file_system( + Resource::GetAs<PPB_FileSystem_Impl>(file_system_id)); + if (!file_system) + return PP_ERROR_BADRESOURCE; + + if (file_system->opened()) + return PP_OK; + + if ((file_system->type() != PP_FILESYSTEMTYPE_LOCALPERSISTENT) && + (file_system->type() != PP_FILESYSTEMTYPE_LOCALTEMPORARY)) + return PP_ERROR_FAILED; + + PluginInstance* instance = file_system->instance(); + fileapi::FileSystemType file_system_type = + (file_system->type() == PP_FILESYSTEMTYPE_LOCALTEMPORARY ? + fileapi::kFileSystemTypeTemporary : + fileapi::kFileSystemTypePersistent); + if (!instance->delegate()->OpenFileSystem( + instance->container()->element().document().frame()->url(), + file_system_type, expected_size, + new FileCallbacks(instance->module()->AsWeakPtr(), + callback, NULL, file_system, NULL))) + return PP_ERROR_FAILED; + + return PP_ERROR_WOULDBLOCK; +} + +const PPB_FileSystem_Dev ppb_filesystem = { + &Create, + &Open +}; + +} // namespace + +PPB_FileSystem_Impl::PPB_FileSystem_Impl(PluginInstance* instance, + PP_FileSystemType_Dev type) + : Resource(instance->module()), + instance_(instance), + type_(type), + opened_(false) { +} + +PPB_FileSystem_Impl* PPB_FileSystem_Impl::AsPPB_FileSystem_Impl() { + return this; +} + +const PPB_FileSystem_Dev* PPB_FileSystem_Impl::GetInterface() { + return &ppb_filesystem; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_file_system_impl.h b/webkit/plugins/ppapi/ppb_file_system_impl.h new file mode 100644 index 0000000..2b3e7af --- /dev/null +++ b/webkit/plugins/ppapi/ppb_file_system_impl.h @@ -0,0 +1,48 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_FILE_SYSTEM_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_FILE_SYSTEM_IMPL_H_ + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "ppapi/c/dev/pp_file_info_dev.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PPB_FileSystem_Dev; + +namespace webkit { +namespace ppapi { + +class PluginInstance; + +class PPB_FileSystem_Impl : public Resource { + public: + // Returns a pointer to the interface implementing PPB_FileSystem that is + // exposed to the plugin. + static const PPB_FileSystem_Dev* GetInterface(); + + PPB_FileSystem_Impl(PluginInstance* instance, PP_FileSystemType_Dev type); + virtual PPB_FileSystem_Impl* AsPPB_FileSystem_Impl(); + + PluginInstance* instance() { return instance_; } + PP_FileSystemType_Dev type() { return type_; } + const FilePath& root_path() const { return root_path_; } + void set_root_path(const FilePath& root_path) { root_path_ = root_path; } + bool opened() const { return opened_; } + void set_opened(bool opened) { opened_ = opened; } + + private: + PluginInstance* instance_; + PP_FileSystemType_Dev type_; + FilePath root_path_; + bool opened_; + + DISALLOW_COPY_AND_ASSIGN(PPB_FileSystem_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_FILE_SYSTEM_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_flash.h b/webkit/plugins/ppapi/ppb_flash.h new file mode 100644 index 0000000..607adcd --- /dev/null +++ b/webkit/plugins/ppapi/ppb_flash.h @@ -0,0 +1,117 @@ +// 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 WEBKIT_PLUGINS_PEPPER_PPB_FLASH_H_ +#define WEBKIT_PLUGINS_PEPPER_PPB_FLASH_H_ + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" + +#define PPB_FLASH_INTERFACE "PPB_Flash;1" + +#ifdef _WIN32 +typedef HANDLE PP_FileHandle; +static const PP_FileHandle PP_kInvalidFileHandle = NULL; +#else +typedef int PP_FileHandle; +static const PP_FileHandle PP_kInvalidFileHandle = -1; +#endif + +struct PP_FontDescription_Dev; +struct PP_FileInfo_Dev; + +struct PP_DirEntry_Dev { + const char* name; + bool is_dir; +}; + +struct PP_DirContents_Dev { + int32_t count; + PP_DirEntry_Dev* entries; +}; + +struct PPB_Flash { + // Sets or clears the rendering hint that the given plugin instance is always + // on top of page content. Somewhat more optimized painting can be used in + // this case. + void (*SetInstanceAlwaysOnTop)(PP_Instance instance, bool on_top); + + bool (*DrawGlyphs)(PP_Resource pp_image_data, + const PP_FontDescription_Dev* font_desc, + uint32_t color, + PP_Point position, + PP_Rect clip, + const float transformation[3][3], + uint32_t glyph_count, + const uint16_t glyph_indices[], + const PP_Point glyph_advances[]); + + // Retrieves the proxy that will be used for the given URL. The result will + // be a string in PAC format, or an undefined var on error. + PP_Var (*GetProxyForURL)(PP_Module module, const char* url); + + // Opens a module-local file, returning a file descriptor (posix) or a HANDLE + // (win32) into file. Module-local file paths (here and below) are + // '/'-separated UTF-8 strings, relative to a module-specific root. The return + // value is the ppapi error, PP_OK if success, one of the PP_ERROR_* in case + // of failure. + int32_t (*OpenModuleLocalFile)(PP_Module module, + const char* path, + int32_t mode, + PP_FileHandle* file); + + // Renames a module-local file. The return value is the ppapi error, PP_OK if + // success, one of the PP_ERROR_* in case of failure. + int32_t (*RenameModuleLocalFile)(PP_Module module, + const char* path_from, + const char* path_to); + + // Deletes a module-local file or directory. If recursive is set and the path + // points to a directory, deletes all the contents of the directory. The + // return value is the ppapi error, PP_OK if success, one of the PP_ERROR_* in + // case of failure. + int32_t (*DeleteModuleLocalFileOrDir)(PP_Module module, + const char* path, + bool recursive); + + // Creates a module-local directory. The return value is the ppapi error, + // PP_OK if success, one of the PP_ERROR_* in case of failure. + int32_t (*CreateModuleLocalDir)(PP_Module module, const char* path); + + // Queries information about a module-local file. The return value is the + // ppapi error, PP_OK if success, one of the PP_ERROR_* in case of failure. + int32_t (*QueryModuleLocalFile)(PP_Module module, + const char* path, + PP_FileInfo_Dev* info); + + // Gets the list of files contained in a module-local directory. The return + // value is the ppapi error, PP_OK if success, one of the PP_ERROR_* in case + // of failure. If non-NULL, the returned contents should be freed with + // FreeModuleLocalDirContents. + int32_t (*GetModuleLocalDirContents)(PP_Module module, + const char* path, + PP_DirContents_Dev** contents); + + // Frees the data allocated by GetModuleLocalDirContents. + void (*FreeModuleLocalDirContents)(PP_Module module, + PP_DirContents_Dev* contents); + + // Navigate to URL. May open a new tab if target is not "_self". Return true + // if success. This differs from javascript:window.open() in that it bypasses + // the popup blocker, even when this is not called from an event handler. + bool (*NavigateToURL)(PP_Instance instance, + const char* url, + const char* target); +}; + +#endif // WEBKIT_GLUE_PLUGINS_PPB_FLASH_H_ diff --git a/webkit/plugins/ppapi/ppb_flash_impl.cc b/webkit/plugins/ppapi/ppb_flash_impl.cc new file mode 100644 index 0000000..b6340df --- /dev/null +++ b/webkit/plugins/ppapi/ppb_flash_impl.cc @@ -0,0 +1,246 @@ +// 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 "webkit/plugins/ppapi/ppb_flash_impl.h" + +#include <string.h> + +#include "base/file_path.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "googleurl/src/gurl.h" +#include "ppapi/c/dev/pp_file_info_dev.h" +#include "ppapi/c/dev/ppb_file_io_dev.h" +#include "webkit/plugins/ppapi/error_util.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_flash.h" +#include "webkit/plugins/ppapi/var.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PluginInstance* GetSomeInstance(PP_Module pp_module) { + PluginModule* module = ResourceTracker::Get()->GetModule(pp_module); + if (!module) + return NULL; + + return module->GetSomeInstance(); +} + +void SetInstanceAlwaysOnTop(PP_Instance pp_instance, bool on_top) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(pp_instance); + if (!instance) + return; + instance->set_always_on_top(on_top); +} + +PP_Var GetProxyForURL(PP_Module pp_module, const char* url) { + PluginInstance* instance = GetSomeInstance(pp_module); + if (!instance) + return PP_MakeUndefined(); + + GURL gurl(url); + if (!gurl.is_valid()) + return PP_MakeUndefined(); + + std::string proxy_host = instance->delegate()->ResolveProxy(gurl); + if (proxy_host.empty()) + return PP_MakeUndefined(); // No proxy. + return StringVar::StringToPPVar(instance->module(), proxy_host); +} + +FilePath GetFilePathFromUTF8(const char* path) { +#if defined(OS_WIN) + return FilePath(UTF8ToUTF16(path)); +#else + return FilePath(path); +#endif +} + +int32_t OpenModuleLocalFile(PP_Module module, + const char* path, + int32_t mode, + PP_FileHandle* file) { + PluginInstance* instance = GetSomeInstance(module); + if (!instance) + return PP_ERROR_FAILED; + + int flags = 0; + if (mode & PP_FILEOPENFLAG_READ) + flags |= base::PLATFORM_FILE_READ; + if (mode & PP_FILEOPENFLAG_WRITE) { + flags |= base::PLATFORM_FILE_WRITE; + flags |= base::PLATFORM_FILE_WRITE_ATTRIBUTES; + } + if (mode & PP_FILEOPENFLAG_TRUNCATE) { + DCHECK(mode & PP_FILEOPENFLAG_WRITE); + flags |= base::PLATFORM_FILE_TRUNCATE; + } + + if (mode & PP_FILEOPENFLAG_CREATE) { + if (mode & PP_FILEOPENFLAG_EXCLUSIVE) + flags |= base::PLATFORM_FILE_CREATE; + else + flags |= base::PLATFORM_FILE_OPEN_ALWAYS; + } else { + flags |= base::PLATFORM_FILE_OPEN; + } + + base::PlatformFile base_file; + base::PlatformFileError result = instance->delegate()->OpenModuleLocalFile( + instance->module()->name(), + GetFilePathFromUTF8(path), + flags, + &base_file); + *file = base_file; + return PlatformFileErrorToPepperError(result); +} + + +int32_t RenameModuleLocalFile(PP_Module module, + const char* path_from, + const char* path_to) { + PluginInstance* instance = GetSomeInstance(module); + if (!instance) + return PP_ERROR_FAILED; + + base::PlatformFileError result = instance->delegate()->RenameModuleLocalFile( + instance->module()->name(), + GetFilePathFromUTF8(path_from), + GetFilePathFromUTF8(path_to)); + return PlatformFileErrorToPepperError(result); +} + +int32_t DeleteModuleLocalFileOrDir(PP_Module module, + const char* path, + bool recursive) { + PluginInstance* instance = GetSomeInstance(module); + if (!instance) + return PP_ERROR_FAILED; + + base::PlatformFileError result = + instance->delegate()->DeleteModuleLocalFileOrDir( + instance->module()->name(), GetFilePathFromUTF8(path), recursive); + return PlatformFileErrorToPepperError(result); +} + +int32_t CreateModuleLocalDir(PP_Module module, const char* path) { + PluginInstance* instance = GetSomeInstance(module); + if (!instance) + return PP_ERROR_FAILED; + + base::PlatformFileError result = instance->delegate()->CreateModuleLocalDir( + instance->module()->name(), GetFilePathFromUTF8(path)); + return PlatformFileErrorToPepperError(result); +} + +int32_t QueryModuleLocalFile(PP_Module module, + const char* path, + PP_FileInfo_Dev* info) { + PluginInstance* instance = GetSomeInstance(module); + if (!instance) + return PP_ERROR_FAILED; + + base::PlatformFileInfo file_info; + base::PlatformFileError result = instance->delegate()->QueryModuleLocalFile( + instance->module()->name(), GetFilePathFromUTF8(path), &file_info); + if (result == base::PLATFORM_FILE_OK) { + info->size = file_info.size; + info->creation_time = file_info.creation_time.ToDoubleT(); + info->last_access_time = file_info.last_accessed.ToDoubleT(); + info->last_modified_time = file_info.last_modified.ToDoubleT(); + info->system_type = PP_FILESYSTEMTYPE_EXTERNAL; + if (file_info.is_directory) + info->type = PP_FILETYPE_DIRECTORY; + else + info->type = PP_FILETYPE_REGULAR; + } + return PlatformFileErrorToPepperError(result); +} + +int32_t GetModuleLocalDirContents(PP_Module module, + const char* path, + PP_DirContents_Dev** contents) { + PluginInstance* instance = GetSomeInstance(module); + if (!instance) + return PP_ERROR_FAILED; + + *contents = NULL; + DirContents pepper_contents; + base::PlatformFileError result = + instance->delegate()->GetModuleLocalDirContents( + instance->module()->name(), + GetFilePathFromUTF8(path), + &pepper_contents); + + if (result != base::PLATFORM_FILE_OK) + return PlatformFileErrorToPepperError(result); + + *contents = new PP_DirContents_Dev; + size_t count = pepper_contents.size(); + (*contents)->count = count; + (*contents)->entries = new PP_DirEntry_Dev[count]; + for (size_t i = 0; i < count; ++i) { + PP_DirEntry_Dev& entry = (*contents)->entries[i]; +#if defined(OS_WIN) + const std::string& name = UTF16ToUTF8(pepper_contents[i].name.value()); +#else + const std::string& name = pepper_contents[i].name.value(); +#endif + size_t size = name.size() + 1; + char* name_copy = new char[size]; + memcpy(name_copy, name.c_str(), size); + entry.name = name_copy; + entry.is_dir = pepper_contents[i].is_dir; + } + return PP_OK; +} + +void FreeModuleLocalDirContents(PP_Module module, + PP_DirContents_Dev* contents) { + DCHECK(contents); + for (int32_t i = 0; i < contents->count; ++i) { + delete [] contents->entries[i].name; + } + delete [] contents->entries; + delete contents; +} + +bool NavigateToURL(PP_Instance pp_instance, + const char* url, + const char* target) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(pp_instance); + if (!instance) + return false; + return instance->NavigateToURL(url, target); +} + +const PPB_Flash ppb_flash = { + &SetInstanceAlwaysOnTop, + &PPB_Flash_Impl::DrawGlyphs, + &GetProxyForURL, + &OpenModuleLocalFile, + &RenameModuleLocalFile, + &DeleteModuleLocalFileOrDir, + &CreateModuleLocalDir, + &QueryModuleLocalFile, + &GetModuleLocalDirContents, + &FreeModuleLocalDirContents, + &NavigateToURL, +}; + +} // namespace + +// static +const PPB_Flash* PPB_Flash_Impl::GetInterface() { + return &ppb_flash; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_flash_impl.h b/webkit/plugins/ppapi/ppb_flash_impl.h new file mode 100644 index 0000000..44ed224 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_flash_impl.h @@ -0,0 +1,48 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_FLASH_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_FLASH_IMPL_H_ + +#include "base/basictypes.h" +#include "build/build_config.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_rect.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PP_FontDescription_Dev; +struct PPB_Flash; + +namespace webkit { +namespace ppapi { + +class PPB_Flash_Impl { + public: + // Returns a pointer to the interface implementing PPB_Flash that is + // exposed to the plugin. + static const PPB_Flash* GetInterface(); + + static bool DrawGlyphs(PP_Resource pp_image_data, + const PP_FontDescription_Dev* font_desc, + uint32_t color, + PP_Point position, + PP_Rect clip, + const float transformation[3][3], + uint32_t glyph_count, + const uint16_t glyph_indices[], + const PP_Point glyph_advances[]) +#if defined(OS_LINUX) + ; +#else + { return false; } +#endif + + private: + DISALLOW_COPY_AND_ASSIGN(PPB_Flash_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_FLASH_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_flash_impl_linux.cc b/webkit/plugins/ppapi/ppb_flash_impl_linux.cc new file mode 100644 index 0000000..23290eb --- /dev/null +++ b/webkit/plugins/ppapi/ppb_flash_impl_linux.cc @@ -0,0 +1,112 @@ +// 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 "webkit/plugins/ppapi/ppb_flash_impl.h" + +#include "skia/ext/platform_canvas.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/dev/ppb_font_dev.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPoint.h" +#include "third_party/skia/include/core/SkTemplates.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" +#include "webkit/plugins/ppapi/var.h" + +namespace webkit { +namespace ppapi { + +bool PPB_Flash_Impl::DrawGlyphs(PP_Resource pp_image_data, + const PP_FontDescription_Dev* font_desc, + uint32_t color, + PP_Point position, + PP_Rect clip, + const float transformation[3][3], + uint32_t glyph_count, + const uint16_t glyph_indices[], + const PP_Point glyph_advances[]) { + scoped_refptr<PPB_ImageData_Impl> image_resource( + Resource::GetAs<PPB_ImageData_Impl>(pp_image_data)); + if (!image_resource.get()) + return false; + ImageDataAutoMapper mapper(image_resource); + if (!mapper.is_valid()) + return false; + + // Set up the typeface. + scoped_refptr<StringVar> face_name(StringVar::FromPPVar(font_desc->face)); + if (!face_name) + return false; + int style = SkTypeface::kNormal; + if (font_desc->weight >= PP_FONTWEIGHT_BOLD) + style |= SkTypeface::kBold; + if (font_desc->italic) + style |= SkTypeface::kItalic; + SkTypeface* typeface = + SkTypeface::CreateFromName(face_name->value().c_str(), + static_cast<SkTypeface::Style>(style)); + if (!typeface) + return false; + + // Set up the canvas. + SkCanvas* canvas = image_resource->mapped_canvas(); + canvas->save(); + + // Clip is applied in pixels before the transform. + SkRect clip_rect = { clip.point.x, clip.point.y, + clip.point.x + clip.size.width, + clip.point.y + clip.size.height }; + canvas->clipRect(clip_rect); + + // -- Do not return early below this. The canvas needs restoring and the + // typeface will leak if it's not assigned to the paint (it's refcounted and + // the refcount is currently 0). + + // Convert & set the matrix. + SkMatrix matrix; + matrix.set(SkMatrix::kMScaleX, SkFloatToScalar(transformation[0][0])); + matrix.set(SkMatrix::kMSkewX, SkFloatToScalar(transformation[0][1])); + matrix.set(SkMatrix::kMTransX, SkFloatToScalar(transformation[0][2])); + matrix.set(SkMatrix::kMSkewY, SkFloatToScalar(transformation[1][0])); + matrix.set(SkMatrix::kMScaleY, SkFloatToScalar(transformation[1][1])); + matrix.set(SkMatrix::kMTransY, SkFloatToScalar(transformation[1][2])); + matrix.set(SkMatrix::kMPersp0, SkFloatToScalar(transformation[2][0])); + matrix.set(SkMatrix::kMPersp1, SkFloatToScalar(transformation[2][1])); + matrix.set(SkMatrix::kMPersp2, SkFloatToScalar(transformation[2][2])); + canvas->concat(matrix); + + SkPaint paint; + paint.setColor(color); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setAntiAlias(true); + paint.setHinting(SkPaint::kFull_Hinting); + paint.setTextSize(SkIntToScalar(font_desc->size)); + paint.setTypeface(typeface); // Takes a ref and manages lifetime. + paint.setSubpixelText(true); + paint.setLCDRenderText(true); + + SkScalar x = SkIntToScalar(position.x); + SkScalar y = SkIntToScalar(position.y); + + // Build up the skia advances. + SkAutoSTMalloc<32, SkPoint> storage(glyph_count); + SkPoint* sk_positions = storage.get(); + for (uint32_t i = 0; i < glyph_count; i++) { + sk_positions[i].set(x, y); + x += SkFloatToScalar(glyph_advances[i].x); + y += SkFloatToScalar(glyph_advances[i].y); + } + + canvas->drawPosText(glyph_indices, glyph_count * 2, sk_positions, paint); + + canvas->restore(); + return true; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_font_impl.cc b/webkit/plugins/ppapi/ppb_font_impl.cc new file mode 100644 index 0000000..d0faee9 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_font_impl.cc @@ -0,0 +1,302 @@ +// 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 "webkit/plugins/ppapi/ppb_font_impl.h" + +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/pp_rect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFont.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFontDescription.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFloatPoint.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFloatRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebTextRun.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" +#include "webkit/plugins/ppapi/string.h" +#include "webkit/plugins/ppapi/var.h" +#include "webkit/glue/webkit_glue.h" + +using WebKit::WebFloatPoint; +using WebKit::WebFloatRect; +using WebKit::WebFont; +using WebKit::WebFontDescription; +using WebKit::WebRect; +using WebKit::WebTextRun; + +namespace webkit { +namespace ppapi { + +namespace { + +bool IsPPFontDescriptionValid(const PP_FontDescription_Dev& desc) { + // Check validity of UTF-8. + if (desc.face.type != PP_VARTYPE_STRING && + desc.face.type != PP_VARTYPE_UNDEFINED) + return false; + + // Check enum ranges. + if (static_cast<int>(desc.family) < PP_FONTFAMILY_DEFAULT || + static_cast<int>(desc.family) > PP_FONTFAMILY_MONOSPACE) + return false; + if (static_cast<int>(desc.weight) < PP_FONTWEIGHT_100 || + static_cast<int>(desc.weight) > PP_FONTWEIGHT_900) + return false; + + // Check for excessive sizes which may cause layout to get confused. + if (desc.size > 200) + return false; + + return true; +} + +// The PP_* version lacks "None", so is just one value shifted from the +// WebFontDescription version. These values are checked in +// PPFontDescToWebFontDesc to make sure the conversion is correct. This is a +// macro so it can also be used in the COMPILE_ASSERTS. +#define PP_FONTFAMILY_TO_WEB_FONTFAMILY(f) \ + static_cast<WebFontDescription::GenericFamily>(f + 1) + +// Assumes the given PP_FontDescription has been validated. +WebFontDescription PPFontDescToWebFontDesc(const PP_FontDescription_Dev& font) { + // Verify that the enums match so we can just static cast. + COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight100) == + static_cast<int>(PP_FONTWEIGHT_100), + FontWeight100); + COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight900) == + static_cast<int>(PP_FONTWEIGHT_900), + FontWeight900); + COMPILE_ASSERT(WebFontDescription::GenericFamilyStandard == + PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_DEFAULT), + StandardFamily); + COMPILE_ASSERT(WebFontDescription::GenericFamilySerif == + PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SERIF), + SerifFamily); + COMPILE_ASSERT(WebFontDescription::GenericFamilySansSerif == + PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SANSSERIF), + SansSerifFamily); + COMPILE_ASSERT(WebFontDescription::GenericFamilyMonospace == + PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_MONOSPACE), + MonospaceFamily); + + WebFontDescription result; + scoped_refptr<StringVar> face_name(StringVar::FromPPVar(font.face)); + if (face_name) + result.family = UTF8ToUTF16(face_name->value()); + result.genericFamily = PP_FONTFAMILY_TO_WEB_FONTFAMILY(font.family); + result.size = static_cast<float>(font.size); + result.italic = PPBoolToBool(font.italic); + result.smallCaps = PPBoolToBool(font.small_caps); + result.weight = static_cast<WebFontDescription::Weight>(font.weight); + result.letterSpacing = static_cast<short>(font.letter_spacing); + result.wordSpacing = static_cast<short>(font.word_spacing); + return result; +} + +// Converts the given PP_TextRun to a WebTextRun, returning true on success. +// False means the input was invalid. +bool PPTextRunToWebTextRun(const PP_TextRun_Dev* run, WebTextRun* output) { + scoped_refptr<StringVar> text_string(StringVar::FromPPVar(run->text)); + if (!text_string) + return false; + *output = WebTextRun(UTF8ToUTF16(text_string->value()), + PPBoolToBool(run->rtl), + PPBoolToBool(run->override_direction)); + return true; +} + +PP_Resource Create(PP_Module module_id, + const PP_FontDescription_Dev* description) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + + if (!IsPPFontDescriptionValid(*description)) + return 0; + + scoped_refptr<PPB_Font_Impl> font(new PPB_Font_Impl(module, *description)); + return font->GetReference(); +} + +PP_Bool IsFont(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_Font_Impl>(resource).get()); +} + +PP_Bool Describe(PP_Resource font_id, + PP_FontDescription_Dev* description, + PP_FontMetrics_Dev* metrics) { + scoped_refptr<PPB_Font_Impl> font(Resource::GetAs<PPB_Font_Impl>(font_id)); + if (!font.get()) + return PP_FALSE; + return BoolToPPBool(font->Describe(description, metrics)); +} + +PP_Bool DrawTextAt(PP_Resource font_id, + PP_Resource image_data, + const PP_TextRun_Dev* text, + const PP_Point* position, + uint32_t color, + const PP_Rect* clip, + PP_Bool image_data_is_opaque) { + scoped_refptr<PPB_Font_Impl> font(Resource::GetAs<PPB_Font_Impl>(font_id)); + if (!font.get()) + return PP_FALSE; + return BoolToPPBool(font->DrawTextAt(image_data, text, position, color, clip, + PPBoolToBool(image_data_is_opaque))); +} + +int32_t MeasureText(PP_Resource font_id, const PP_TextRun_Dev* text) { + scoped_refptr<PPB_Font_Impl> font(Resource::GetAs<PPB_Font_Impl>(font_id)); + if (!font.get()) + return -1; + return font->MeasureText(text); +} + +uint32_t CharacterOffsetForPixel(PP_Resource font_id, + const PP_TextRun_Dev* text, + int32_t pixel_position) { + scoped_refptr<PPB_Font_Impl> font(Resource::GetAs<PPB_Font_Impl>(font_id)); + if (!font.get()) + return false; + return font->CharacterOffsetForPixel(text, pixel_position); +} + +int32_t PixelOffsetForCharacter(PP_Resource font_id, + const PP_TextRun_Dev* text, + uint32_t char_offset) { + scoped_refptr<PPB_Font_Impl> font(Resource::GetAs<PPB_Font_Impl>(font_id)); + if (!font.get()) + return false; + return font->PixelOffsetForCharacter(text, char_offset); +} + +const PPB_Font_Dev ppb_font = { + &Create, + &IsFont, + &Describe, + &DrawTextAt, + &MeasureText, + &CharacterOffsetForPixel, + &PixelOffsetForCharacter +}; + +} // namespace + +PPB_Font_Impl::PPB_Font_Impl(PluginModule* module, + const PP_FontDescription_Dev& desc) + : Resource(module) { + WebFontDescription web_font_desc = PPFontDescToWebFontDesc(desc); + font_.reset(WebFont::create(web_font_desc)); +} + +PPB_Font_Impl::~PPB_Font_Impl() { +} + +// static +const PPB_Font_Dev* PPB_Font_Impl::GetInterface() { + return &ppb_font; +} + +PPB_Font_Impl* PPB_Font_Impl::AsPPB_Font_Impl() { + return this; +} + +bool PPB_Font_Impl::Describe(PP_FontDescription_Dev* description, + PP_FontMetrics_Dev* metrics) { + if (description->face.type != PP_VARTYPE_UNDEFINED) + return false; + + WebFontDescription web_desc = font_->fontDescription(); + + // While converting the other way in PPFontDescToWebFontDesc we validated + // that the enums can be casted. + description->face = StringVar::StringToPPVar(module(), + UTF16ToUTF8(web_desc.family)); + description->family = static_cast<PP_FontFamily_Dev>(web_desc.genericFamily); + description->size = static_cast<uint32_t>(web_desc.size); + description->weight = static_cast<PP_FontWeight_Dev>(web_desc.weight); + description->italic = BoolToPPBool(web_desc.italic); + description->small_caps = BoolToPPBool(web_desc.smallCaps); + + metrics->height = font_->height(); + metrics->ascent = font_->ascent(); + metrics->descent = font_->descent(); + metrics->line_spacing = font_->lineSpacing(); + metrics->x_height = static_cast<int32_t>(font_->xHeight()); + + return true; +} + +bool PPB_Font_Impl::DrawTextAt(PP_Resource image_data, + const PP_TextRun_Dev* text, + const PP_Point* position, + uint32_t color, + const PP_Rect* clip, + bool image_data_is_opaque) { + WebTextRun run; + if (!PPTextRunToWebTextRun(text, &run)) + return false; + + // Get and map the image data we're painting to. + scoped_refptr<PPB_ImageData_Impl> image_resource( + Resource::GetAs<PPB_ImageData_Impl>(image_data)); + if (!image_resource.get()) + return false; + ImageDataAutoMapper mapper(image_resource); + if (!mapper.is_valid()) + return false; + + // Convert position and clip. + WebFloatPoint web_position(static_cast<float>(position->x), + static_cast<float>(position->y)); + WebRect web_clip; + if (!clip) { + // Use entire canvas. + web_clip = WebRect(0, 0, image_resource->width(), image_resource->height()); + } else { + web_clip = WebRect(clip->point.x, clip->point.y, + clip->size.width, clip->size.height); + } + + font_->drawText(webkit_glue::ToWebCanvas(image_resource->mapped_canvas()), + run, web_position, color, web_clip, image_data_is_opaque); + return true; +} + +int32_t PPB_Font_Impl::MeasureText(const PP_TextRun_Dev* text) { + WebTextRun run; + if (!PPTextRunToWebTextRun(text, &run)) + return -1; + return font_->calculateWidth(run); +} + +uint32_t PPB_Font_Impl::CharacterOffsetForPixel(const PP_TextRun_Dev* text, + int32_t pixel_position) { + WebTextRun run; + if (!PPTextRunToWebTextRun(text, &run)) + return -1; + + return static_cast<uint32_t>(font_->offsetForPosition( + run, static_cast<float>(pixel_position))); +} + +int32_t PPB_Font_Impl::PixelOffsetForCharacter(const PP_TextRun_Dev* text, + uint32_t char_offset) { + WebTextRun run; + if (!PPTextRunToWebTextRun(text, &run)) + return -1; + if (char_offset >= run.text.length()) + return -1; + + WebFloatRect rect = font_->selectionRectForText( + run, WebFloatPoint(0.0f, 0.0f), font_->height(), 0, char_offset); + return static_cast<int>(rect.width); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_font_impl.h b/webkit/plugins/ppapi/ppb_font_impl.h new file mode 100644 index 0000000..ff70330 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_font_impl.h @@ -0,0 +1,58 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_FONT_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_FONT_IMPL_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "ppapi/c/dev/ppb_font_dev.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace WebKit { +class WebFont; +} + +namespace webkit { +namespace ppapi { + +class PluginInstance; + +class PPB_Font_Impl : public Resource { + public: + PPB_Font_Impl(PluginModule* module, const PP_FontDescription_Dev& desc); + virtual ~PPB_Font_Impl(); + + // Returns a pointer to the interface implementing PPB_Font that is exposed to + // the plugin. + static const PPB_Font_Dev* GetInterface(); + + // Resource overrides. + virtual PPB_Font_Impl* AsPPB_Font_Impl(); + + // PPB_Font implementation. + bool Describe(PP_FontDescription_Dev* description, + PP_FontMetrics_Dev* metrics); + bool DrawTextAt(PP_Resource image_data, + const PP_TextRun_Dev* text, + const PP_Point* position, + uint32_t color, + const PP_Rect* clip, + bool image_data_is_opaque); + int32_t MeasureText(const PP_TextRun_Dev* text); + uint32_t CharacterOffsetForPixel(const PP_TextRun_Dev* text, + int32_t pixel_position); + int32_t PixelOffsetForCharacter(const PP_TextRun_Dev* text, + uint32_t char_offset); + + private: + scoped_ptr<WebKit::WebFont> font_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Font_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_FONT_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc b/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc new file mode 100644 index 0000000..89435ff --- /dev/null +++ b/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc @@ -0,0 +1,652 @@ +// 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 "webkit/plugins/ppapi/ppb_graphics_2d_impl.h" + +#include <iterator> + +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/task.h" +#include "gfx/blit.h" +#include "gfx/point.h" +#include "gfx/rect.h" +#include "skia/ext/platform_canvas.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_graphics_2d.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" + +#if defined(OS_MACOSX) +#include "base/mac_util.h" +#include "base/mac/scoped_cftyperef.h" +#endif + +namespace webkit { +namespace ppapi { + +namespace { + +// 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; +} + +// Converts BGRA <-> RGBA. +void ConvertBetweenBGRAandRGBA(const uint32_t* input, + int pixel_length, + uint32_t* output) { + for (int i = 0; i < pixel_length; i++) { + const unsigned char* pixel_in = + reinterpret_cast<const unsigned char*>(&input[i]); + unsigned char* pixel_out = reinterpret_cast<unsigned char*>(&output[i]); + pixel_out[0] = pixel_in[2]; + pixel_out[1] = pixel_in[1]; + pixel_out[2] = pixel_in[0]; + pixel_out[3] = pixel_in[3]; + } +} + +// Converts ImageData from PP_IMAGEDATAFORMAT_BGRA_PREMUL to +// PP_IMAGEDATAFORMAT_RGBA_PREMUL, or reverse. +void ConvertImageData(PPB_ImageData_Impl* src_image, const SkIRect& src_rect, + PPB_ImageData_Impl* dest_image, const SkRect& dest_rect) { + DCHECK(src_image->format() != dest_image->format()); + DCHECK(PPB_ImageData_Impl::IsImageDataFormatSupported(src_image->format())); + DCHECK(PPB_ImageData_Impl::IsImageDataFormatSupported(dest_image->format())); + + const SkBitmap* src_bitmap = src_image->GetMappedBitmap(); + const SkBitmap* dest_bitmap = dest_image->GetMappedBitmap(); + if (src_rect.width() == src_image->width() && + dest_rect.width() == dest_image->width()) { + // Fast path if the full line needs to be converted. + ConvertBetweenBGRAandRGBA( + src_bitmap->getAddr32(static_cast<int>(src_rect.fLeft), + static_cast<int>(src_rect.fTop)), + src_rect.width() * src_rect.height(), + dest_bitmap->getAddr32(static_cast<int>(dest_rect.fLeft), + static_cast<int>(dest_rect.fTop))); + } else { + // Slow path where we convert line by line. + for (int y = 0; y < src_rect.height(); y++) { + ConvertBetweenBGRAandRGBA( + src_bitmap->getAddr32(static_cast<int>(src_rect.fLeft), + static_cast<int>(src_rect.fTop + y)), + src_rect.width(), + dest_bitmap->getAddr32(static_cast<int>(dest_rect.fLeft), + static_cast<int>(dest_rect.fTop + y))); + } + } +} + +PP_Resource Create(PP_Module module_id, + const PP_Size* size, + PP_Bool is_always_opaque) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + + scoped_refptr<PPB_Graphics2D_Impl> context(new PPB_Graphics2D_Impl(module)); + if (!context->Init(size->width, size->height, PPBoolToBool(is_always_opaque))) + return 0; + return context->GetReference(); +} + +PP_Bool IsGraphics2D(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_Graphics2D_Impl>(resource)); +} + +PP_Bool Describe(PP_Resource graphics_2d, + PP_Size* size, + PP_Bool* is_always_opaque) { + scoped_refptr<PPB_Graphics2D_Impl> context( + Resource::GetAs<PPB_Graphics2D_Impl>(graphics_2d)); + if (!context) + return PP_FALSE; + return context->Describe(size, is_always_opaque); +} + +void PaintImageData(PP_Resource graphics_2d, + PP_Resource image_data, + const PP_Point* top_left, + const PP_Rect* src_rect) { + scoped_refptr<PPB_Graphics2D_Impl> context( + Resource::GetAs<PPB_Graphics2D_Impl>(graphics_2d)); + if (context) + context->PaintImageData(image_data, top_left, src_rect); +} + +void Scroll(PP_Resource graphics_2d, + const PP_Rect* clip_rect, + const PP_Point* amount) { + scoped_refptr<PPB_Graphics2D_Impl> context( + Resource::GetAs<PPB_Graphics2D_Impl>(graphics_2d)); + if (context) + context->Scroll(clip_rect, amount); +} + +void ReplaceContents(PP_Resource graphics_2d, PP_Resource image_data) { + scoped_refptr<PPB_Graphics2D_Impl> context( + Resource::GetAs<PPB_Graphics2D_Impl>(graphics_2d)); + if (context) + context->ReplaceContents(image_data); +} + +int32_t Flush(PP_Resource graphics_2d, + PP_CompletionCallback callback) { + scoped_refptr<PPB_Graphics2D_Impl> context( + Resource::GetAs<PPB_Graphics2D_Impl>(graphics_2d)); + if (!context) + return PP_ERROR_BADRESOURCE; + return context->Flush(callback); +} + +const PPB_Graphics2D ppb_graphics_2d = { + &Create, + &IsGraphics2D, + &Describe, + &PaintImageData, + &Scroll, + &ReplaceContents, + &Flush +}; + +} // namespace + +struct PPB_Graphics2D_Impl::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<PPB_ImageData_Impl> 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<PPB_ImageData_Impl> replace_image; +}; + +PPB_Graphics2D_Impl::PPB_Graphics2D_Impl(PluginModule* module) + : Resource(module), + bound_instance_(NULL), + flushed_any_data_(false), + offscreen_flush_pending_(false), + is_always_opaque_(false) { +} + +PPB_Graphics2D_Impl::~PPB_Graphics2D_Impl() { +} + +// static +const PPB_Graphics2D* PPB_Graphics2D_Impl::GetInterface() { + return &ppb_graphics_2d; +} + +bool PPB_Graphics2D_Impl::Init(int width, int height, bool is_always_opaque) { + // The underlying PPB_ImageData_Impl will validate the dimensions. + image_data_ = new PPB_ImageData_Impl(module()); + if (!image_data_->Init(PPB_ImageData_Impl::GetNativeImageDataFormat(), + width, height, true) || + !image_data_->Map()) { + image_data_ = NULL; + return false; + } + is_always_opaque_ = is_always_opaque; + return true; +} + +PPB_Graphics2D_Impl* PPB_Graphics2D_Impl::AsPPB_Graphics2D_Impl() { + return this; +} + +PP_Bool PPB_Graphics2D_Impl::Describe(PP_Size* size, PP_Bool* is_always_opaque) { + size->width = image_data_->width(); + size->height = image_data_->height(); + *is_always_opaque = PP_FALSE; // TODO(brettw) implement this. + return PP_TRUE; +} + +void PPB_Graphics2D_Impl::PaintImageData(PP_Resource image_data, + const PP_Point* top_left, + const PP_Rect* src_rect) { + if (!top_left) + return; + + scoped_refptr<PPB_ImageData_Impl> image_resource( + Resource::GetAs<PPB_ImageData_Impl>(image_data)); + if (!image_resource) + return; + + QueuedOperation operation(QueuedOperation::PAINT); + operation.paint_image = image_resource; + if (!ValidateAndConvertRect(src_rect, image_resource->width(), + image_resource->height(), + &operation.paint_src_rect)) + return; + + // Validate the bitmap position using the previously-validated rect, there + // should be no painted area outside of the image. + int64 x64 = static_cast<int64>(top_left->x); + int64 y64 = static_cast<int64>(top_left->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; + if (y64 + static_cast<int64>(operation.paint_src_rect.y()) < 0 || + y64 + static_cast<int64>(operation.paint_src_rect.bottom()) > + image_data_->height()) + return; + operation.paint_x = top_left->x; + operation.paint_y = top_left->y; + + queued_operations_.push_back(operation); +} + +void PPB_Graphics2D_Impl::Scroll(const PP_Rect* clip_rect, + const PP_Point* amount) { + QueuedOperation operation(QueuedOperation::SCROLL); + if (!ValidateAndConvertRect(clip_rect, + image_data_->width(), + image_data_->height(), + &operation.scroll_clip_rect)) + return; + + // If we're being asked to scroll by more than the clip rect size, just + // ignore this scroll command and say it worked. + int32 dx = amount->x; + int32 dy = amount->y; + if (dx <= -image_data_->width() || dx >= image_data_->width() || + dy <= -image_data_->height() || dy >= image_data_->height()) + return; + + operation.scroll_dx = dx; + operation.scroll_dy = dy; + + queued_operations_.push_back(operation); +} + +void PPB_Graphics2D_Impl::ReplaceContents(PP_Resource image_data) { + scoped_refptr<PPB_ImageData_Impl> image_resource( + Resource::GetAs<PPB_ImageData_Impl>(image_data)); + if (!image_resource) + return; + if (!PPB_ImageData_Impl::IsImageDataFormatSupported( + image_resource->format())) + return; + + if (image_resource->width() != image_data_->width() || + image_resource->height() != image_data_->height()) + return; + + QueuedOperation operation(QueuedOperation::REPLACE); + operation.replace_image = image_resource; + queued_operations_.push_back(operation); +} + +int32_t PPB_Graphics2D_Impl::Flush(const PP_CompletionCallback& callback) { + // Don't allow more than one pending flush at a time. + if (HasPendingFlush()) + return PP_ERROR_INPROGRESS; + + // TODO(brettw) check that the current thread is not the main one and + // implement blocking flushes in this case. + if (!callback.func) + return PP_ERROR_BADARGUMENT; + + bool nothing_visible = true; + for (size_t i = 0; i < queued_operations_.size(); i++) { + QueuedOperation& operation = queued_operations_[i]; + gfx::Rect op_rect; + switch (operation.type) { + case QueuedOperation::PAINT: + ExecutePaintImageData(operation.paint_image, + operation.paint_x, operation.paint_y, + operation.paint_src_rect, + &op_rect); + break; + case QueuedOperation::SCROLL: + ExecuteScroll(operation.scroll_clip_rect, + operation.scroll_dx, operation.scroll_dy, + &op_rect); + break; + case QueuedOperation::REPLACE: + ExecuteReplaceContents(operation.replace_image, &op_rect); + break; + } + + // We need the rect to be in terms of the current clip rect of the plugin + // since that's what will actually be painted. If we issue an invalidate + // for a clipped-out region, WebKit will do nothing and we won't get any + // ViewInitiatedPaint/ViewFlushedPaint calls, leaving our callback stranded. + gfx::Rect visible_changed_rect; + if (bound_instance_ && !op_rect.IsEmpty()) + visible_changed_rect = bound_instance_->clip().Intersect(op_rect); + + if (bound_instance_ && !visible_changed_rect.IsEmpty()) { + if (operation.type == QueuedOperation::SCROLL) { + bound_instance_->ScrollRect(operation.scroll_dx, operation.scroll_dy, + visible_changed_rect); + } else { + bound_instance_->InvalidateRect(visible_changed_rect); + } + nothing_visible = false; + } + } + queued_operations_.clear(); + flushed_any_data_ = true; + + if (nothing_visible) { + // There's nothing visible to invalidate so just schedule the callback to + // execute in the next round of the message loop. + ScheduleOffscreenCallback(FlushCallbackData(callback)); + } else { + unpainted_flush_callback_.Set(callback); + } + return PP_ERROR_WOULDBLOCK; +} + +bool PPB_Graphics2D_Impl::ReadImageData(PP_Resource image, + const PP_Point* top_left) { + // Get and validate the image object to paint into. + scoped_refptr<PPB_ImageData_Impl> image_resource( + Resource::GetAs<PPB_ImageData_Impl>(image)); + if (!image_resource) + return false; + if (!PPB_ImageData_Impl::IsImageDataFormatSupported( + image_resource->format())) + return false; // Must be in the right format. + + // Validate the bitmap position. + int x = top_left->x; + if (x < 0 || + static_cast<int64>(x) + static_cast<int64>(image_resource->width()) > + image_data_->width()) + return false; + int y = top_left->y; + if (y < 0 || + static_cast<int64>(y) + static_cast<int64>(image_resource->height()) > + image_data_->height()) + return false; + + ImageDataAutoMapper auto_mapper(image_resource); + if (!auto_mapper.is_valid()) + return false; + + 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()) }; + + ImageDataAutoMapper auto_mapper2(image_data_); + if (image_resource->format() != image_data_->format()) { + // Convert the image data if the format does not match. + ConvertImageData(image_data_, src_irect, image_resource.get(), dest_rect); + } else { + skia::PlatformCanvas* dest_canvas = image_resource->mapped_canvas(); + + // 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; +} + +bool PPB_Graphics2D_Impl::BindToInstance(PluginInstance* new_instance) { + if (bound_instance_ == new_instance) + return true; // Rebinding the same device, nothing to do. + if (bound_instance_ && new_instance) + return false; // Can't change a bound device. + + if (!new_instance) { + // When the device is detached, we'll not get any more paint callbacks so + // we need to clear the list, but we still want to issue any pending + // callbacks to the plugin. + if (!unpainted_flush_callback_.is_null()) { + ScheduleOffscreenCallback(unpainted_flush_callback_); + unpainted_flush_callback_.Clear(); + } + if (!painted_flush_callback_.is_null()) { + ScheduleOffscreenCallback(painted_flush_callback_); + painted_flush_callback_.Clear(); + } + } else if (flushed_any_data_) { + // Only schedule a paint if this backing store has had any data flushed to + // it. This is an optimization. A "normal" plugin will first allocated a + // backing store, bind it, and then execute their normal painting and + // update loop. If binding a device always invalidated, it would mean we + // would get one paint for the bind, and one for the first time the plugin + // actually painted something. By not bothering to schedule an invalidate + // when an empty device is initially bound, we can save an extra paint for + // many plugins during the critical page initialization phase. + new_instance->InvalidateRect(gfx::Rect()); + } + + bound_instance_ = new_instance; + return true; +} + +void PPB_Graphics2D_Impl::Paint(WebKit::WebCanvas* canvas, + const gfx::Rect& plugin_rect, + const gfx::Rect& paint_rect) { + ImageDataAutoMapper auto_mapper(image_data_); + const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap(); + +#if defined(OS_MACOSX) + SkAutoLockPixels lock(backing_bitmap); + + base::mac::ScopedCFTypeRef<CGDataProviderRef> data_provider( + CGDataProviderCreateWithData( + NULL, backing_bitmap.getAddr32(0, 0), + backing_bitmap.rowBytes() * backing_bitmap.height(), NULL)); + base::mac::ScopedCFTypeRef<CGImageRef> image( + CGImageCreate( + backing_bitmap.width(), backing_bitmap.height(), + 8, 32, backing_bitmap.rowBytes(), + mac_util::GetSystemColorSpace(), + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, + data_provider, NULL, false, kCGRenderingIntentDefault)); + + // Flip the transform + CGContextSaveGState(canvas); + float window_height = static_cast<float>(CGBitmapContextGetHeight(canvas)); + CGContextTranslateCTM(canvas, 0, window_height); + CGContextScaleCTM(canvas, 1.0, -1.0); + + CGRect bounds; + bounds.origin.x = plugin_rect.origin().x(); + bounds.origin.y = window_height - plugin_rect.origin().y() - + backing_bitmap.height(); + bounds.size.width = backing_bitmap.width(); + bounds.size.height = backing_bitmap.height(); + + // TODO(brettw) bug 56673: do a direct memcpy instead of going through CG + // if the is_always_opaque_ flag is set. + + CGContextDrawImage(canvas, bounds, image); + CGContextRestoreGState(canvas); +#else + SkPaint paint; + if (is_always_opaque_) { + // When we know the device is opaque, we can disable blending for slightly + // more optimized painting. + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + } + + gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y()); + canvas->drawBitmap(backing_bitmap, + SkIntToScalar(plugin_rect.origin().x()), + SkIntToScalar(plugin_rect.origin().y()), + &paint); +#endif +} + +void PPB_Graphics2D_Impl::ViewInitiatedPaint() { + // Move any "unpainted" callback to the painted state. See + // |unpainted_flush_callback_| in the header for more. + if (!unpainted_flush_callback_.is_null()) { + DCHECK(painted_flush_callback_.is_null()); + std::swap(painted_flush_callback_, unpainted_flush_callback_); + } +} + +void PPB_Graphics2D_Impl::ViewFlushedPaint() { + // Notify any "painted" callback. See |unpainted_flush_callback_| in the + // header for more. + if (!painted_flush_callback_.is_null()) { + // We must clear this variable before issuing the callback. It will be + // common for the plugin to issue another invalidate in response to a flush + // callback, and we don't want to think that a callback is already pending. + FlushCallbackData callback; + std::swap(callback, painted_flush_callback_); + callback.Execute(PP_OK); + } +} + +void PPB_Graphics2D_Impl::ExecutePaintImageData(PPB_ImageData_Impl* image, + int x, int y, + const gfx::Rect& src_rect, + gfx::Rect* invalidated_rect) { + // Ensure the source image is mapped to read from it. + ImageDataAutoMapper auto_mapper(image); + if (!auto_mapper.is_valid()) + return; + + // 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. + *invalidated_rect = src_rect; + invalidated_rect->Offset(x, y); + SkRect dest_rect = { SkIntToScalar(invalidated_rect->x()), + SkIntToScalar(invalidated_rect->y()), + SkIntToScalar(invalidated_rect->right()), + SkIntToScalar(invalidated_rect->bottom()) }; + + if (image->format() != image_data_->format()) { + // Convert the image data if the format does not match. + ConvertImageData(image, src_irect, image_data_, dest_rect); + } else { + // 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 PPB_Graphics2D_Impl::ExecuteScroll(const gfx::Rect& clip, + int dx, int dy, + gfx::Rect* invalidated_rect) { + gfx::ScrollCanvas(image_data_->mapped_canvas(), + clip, gfx::Point(dx, dy)); + *invalidated_rect = clip; +} + +void PPB_Graphics2D_Impl::ExecuteReplaceContents(PPB_ImageData_Impl* image, + gfx::Rect* invalidated_rect) { + if (image->format() != image_data_->format()) { + DCHECK(image->width() == image_data_->width() && + image->height() == image_data_->height()); + // Convert the image data if the format does not match. + SkIRect src_irect = { 0, 0, image->width(), image->height() }; + SkRect dest_rect = { SkIntToScalar(0), + SkIntToScalar(0), + SkIntToScalar(image_data_->width()), + SkIntToScalar(image_data_->height()) }; + ConvertImageData(image, src_irect, image_data_, dest_rect); + } else { + image_data_->Swap(image); + } + *invalidated_rect = gfx::Rect(0, 0, + image_data_->width(), image_data_->height()); +} + +void PPB_Graphics2D_Impl::ScheduleOffscreenCallback( + const FlushCallbackData& callback) { + DCHECK(!HasPendingFlush()); + offscreen_flush_pending_ = true; + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(this, + &PPB_Graphics2D_Impl::ExecuteOffscreenCallback, + callback)); +} + +void PPB_Graphics2D_Impl::ExecuteOffscreenCallback(FlushCallbackData data) { + DCHECK(offscreen_flush_pending_); + + // We must clear this flag before issuing the callback. It will be + // common for the plugin to issue another invalidate in response to a flush + // callback, and we don't want to think that a callback is already pending. + offscreen_flush_pending_ = false; + data.Execute(PP_OK); +} + +bool PPB_Graphics2D_Impl::HasPendingFlush() const { + return !unpainted_flush_callback_.is_null() || + !painted_flush_callback_.is_null() || + offscreen_flush_pending_; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_graphics_2d_impl.h b/webkit/plugins/ppapi/ppb_graphics_2d_impl.h new file mode 100644 index 0000000..40f2e5d --- /dev/null +++ b/webkit/plugins/ppapi/ppb_graphics_2d_impl.h @@ -0,0 +1,182 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_GRAPHICS_2D_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_GRAPHICS_2D_IMPL_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/ppb_graphics_2d.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PPB_Graphics2D; + +namespace gfx { +class Rect; +} + +namespace webkit { +namespace ppapi { + +class PPB_ImageData_Impl; +class PluginInstance; +class PluginModule; + +class PPB_Graphics2D_Impl : public Resource { + public: + PPB_Graphics2D_Impl(PluginModule* module); + virtual ~PPB_Graphics2D_Impl(); + + // Returns a pointer to the interface implementing PPB_ImageData that is + // exposed to the plugin. + static const PPB_Graphics2D* GetInterface(); + + bool Init(int width, int height, bool is_always_opaque); + + bool is_always_opaque() const { return is_always_opaque_; } + + // Resource override. + virtual PPB_Graphics2D_Impl* AsPPB_Graphics2D_Impl(); + + // PPB_Graphics2D functions. + PP_Bool Describe(PP_Size* size, PP_Bool* is_always_opaque); + void PaintImageData(PP_Resource image_data, + const PP_Point* top_left, + const PP_Rect* src_rect); + void Scroll(const PP_Rect* clip_rect, const PP_Point* amount); + void ReplaceContents(PP_Resource image_data); + int32_t Flush(const PP_CompletionCallback& callback); + + bool ReadImageData(PP_Resource image, const PP_Point* top_left); + + // Assciates this device with the given plugin instance. You can pass NULL to + // clear the existing device. Returns true on success. In this case, a + // repaint of the page will also be scheduled. Failure means that the device + // is already bound to a different instance, and nothing will happen. + bool BindToInstance(PluginInstance* new_instance); + + // Paints the current backing store to the web page. + void Paint(WebKit::WebCanvas* canvas, + const gfx::Rect& plugin_rect, + const gfx::Rect& paint_rect); + + // Notifications that the view has rendered the page and that it has been + // flushed to the screen. These messages are used to send Flush callbacks to + // the plugin. See + void ViewInitiatedPaint(); + void ViewFlushedPaint(); + + PPB_ImageData_Impl* image_data() { return image_data_.get(); } + + private: + // Tracks a call to flush that requires a callback. + class FlushCallbackData { + public: + FlushCallbackData() { + Clear(); + } + + FlushCallbackData(const PP_CompletionCallback& callback) { + Set(callback); + } + + bool is_null() const { return !callback_.func; } + + void Set(const PP_CompletionCallback& callback) { + callback_ = callback; + } + + void Clear() { + callback_ = PP_MakeCompletionCallback(NULL, 0); + } + + void Execute(int32_t result) { + PP_RunCompletionCallback(&callback_, result); + } + + private: + PP_CompletionCallback callback_; + }; + + // Called internally to execute the different queued commands. The + // parameters to these functions will have already been validated. The last + // rect argument will be filled by each function with the area affected by + // the update that requires invalidation. If there were no pixels changed, + // this rect can be untouched. + void ExecutePaintImageData(PPB_ImageData_Impl* image, + int x, int y, + const gfx::Rect& src_rect, + gfx::Rect* invalidated_rect); + void ExecuteScroll(const gfx::Rect& clip, int dx, int dy, + gfx::Rect* invalidated_rect); + void ExecuteReplaceContents(PPB_ImageData_Impl* image, + gfx::Rect* invalidated_rect); + + // Schedules the offscreen callback to be fired at a future time. This + // will add the given item to the offscreen_flush_callbacks_ vector. + void ScheduleOffscreenCallback(const FlushCallbackData& callback); + + // Function scheduled to execute by ScheduleOffscreenCallback that actually + // issues the offscreen callbacks. + void ExecuteOffscreenCallback(FlushCallbackData data); + + // Returns true if there is any type of flush callback pending. + bool HasPendingFlush() const; + + scoped_refptr<PPB_ImageData_Impl> image_data_; + + // Non-owning pointer to the plugin instance this context is currently bound + // to, if any. If the context is currently unbound, this will be NULL. + PluginInstance* bound_instance_; + + // Keeps track of all drawing commands queued before a Flush call. + struct QueuedOperation; + typedef std::vector<QueuedOperation> OperationQueue; + OperationQueue queued_operations_; + + // Indicates whether any changes have been flushed to the backing store. + // This is initially false and is set to true at the first Flush() call. + bool flushed_any_data_; + + // The plugin can give us one "Flush" at a time. This flush will either be in + // the "unpainted" state (in which case unpainted_flush_callback_ will be + // non-NULL) or painted, in which case painted_flush_callback_ will be + // non-NULL). There can also be an offscreen callback which is handled + // separately (see offscreen_callback_pending_). Only one of these three + // things may be set at a time to enforce the "only one pending flush at a + // time" constraint. + // + // "Unpainted" ones are flush requests which have never been painted. These + // could have been done while the RenderView was already waiting for an ACK + // from a previous paint, so won't generate a new one yet. + // + // "Painted" ones are those flushes that have been painted by RenderView, but + // for which the ACK from the browser has not yet been received. + // + // When we get updates from a plugin with a callback, it is first added to + // the unpainted callbacks. When the renderer has initiated a paint, we'll + // move it to the painted callbacks list. When the renderer receives a flush, + // we'll execute the callback and remove it from the list. + FlushCallbackData unpainted_flush_callback_; + FlushCallbackData painted_flush_callback_; + + // When doing offscreen flushes, we issue a task that issues the callback + // later. This is set when one of those tasks is pending so that we can + // enforce the "only one pending flush at a time" constraint in the API. + bool offscreen_flush_pending_; + + // Set to true if the plugin declares that this device will always be opaque. + // This allows us to do more optimized painting in some cases. + bool is_always_opaque_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Graphics2D_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_GRAPHICS_2D_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_graphics_3d_impl.cc b/webkit/plugins/ppapi/ppb_graphics_3d_impl.cc new file mode 100644 index 0000000..0355262 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_graphics_3d_impl.cc @@ -0,0 +1,263 @@ +// 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 "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" + +#include "gpu/command_buffer/common/command_buffer.h" +#include "base/lazy_instance.h" +#include "base/thread_local.h" +#include "ppapi/c/dev/ppb_graphics_3d_dev.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +namespace webkit { +namespace ppapi { + +namespace { + +static base::LazyInstance<base::ThreadLocalPointer<PPB_Graphics3D_Impl> > + g_current_context_key(base::LINKER_INITIALIZED); + +// Size of the transfer buffer. +enum { kTransferBufferSize = 512 * 1024 }; + +PP_Bool IsGraphics3D(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_Graphics3D_Impl>(resource)); +} + +PP_Bool GetConfigs(int32_t* configs, int32_t config_size, int32_t* num_config) { + // TODO(neb): Implement me! + return PP_FALSE; +} + +PP_Bool ChooseConfig(const int32_t* attrib_list, int32_t* configs, + int32_t config_size, int32_t* num_config) { + // TODO(neb): Implement me! + return PP_FALSE; +} + +PP_Bool GetConfigAttrib(int32_t config, int32_t attribute, int32_t* value) { + // TODO(neb): Implement me! + return PP_FALSE; +} + +const char* QueryString(int32_t name) { + switch (name) { + case EGL_CLIENT_APIS: + return "OpenGL_ES"; + case EGL_EXTENSIONS: + return ""; + case EGL_VENDOR: + return "Google"; + case EGL_VERSION: + return "1.0 Google"; + default: + return NULL; + } +} + +PP_Resource CreateContext(PP_Instance instance_id, int32_t config, + int32_t share_context, + const int32_t* attrib_list) { + DCHECK_EQ(0, share_context); + + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) { + return 0; + } + + scoped_refptr<PPB_Graphics3D_Impl> context( + new PPB_Graphics3D_Impl(instance->module())); + if (!context->Init(instance_id, config, attrib_list)) { + return 0; + } + + return context->GetReference(); +} + +void* GetProcAddress(const char* name) { + // TODO(neb): Implement me! + return NULL; +} + +PP_Bool MakeCurrent(PP_Resource graphics3d) { + if (!graphics3d) { + PPB_Graphics3D_Impl::ResetCurrent(); + return PP_TRUE; + } else { + scoped_refptr<PPB_Graphics3D_Impl> context( + Resource::GetAs<PPB_Graphics3D_Impl>(graphics3d)); + return BoolToPPBool(context.get() && context->MakeCurrent()); + } +} + +PP_Resource GetCurrentContext() { + PPB_Graphics3D_Impl* current_context = PPB_Graphics3D_Impl::GetCurrent(); + return current_context ? current_context->GetReference() : 0; +} + +PP_Bool SwapBuffers(PP_Resource graphics3d) { + scoped_refptr<PPB_Graphics3D_Impl> context( + Resource::GetAs<PPB_Graphics3D_Impl>(graphics3d)); + return BoolToPPBool(context && context->SwapBuffers()); +} + +uint32_t GetError() { + // Technically, this should return the last error that occurred on the current + // thread, rather than an error associated with a particular context. + // TODO(apatrick): Fix this. + PPB_Graphics3D_Impl* current_context = PPB_Graphics3D_Impl::GetCurrent(); + if (!current_context) + return 0; + + return current_context->GetError(); +} + +const PPB_Graphics3D_Dev ppb_graphics3d = { + &IsGraphics3D, + &GetConfigs, + &ChooseConfig, + &GetConfigAttrib, + &QueryString, + &CreateContext, + &GetProcAddress, + &MakeCurrent, + &GetCurrentContext, + &SwapBuffers, + &GetError +}; + +} // namespace + +PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PluginModule* module) + : Resource(module), + bound_instance_(NULL) { +} + +const PPB_Graphics3D_Dev* PPB_Graphics3D_Impl::GetInterface() { + return &ppb_graphics3d; +} + +PPB_Graphics3D_Impl* PPB_Graphics3D_Impl::GetCurrent() { + return g_current_context_key.Get().Get(); +} + +void PPB_Graphics3D_Impl::ResetCurrent() { + g_current_context_key.Get().Set(NULL); +} + +PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() { + Destroy(); +} + +PPB_Graphics3D_Impl* PPB_Graphics3D_Impl::AsPPB_Graphics3D_Impl() { + return this; +} + +bool PPB_Graphics3D_Impl::Init(PP_Instance instance_id, int32_t config, + const int32_t* attrib_list) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) { + return false; + } + + // Create and initialize the objects required to issue GLES2 calls. + platform_context_.reset(instance->delegate()->CreateContext3D()); + if (!platform_context_.get()) { + Destroy(); + return false; + } + + if (!platform_context_->Init()) { + Destroy(); + return false; + } + + gles2_implementation_ = platform_context_->GetGLES2Implementation(); + DCHECK(gles2_implementation_); + + return true; +} + +bool PPB_Graphics3D_Impl::BindToInstance(PluginInstance* new_instance) { + if (bound_instance_ == new_instance) + return true; // Rebinding the same device, nothing to do. + if (bound_instance_ && new_instance) + return false; // Can't change a bound device. + + if (new_instance) { + // Resize the backing texture to the size of the instance when it is bound. + platform_context_->ResizeBackingTexture(new_instance->position().size()); + + // This is a temporary hack. The SwapBuffers is issued to force the resize + // to take place before any subsequent rendering. This might lead to a + // partially rendered frame being displayed. It is also not thread safe + // since the SwapBuffers is written to the command buffer and that command + // buffer might be written to by another thread. + // TODO(apatrick): Figure out the semantics of binding and resizing. + platform_context_->SwapBuffers(); + } + + bound_instance_ = new_instance; + return true; +} + +bool PPB_Graphics3D_Impl::MakeCurrent() { + if (!platform_context_.get()) + return false; + + g_current_context_key.Get().Set(this); + + // TODO(apatrick): Return false on context lost. + return true; +} + +bool PPB_Graphics3D_Impl::SwapBuffers() { + if (!platform_context_.get()) + return false; + + return platform_context_->SwapBuffers(); +} + +unsigned PPB_Graphics3D_Impl::GetError() { + if (!platform_context_.get()) + return 0; + + return platform_context_->GetError(); +} + +void PPB_Graphics3D_Impl::ResizeBackingTexture(const gfx::Size& size) { + if (!platform_context_.get()) + return; + + platform_context_->ResizeBackingTexture(size); +} + +void PPB_Graphics3D_Impl::SetSwapBuffersCallback(Callback0::Type* callback) { + if (!platform_context_.get()) + return; + + platform_context_->SetSwapBuffersCallback(callback); +} + +unsigned PPB_Graphics3D_Impl::GetBackingTextureId() { + if (!platform_context_.get()) + return 0; + + return platform_context_->GetBackingTextureId(); +} + +void PPB_Graphics3D_Impl::Destroy() { + if (GetCurrent() == this) { + ResetCurrent(); + } + + gles2_implementation_ = NULL; + + platform_context_.reset(); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_graphics_3d_impl.h b/webkit/plugins/ppapi/ppb_graphics_3d_impl.h new file mode 100644 index 0000000..8124979 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_graphics_3d_impl.h @@ -0,0 +1,93 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_GRAPHICS_3D_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_GRAPHICS_3D_IMPL_H_ + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/scoped_ptr.h" +#include "gfx/size.h" +#include "gpu/command_buffer/client/gles2_cmd_helper.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "ppapi/c/pp_instance.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace gpu { +namespace gles2 { +class GLES2Implementation; +} // namespace gles2 +} // namespace gpu + +struct PPB_Graphics3D_Dev; +struct PPB_OpenGLES_Dev; + +namespace webkit { +namespace ppapi { + +class PPB_Graphics3D_Impl : public Resource { + public: + explicit PPB_Graphics3D_Impl(PluginModule* module); + + virtual ~PPB_Graphics3D_Impl(); + + static const PPB_Graphics3D_Dev* GetInterface(); + static const PPB_OpenGLES_Dev* GetOpenGLESInterface(); + + static bool Shutdown(); + + static PPB_Graphics3D_Impl* GetCurrent(); + + static void ResetCurrent(); + + // Resource override. + virtual PPB_Graphics3D_Impl* AsPPB_Graphics3D_Impl(); + + bool Init(PP_Instance instance_id, int32_t config, + const int32_t* attrib_list); + + // Associates this PPB_Graphics3D_Impl with the given plugin instance. You can pass + // NULL to clear the existing device. Returns true on success. In this case, + // the last rendered frame is displayed. + // TODO(apatrick): Figure out the best semantics here. + bool BindToInstance(PluginInstance* new_instance); + + bool MakeCurrent(); + + bool SwapBuffers(); + + unsigned GetError(); + + void ResizeBackingTexture(const gfx::Size& size); + + void SetSwapBuffersCallback(Callback0::Type* callback); + + unsigned GetBackingTextureId(); + + gpu::gles2::GLES2Implementation* impl() { + return gles2_implementation_; + } + + private: + void Destroy(); + + // Non-owning pointer to the plugin instance this context is currently bound + // to, if any. If the context is currently unbound, this will be NULL. + PluginInstance* bound_instance_; + + // PluginDelegate's 3D Context. Responsible for providing the command buffer. + scoped_ptr<PluginDelegate::PlatformContext3D> platform_context_; + + // GLES2 Implementation instance. Owned by the platform context's GGL context. + gpu::gles2::GLES2Implementation* gles2_implementation_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Graphics3D_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_GRAPHICS_3D_IMPL_H_ + diff --git a/webkit/plugins/ppapi/ppb_image_data_impl.cc b/webkit/plugins/ppapi/ppb_image_data_impl.cc new file mode 100644 index 0000000..ee89cc3 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_image_data_impl.cc @@ -0,0 +1,226 @@ +// 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 "webkit/plugins/ppapi/ppb_image_data_impl.h" + +#include <algorithm> +#include <limits> + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "skia/ext/platform_canvas.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_image_data.h" +#include "ppapi/c/trusted/ppb_image_data_trusted.h" +#include "third_party/skia/include/core/SkColorPriv.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PP_ImageDataFormat GetNativeImageDataFormat() { + return PPB_ImageData_Impl::GetNativeImageDataFormat(); +} + +PP_Bool IsImageDataFormatSupported(PP_ImageDataFormat format) { + return BoolToPPBool(PPB_ImageData_Impl::IsImageDataFormatSupported(format)); +} + +PP_Resource Create(PP_Module module_id, + PP_ImageDataFormat format, + const PP_Size* size, + PP_Bool init_to_zero) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + + scoped_refptr<PPB_ImageData_Impl> data(new PPB_ImageData_Impl(module)); + if (!data->Init(format, + size->width, + size->height, + PPBoolToBool(init_to_zero))) { + return 0; + } + + return data->GetReference(); +} + +PP_Bool IsImageData(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_ImageData_Impl>(resource)); +} + +PP_Bool Describe(PP_Resource resource, PP_ImageDataDesc* desc) { + // Give predictable values on failure. + memset(desc, 0, sizeof(PP_ImageDataDesc)); + + scoped_refptr<PPB_ImageData_Impl> image_data( + Resource::GetAs<PPB_ImageData_Impl>(resource)); + if (!image_data) + return PP_FALSE; + image_data->Describe(desc); + return PP_TRUE; +} + +void* Map(PP_Resource resource) { + scoped_refptr<PPB_ImageData_Impl> image_data( + Resource::GetAs<PPB_ImageData_Impl>(resource)); + if (!image_data) + return NULL; + return image_data->Map(); +} + +void Unmap(PP_Resource resource) { + scoped_refptr<PPB_ImageData_Impl> image_data( + Resource::GetAs<PPB_ImageData_Impl>(resource)); + if (image_data) + image_data->Unmap(); +} + +int32_t GetSharedMemory(PP_Resource resource, + int* handle, + uint32_t* byte_count) { + scoped_refptr<PPB_ImageData_Impl> image_data( + Resource::GetAs<PPB_ImageData_Impl>(resource)); + if (image_data) { + *handle = image_data->GetSharedMemoryHandle(byte_count); + return PP_OK; + } + return PP_ERROR_BADRESOURCE; +} + +const PPB_ImageData ppb_imagedata = { + &GetNativeImageDataFormat, + &IsImageDataFormatSupported, + &Create, + &IsImageData, + &Describe, + &Map, + &Unmap, +}; + +const PPB_ImageDataTrusted ppb_imagedata_trusted = { + &GetSharedMemory, +}; + +} // namespace + +PPB_ImageData_Impl::PPB_ImageData_Impl(PluginModule* module) + : Resource(module), + format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL), + width_(0), + height_(0) { +} + +PPB_ImageData_Impl::~PPB_ImageData_Impl() { +} + +// static +const PPB_ImageData* PPB_ImageData_Impl::GetInterface() { + return &ppb_imagedata; +} + +// static +const PPB_ImageDataTrusted* PPB_ImageData_Impl::GetTrustedInterface() { + return &ppb_imagedata_trusted; +} + +// static +PP_ImageDataFormat PPB_ImageData_Impl::GetNativeImageDataFormat() { + if (SK_B32_SHIFT == 0) + return PP_IMAGEDATAFORMAT_BGRA_PREMUL; + else if (SK_R32_SHIFT == 0) + return PP_IMAGEDATAFORMAT_RGBA_PREMUL; + else + return PP_IMAGEDATAFORMAT_BGRA_PREMUL; // Default to something on failure. +} + +// static +bool PPB_ImageData_Impl::IsImageDataFormatSupported( + PP_ImageDataFormat format) { + return format == PP_IMAGEDATAFORMAT_BGRA_PREMUL || + format == PP_IMAGEDATAFORMAT_RGBA_PREMUL; +} + +PPB_ImageData_Impl* PPB_ImageData_Impl::AsPPB_ImageData_Impl() { + return this; +} + +bool PPB_ImageData_Impl::Init(PP_ImageDataFormat format, + 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. + if (!IsImageDataFormatSupported(format)) + return false; // Only support this one format for now. + if (width <= 0 || height <= 0) + return false; + if (static_cast<int64>(width) * static_cast<int64>(height) >= + std::numeric_limits<int32>::max()) + return false; // Prevent overflow of signed 32-bit ints. + + platform_image_.reset( + module()->GetSomeInstance()->delegate()->CreateImage2D(width, height)); + format_ = format; + width_ = width; + height_ = height; + return !!platform_image_.get(); +} + +void PPB_ImageData_Impl::Describe(PP_ImageDataDesc* desc) const { + desc->format = format_; + desc->size.width = width_; + desc->size.height = height_; + desc->stride = width_ * 4; +} + +void* PPB_ImageData_Impl::Map() { + if (!mapped_canvas_.get()) { + mapped_canvas_.reset(platform_image_->Map()); + if (!mapped_canvas_.get()) + return NULL; + } + const SkBitmap& bitmap = + mapped_canvas_->getTopPlatformDevice().accessBitmap(true); + + // Our platform bitmaps are set to opaque by default, which we don't want. + const_cast<SkBitmap&>(bitmap).setIsOpaque(false); + + bitmap.lockPixels(); + return bitmap.getAddr32(0, 0); +} + +void PPB_ImageData_Impl::Unmap() { + // This is currently unimplemented, which is OK. The data will just always + // be around once it's mapped. Chrome's TransportDIB isn't currently + // unmappable without freeing it, but this may be something we want to support + // in the future to save some memory. +} + +int PPB_ImageData_Impl::GetSharedMemoryHandle(uint32* byte_count) const { + return platform_image_->GetSharedMemoryHandle(byte_count); +} + +const SkBitmap* PPB_ImageData_Impl::GetMappedBitmap() const { + if (!mapped_canvas_.get()) + return NULL; + return &mapped_canvas_->getTopPlatformDevice().accessBitmap(false); +} + +void PPB_ImageData_Impl::Swap(PPB_ImageData_Impl* other) { + swap(other->platform_image_, platform_image_); + swap(other->mapped_canvas_, mapped_canvas_); + std::swap(other->format_, format_); + std::swap(other->width_, width_); + std::swap(other->height_, height_); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_image_data_impl.h b/webkit/plugins/ppapi/ppb_image_data_impl.h new file mode 100644 index 0000000..e036d39 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_image_data_impl.h @@ -0,0 +1,134 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_IMAGE_DATA_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_IMAGE_DATA_IMPL_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "ppapi/c/ppb_image_data.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace skia { +class PlatformCanvas; +} + +struct PPB_ImageDataTrusted; +class SkBitmap; + +namespace webkit { +namespace ppapi { + +class PPB_ImageData_Impl : public Resource { + public: + explicit PPB_ImageData_Impl(PluginModule* module); + virtual ~PPB_ImageData_Impl(); + + int width() const { return width_; } + int height() const { return height_; } + + // Returns the image format. + PP_ImageDataFormat format() const { return format_; } + + // Returns true if this image is mapped. False means that the image is either + // invalid or not mapped. See ImageDataAutoMapper below. + bool is_mapped() const { return !!mapped_canvas_.get(); } + + PluginDelegate::PlatformImage2D* platform_image() 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(); + static const PPB_ImageDataTrusted* GetTrustedInterface(); + + // Returns the image data format used by the browser. If the plugin uses the + // same format, there is no conversion. Otherwise the browser will be in + // charge of converting from a supported format to its native format. + static PP_ImageDataFormat GetNativeImageDataFormat(); + + // Returns true if the format is supported by the browser. + static bool IsImageDataFormatSupported(PP_ImageDataFormat format); + + // Resource overrides. + virtual PPB_ImageData_Impl* AsPPB_ImageData_Impl(); + + // PPB_ImageData implementation. + bool Init(PP_ImageDataFormat format, + int width, int height, + bool init_to_zero); + void Describe(PP_ImageDataDesc* desc) const; + void* Map(); + void Unmap(); + + // PPB_ImageDataTrusted implementation. + int GetSharedMemoryHandle(uint32* byte_count) const; + + // The mapped bitmap and canvas will be NULL if the image is not mapped. + skia::PlatformCanvas* mapped_canvas() const { return mapped_canvas_.get(); } + const SkBitmap* GetMappedBitmap() const; + + // Swaps the guts of this image data with another. + void Swap(PPB_ImageData_Impl* other); + + private: + // This will be NULL before initialization, and if this PPB_ImageData_Impl is + // swapped with another. + scoped_ptr<PluginDelegate::PlatformImage2D> platform_image_; + + // When the device is mapped, this is the image. Null when umapped. + scoped_ptr<skia::PlatformCanvas> mapped_canvas_; + + PP_ImageDataFormat format_; + int width_; + int height_; + + DISALLOW_COPY_AND_ASSIGN(PPB_ImageData_Impl); +}; + +// Manages mapping an image resource if necessary. Use this to ensure the +// image is mapped. The destructor will put the image back into the previous +// state. You must check is_valid() to make sure the image was successfully +// mapped before using it. +// +// Example: +// ImageDataAutoMapper mapper(image_data); +// if (!mapper.is_valid()) +// return utter_failure; +// image_data->mapped_canvas()->blah(); // Guaranteed valid. +class ImageDataAutoMapper { + public: + ImageDataAutoMapper(PPB_ImageData_Impl* image_data) + : image_data_(image_data) { + if (image_data_->is_mapped()) { + is_valid_ = true; + needs_unmap_ = false; + } else { + is_valid_ = needs_unmap_ = !!image_data_->Map(); + } + } + + ~ImageDataAutoMapper() { + if (needs_unmap_) + image_data_->Unmap(); + } + + // Check this to see if the image was successfully mapped. If this is false, + // the image could not be mapped and is unusable. + bool is_valid() const { return is_valid_; } + + private: + PPB_ImageData_Impl* image_data_; + bool is_valid_; + bool needs_unmap_; + + DISALLOW_COPY_AND_ASSIGN(ImageDataAutoMapper); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_IMAGE_DATA_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_open_gl_es_impl.cc b/webkit/plugins/ppapi/ppb_open_gl_es_impl.cc new file mode 100644 index 0000000..8d64168 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_open_gl_es_impl.cc @@ -0,0 +1,673 @@ +// 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. + +// This file is auto-generated. DO NOT EDIT! + +#include "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" + +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "ppapi/c/dev/ppb_opengles_dev.h" + +namespace webkit { +namespace ppapi { + +namespace { + +void ActiveTexture(GLenum texture) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ActiveTexture(texture); +} +void AttachShader(GLuint program, GLuint shader) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->AttachShader(program, shader); +} +void BindAttribLocation(GLuint program, GLuint index, const char* name) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BindAttribLocation(program, index, name); +} +void BindBuffer(GLenum target, GLuint buffer) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BindBuffer(target, buffer); +} +void BindFramebuffer(GLenum target, GLuint framebuffer) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BindFramebuffer(target, framebuffer); +} +void BindRenderbuffer(GLenum target, GLuint renderbuffer) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BindRenderbuffer(target, renderbuffer); +} +void BindTexture(GLenum target, GLuint texture) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BindTexture(target, texture); +} +void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BlendColor(red, green, blue, alpha); +} +void BlendEquation(GLenum mode) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BlendEquation(mode); +} +void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BlendEquationSeparate(modeRGB, modeAlpha); +} +void BlendFunc(GLenum sfactor, GLenum dfactor) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BlendFunc(sfactor, dfactor); +} +void BlendFuncSeparate( + GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BlendFuncSeparate( + srcRGB, dstRGB, srcAlpha, dstAlpha); +} +void BufferData( + GLenum target, GLsizeiptr size, const void* data, GLenum usage) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BufferData(target, size, data, usage); +} +void BufferSubData( + GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->BufferSubData(target, offset, size, data); +} +GLenum CheckFramebufferStatus(GLenum target) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->CheckFramebufferStatus(target); +} +void Clear(GLbitfield mask) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Clear(mask); +} +void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ClearColor(red, green, blue, alpha); +} +void ClearDepthf(GLclampf depth) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ClearDepthf(depth); +} +void ClearStencil(GLint s) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ClearStencil(s); +} +void ColorMask( + GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ColorMask(red, green, blue, alpha); +} +void CompileShader(GLuint shader) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->CompileShader(shader); +} +void CompressedTexImage2D( + GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, const void* data) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->CompressedTexImage2D( + target, level, internalformat, width, height, border, imageSize, data); +} +void CompressedTexSubImage2D( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLenum format, GLsizei imageSize, const void* data) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->CompressedTexSubImage2D( + target, level, xoffset, yoffset, width, height, format, imageSize, data); +} +void CopyTexImage2D( + GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->CopyTexImage2D( + target, level, internalformat, x, y, width, height, border); +} +void CopyTexSubImage2D( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, + GLsizei width, GLsizei height) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->CopyTexSubImage2D( + target, level, xoffset, yoffset, x, y, width, height); +} +GLuint CreateProgram() { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->CreateProgram(); +} +GLuint CreateShader(GLenum type) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->CreateShader(type); +} +void CullFace(GLenum mode) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->CullFace(mode); +} +void DeleteBuffers(GLsizei n, const GLuint* buffers) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DeleteBuffers(n, buffers); +} +void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DeleteFramebuffers(n, framebuffers); +} +void DeleteProgram(GLuint program) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DeleteProgram(program); +} +void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DeleteRenderbuffers(n, renderbuffers); +} +void DeleteShader(GLuint shader) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DeleteShader(shader); +} +void DeleteTextures(GLsizei n, const GLuint* textures) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DeleteTextures(n, textures); +} +void DepthFunc(GLenum func) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DepthFunc(func); +} +void DepthMask(GLboolean flag) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DepthMask(flag); +} +void DepthRangef(GLclampf zNear, GLclampf zFar) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DepthRangef(zNear, zFar); +} +void DetachShader(GLuint program, GLuint shader) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DetachShader(program, shader); +} +void Disable(GLenum cap) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Disable(cap); +} +void DisableVertexAttribArray(GLuint index) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DisableVertexAttribArray(index); +} +void DrawArrays(GLenum mode, GLint first, GLsizei count) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DrawArrays(mode, first, count); +} +void DrawElements( + GLenum mode, GLsizei count, GLenum type, const void* indices) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->DrawElements(mode, count, type, indices); +} +void Enable(GLenum cap) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Enable(cap); +} +void EnableVertexAttribArray(GLuint index) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->EnableVertexAttribArray(index); +} +void Finish() { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Finish(); +} +void Flush() { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Flush(); +} +void FramebufferRenderbuffer( + GLenum target, GLenum attachment, GLenum renderbuffertarget, + GLuint renderbuffer) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->FramebufferRenderbuffer( + target, attachment, renderbuffertarget, renderbuffer); +} +void FramebufferTexture2D( + GLenum target, GLenum attachment, GLenum textarget, GLuint texture, + GLint level) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->FramebufferTexture2D( + target, attachment, textarget, texture, level); +} +void FrontFace(GLenum mode) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->FrontFace(mode); +} +void GenBuffers(GLsizei n, GLuint* buffers) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GenBuffers(n, buffers); +} +void GenerateMipmap(GLenum target) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GenerateMipmap(target); +} +void GenFramebuffers(GLsizei n, GLuint* framebuffers) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GenFramebuffers(n, framebuffers); +} +void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GenRenderbuffers(n, renderbuffers); +} +void GenTextures(GLsizei n, GLuint* textures) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GenTextures(n, textures); +} +void GetActiveAttrib( + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, + GLenum* type, char* name) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetActiveAttrib( + program, index, bufsize, length, size, type, name); +} +void GetActiveUniform( + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, + GLenum* type, char* name) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetActiveUniform( + program, index, bufsize, length, size, type, name); +} +void GetAttachedShaders( + GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetAttachedShaders( + program, maxcount, count, shaders); +} +GLint GetAttribLocation(GLuint program, const char* name) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->GetAttribLocation(program, name); +} +void GetBooleanv(GLenum pname, GLboolean* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetBooleanv(pname, params); +} +void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetBufferParameteriv( + target, pname, params); +} +GLenum GetError() { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->GetError(); +} +void GetFloatv(GLenum pname, GLfloat* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetFloatv(pname, params); +} +void GetFramebufferAttachmentParameteriv( + GLenum target, GLenum attachment, GLenum pname, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetFramebufferAttachmentParameteriv( + target, attachment, pname, params); +} +void GetIntegerv(GLenum pname, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetIntegerv(pname, params); +} +void GetProgramiv(GLuint program, GLenum pname, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetProgramiv(program, pname, params); +} +void GetProgramInfoLog( + GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetProgramInfoLog( + program, bufsize, length, infolog); +} +void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetRenderbufferParameteriv( + target, pname, params); +} +void GetShaderiv(GLuint shader, GLenum pname, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetShaderiv(shader, pname, params); +} +void GetShaderInfoLog( + GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetShaderInfoLog( + shader, bufsize, length, infolog); +} +void GetShaderPrecisionFormat( + GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetShaderPrecisionFormat( + shadertype, precisiontype, range, precision); +} +void GetShaderSource( + GLuint shader, GLsizei bufsize, GLsizei* length, char* source) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetShaderSource( + shader, bufsize, length, source); +} +const GLubyte* GetString(GLenum name) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->GetString(name); +} +void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetTexParameterfv(target, pname, params); +} +void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetTexParameteriv(target, pname, params); +} +void GetUniformfv(GLuint program, GLint location, GLfloat* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetUniformfv(program, location, params); +} +void GetUniformiv(GLuint program, GLint location, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetUniformiv(program, location, params); +} +GLint GetUniformLocation(GLuint program, const char* name) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->GetUniformLocation(program, name); +} +void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetVertexAttribfv(index, pname, params); +} +void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetVertexAttribiv(index, pname, params); +} +void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->GetVertexAttribPointerv( + index, pname, pointer); +} +void Hint(GLenum target, GLenum mode) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Hint(target, mode); +} +GLboolean IsBuffer(GLuint buffer) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->IsBuffer(buffer); +} +GLboolean IsEnabled(GLenum cap) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->IsEnabled(cap); +} +GLboolean IsFramebuffer(GLuint framebuffer) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->IsFramebuffer(framebuffer); +} +GLboolean IsProgram(GLuint program) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->IsProgram(program); +} +GLboolean IsRenderbuffer(GLuint renderbuffer) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->IsRenderbuffer(renderbuffer); +} +GLboolean IsShader(GLuint shader) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->IsShader(shader); +} +GLboolean IsTexture(GLuint texture) { + return PPB_Graphics3D_Impl::GetCurrent()->impl()->IsTexture(texture); +} +void LineWidth(GLfloat width) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->LineWidth(width); +} +void LinkProgram(GLuint program) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->LinkProgram(program); +} +void PixelStorei(GLenum pname, GLint param) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->PixelStorei(pname, param); +} +void PolygonOffset(GLfloat factor, GLfloat units) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->PolygonOffset(factor, units); +} +void ReadPixels( + GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, + void* pixels) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ReadPixels( + x, y, width, height, format, type, pixels); +} +void ReleaseShaderCompiler() { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ReleaseShaderCompiler(); +} +void RenderbufferStorage( + GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->RenderbufferStorage( + target, internalformat, width, height); +} +void SampleCoverage(GLclampf value, GLboolean invert) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->SampleCoverage(value, invert); +} +void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Scissor(x, y, width, height); +} +void ShaderBinary( + GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, + GLsizei length) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ShaderBinary( + n, shaders, binaryformat, binary, length); +} +void ShaderSource( + GLuint shader, GLsizei count, const char** str, const GLint* length) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ShaderSource(shader, count, str, length); +} +void StencilFunc(GLenum func, GLint ref, GLuint mask) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->StencilFunc(func, ref, mask); +} +void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->StencilFuncSeparate(face, func, ref, mask); +} +void StencilMask(GLuint mask) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->StencilMask(mask); +} +void StencilMaskSeparate(GLenum face, GLuint mask) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->StencilMaskSeparate(face, mask); +} +void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->StencilOp(fail, zfail, zpass); +} +void StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->StencilOpSeparate( + face, fail, zfail, zpass); +} +void TexImage2D( + GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLint border, GLenum format, GLenum type, + const void* pixels) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->TexImage2D( + target, level, internalformat, width, height, border, format, type, + pixels); +} +void TexParameterf(GLenum target, GLenum pname, GLfloat param) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->TexParameterf(target, pname, param); +} +void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->TexParameterfv(target, pname, params); +} +void TexParameteri(GLenum target, GLenum pname, GLint param) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->TexParameteri(target, pname, param); +} +void TexParameteriv(GLenum target, GLenum pname, const GLint* params) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->TexParameteriv(target, pname, params); +} +void TexSubImage2D( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLenum format, GLenum type, const void* pixels) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->TexSubImage2D( + target, level, xoffset, yoffset, width, height, format, type, pixels); +} +void Uniform1f(GLint location, GLfloat x) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform1f(location, x); +} +void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform1fv(location, count, v); +} +void Uniform1i(GLint location, GLint x) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform1i(location, x); +} +void Uniform1iv(GLint location, GLsizei count, const GLint* v) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform1iv(location, count, v); +} +void Uniform2f(GLint location, GLfloat x, GLfloat y) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform2f(location, x, y); +} +void Uniform2fv(GLint location, GLsizei count, const GLfloat* v) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform2fv(location, count, v); +} +void Uniform2i(GLint location, GLint x, GLint y) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform2i(location, x, y); +} +void Uniform2iv(GLint location, GLsizei count, const GLint* v) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform2iv(location, count, v); +} +void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform3f(location, x, y, z); +} +void Uniform3fv(GLint location, GLsizei count, const GLfloat* v) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform3fv(location, count, v); +} +void Uniform3i(GLint location, GLint x, GLint y, GLint z) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform3i(location, x, y, z); +} +void Uniform3iv(GLint location, GLsizei count, const GLint* v) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform3iv(location, count, v); +} +void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform4f(location, x, y, z, w); +} +void Uniform4fv(GLint location, GLsizei count, const GLfloat* v) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform4fv(location, count, v); +} +void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform4i(location, x, y, z, w); +} +void Uniform4iv(GLint location, GLsizei count, const GLint* v) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Uniform4iv(location, count, v); +} +void UniformMatrix2fv( + GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->UniformMatrix2fv( + location, count, transpose, value); +} +void UniformMatrix3fv( + GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->UniformMatrix3fv( + location, count, transpose, value); +} +void UniformMatrix4fv( + GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->UniformMatrix4fv( + location, count, transpose, value); +} +void UseProgram(GLuint program) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->UseProgram(program); +} +void ValidateProgram(GLuint program) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->ValidateProgram(program); +} +void VertexAttrib1f(GLuint indx, GLfloat x) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttrib1f(indx, x); +} +void VertexAttrib1fv(GLuint indx, const GLfloat* values) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttrib1fv(indx, values); +} +void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttrib2f(indx, x, y); +} +void VertexAttrib2fv(GLuint indx, const GLfloat* values) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttrib2fv(indx, values); +} +void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttrib3f(indx, x, y, z); +} +void VertexAttrib3fv(GLuint indx, const GLfloat* values) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttrib3fv(indx, values); +} +void VertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttrib4f(indx, x, y, z, w); +} +void VertexAttrib4fv(GLuint indx, const GLfloat* values) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttrib4fv(indx, values); +} +void VertexAttribPointer( + GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, + const void* ptr) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->VertexAttribPointer( + indx, size, type, normalized, stride, ptr); +} +void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) { + PPB_Graphics3D_Impl::GetCurrent()->impl()->Viewport(x, y, width, height); +} +void SwapBuffers() { + PPB_Graphics3D_Impl::GetCurrent()->impl()->SwapBuffers(); +} + +const struct PPB_OpenGLES_Dev ppb_opengles = { + &ActiveTexture, + &AttachShader, + &BindAttribLocation, + &BindBuffer, + &BindFramebuffer, + &BindRenderbuffer, + &BindTexture, + &BlendColor, + &BlendEquation, + &BlendEquationSeparate, + &BlendFunc, + &BlendFuncSeparate, + &BufferData, + &BufferSubData, + &CheckFramebufferStatus, + &Clear, + &ClearColor, + &ClearDepthf, + &ClearStencil, + &ColorMask, + &CompileShader, + &CompressedTexImage2D, + &CompressedTexSubImage2D, + &CopyTexImage2D, + &CopyTexSubImage2D, + &CreateProgram, + &CreateShader, + &CullFace, + &DeleteBuffers, + &DeleteFramebuffers, + &DeleteProgram, + &DeleteRenderbuffers, + &DeleteShader, + &DeleteTextures, + &DepthFunc, + &DepthMask, + &DepthRangef, + &DetachShader, + &Disable, + &DisableVertexAttribArray, + &DrawArrays, + &DrawElements, + &Enable, + &EnableVertexAttribArray, + &Finish, + &Flush, + &FramebufferRenderbuffer, + &FramebufferTexture2D, + &FrontFace, + &GenBuffers, + &GenerateMipmap, + &GenFramebuffers, + &GenRenderbuffers, + &GenTextures, + &GetActiveAttrib, + &GetActiveUniform, + &GetAttachedShaders, + &GetAttribLocation, + &GetBooleanv, + &GetBufferParameteriv, + &GetError, + &GetFloatv, + &GetFramebufferAttachmentParameteriv, + &GetIntegerv, + &GetProgramiv, + &GetProgramInfoLog, + &GetRenderbufferParameteriv, + &GetShaderiv, + &GetShaderInfoLog, + &GetShaderPrecisionFormat, + &GetShaderSource, + &GetString, + &GetTexParameterfv, + &GetTexParameteriv, + &GetUniformfv, + &GetUniformiv, + &GetUniformLocation, + &GetVertexAttribfv, + &GetVertexAttribiv, + &GetVertexAttribPointerv, + &Hint, + &IsBuffer, + &IsEnabled, + &IsFramebuffer, + &IsProgram, + &IsRenderbuffer, + &IsShader, + &IsTexture, + &LineWidth, + &LinkProgram, + &PixelStorei, + &PolygonOffset, + &ReadPixels, + &ReleaseShaderCompiler, + &RenderbufferStorage, + &SampleCoverage, + &Scissor, + &ShaderBinary, + &ShaderSource, + &StencilFunc, + &StencilFuncSeparate, + &StencilMask, + &StencilMaskSeparate, + &StencilOp, + &StencilOpSeparate, + &TexImage2D, + &TexParameterf, + &TexParameterfv, + &TexParameteri, + &TexParameteriv, + &TexSubImage2D, + &Uniform1f, + &Uniform1fv, + &Uniform1i, + &Uniform1iv, + &Uniform2f, + &Uniform2fv, + &Uniform2i, + &Uniform2iv, + &Uniform3f, + &Uniform3fv, + &Uniform3i, + &Uniform3iv, + &Uniform4f, + &Uniform4fv, + &Uniform4i, + &Uniform4iv, + &UniformMatrix2fv, + &UniformMatrix3fv, + &UniformMatrix4fv, + &UseProgram, + &ValidateProgram, + &VertexAttrib1f, + &VertexAttrib1fv, + &VertexAttrib2f, + &VertexAttrib2fv, + &VertexAttrib3f, + &VertexAttrib3fv, + &VertexAttrib4f, + &VertexAttrib4fv, + &VertexAttribPointer, + &Viewport, + &SwapBuffers +}; + +} // namespace + +const PPB_OpenGLES_Dev* PPB_Graphics3D_Impl::GetOpenGLESInterface() { + return &ppb_opengles; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_pdf.h b/webkit/plugins/ppapi/ppb_pdf.h new file mode 100644 index 0000000..38d1763 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_pdf.h @@ -0,0 +1,135 @@ +// 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 WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_ +#define WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_ + +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" + +#define PPB_PDF_INTERFACE "PPB_PDF;1" + +// From the public PPB_Font_Dev file. +struct PP_FontDescription_Dev; + +typedef enum { + PP_RESOURCESTRING_PDFGETPASSWORD = 0, + PP_RESOURCESTRING_PDFLOADING = 1, + PP_RESOURCESTRING_PDFLOAD_FAILED = 2, +} PP_ResourceString; + +typedef enum { + PP_RESOURCEIMAGE_PDF_BUTTON_FTH = 0, + PP_RESOURCEIMAGE_PDF_BUTTON_FTH_HOVER = 1, + PP_RESOURCEIMAGE_PDF_BUTTON_FTH_PRESSED = 2, + PP_RESOURCEIMAGE_PDF_BUTTON_FTW = 3, + PP_RESOURCEIMAGE_PDF_BUTTON_FTW_HOVER = 4, + PP_RESOURCEIMAGE_PDF_BUTTON_FTW_PRESSED = 5, + PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN = 6, + PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_HOVER = 7, + PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_PRESSED = 8, + PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT = 9, + PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_HOVER = 10, + PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_PRESSED = 11, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_0 = 12, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_1 = 13, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_2 = 14, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_3 = 15, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_4 = 16, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_5 = 17, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_6 = 18, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_7 = 19, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_8 = 20, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_9 = 21, + PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_NUM_BACKGROUND = 22, +} PP_ResourceImage; + +typedef enum { + PP_PRIVATEFONTCHARSET_ANSI = 0, + PP_PRIVATEFONTCHARSET_DEFAULT = 1, + PP_PRIVATEFONTCHARSET_SYMBOL = 2, + PP_PRIVATEFONTCHARSET_MAC = 77, + PP_PRIVATEFONTCHARSET_SHIFTJIS = 128, + PP_PRIVATEFONTCHARSET_HANGUL = 129, + PP_PRIVATEFONTCHARSET_JOHAB = 130, + PP_PRIVATEFONTCHARSET_GB2312 =134, + PP_PRIVATEFONTCHARSET_CHINESEBIG5 = 136, + PP_PRIVATEFONTCHARSET_GREEK = 161, + PP_PRIVATEFONTCHARSET_TURKISH = 162, + PP_PRIVATEFONTCHARSET_VIETNAMESE = 163, + PP_PRIVATEFONTCHARSET_HEBREW = 177, + PP_PRIVATEFONTCHARSET_ARABIC = 178, + PP_PRIVATEFONTCHARSET_BALTIC = 186, + PP_PRIVATEFONTCHARSET_RUSSIAN = 204, + PP_PRIVATEFONTCHARSET_THAI = 222, + PP_PRIVATEFONTCHARSET_EASTEUROPE = 238, + PP_PRIVATEFONTCHARSET_OEM = 255 +} PP_PrivateFontCharset; + +struct PP_PrivateFontFileDescription { + const char* face; + uint32_t weight; + bool italic; +}; + +struct PP_PrivateFindResult { + int start_index; + int length; +}; + +struct PPB_PDF { + // Returns a localized string. + PP_Var (*GetLocalizedString)(PP_Module module, PP_ResourceString string_id); + + // Returns a resource image. + PP_Resource (*GetResourceImage)(PP_Module module, + PP_ResourceImage image_id); + + // Returns a resource identifying a font file corresponding to the given font + // request after applying the browser-specific fallback. + // + // Currently Linux-only. + PP_Resource (*GetFontFileWithFallback)( + PP_Module module, + const PP_FontDescription_Dev* description, + PP_PrivateFontCharset charset); + + // Given a resource previously returned by GetFontFileWithFallback, returns + // a pointer to the requested font table. Linux only. + bool (*GetFontTableForPrivateFontFile)(PP_Resource font_file, + uint32_t table, + void* output, + uint32_t* output_length); + + // Search the given string using ICU. Use PPB_Core's MemFree on results when + // done. + void (*SearchString)( + PP_Module module, + const unsigned short* string, + const unsigned short* term, + bool case_sensitive, + PP_PrivateFindResult** results, + int* count); + + // Since WebFrame doesn't know about PPAPI requests, it'll think the page has + // finished loading even if there are outstanding requests by the plugin. + // Take this out once WebFrame knows about requests by PPAPI plugins. + void (*DidStartLoading)(PP_Instance instance); + void (*DidStopLoading)(PP_Instance instance); + + // Sets content restriction for a full-page plugin (i.e. can't copy/print). + // The value is a bitfield of ContentRestriction enums. + void (*SetContentRestriction)(PP_Instance instance, int restrictions); + + // Use UMA so we know average pdf page count. + void (*HistogramPDFPageCount)(int count); + + // Notifies the browser that the given action has been performed. + void (*UserMetricsRecordAction)(PP_Var action); +}; + +#endif // WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_ diff --git a/webkit/plugins/ppapi/ppb_pdf_impl.cc b/webkit/plugins/ppapi/ppb_pdf_impl.cc new file mode 100644 index 0000000..4d4721f --- /dev/null +++ b/webkit/plugins/ppapi/ppb_pdf_impl.cc @@ -0,0 +1,302 @@ +// 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 "webkit/plugins/ppapi/ppb_pdf_impl.h" + +#include "app/resource_bundle.h" +#include "base/metrics/histogram.h" +#include "base/utf_string_conversions.h" +#include "build/build_config.h" +#include "grit/webkit_resources.h" +#include "grit/webkit_strings.h" +#include "skia/ext/platform_canvas.h" +#include "ppapi/c/pp_resource.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/icu/public/i18n/unicode/usearch.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" +#include "webkit/plugins/ppapi/ppb_pdf.h" +#include "webkit/plugins/ppapi/var.h" + +namespace webkit { +namespace ppapi { + +#if defined(OS_LINUX) +class PrivateFontFile : public Resource { + public: + PrivateFontFile(PluginModule* module, int fd) + : Resource(module), + fd_(fd) { + } + virtual ~PrivateFontFile() { + } + + // Resource overrides. + PrivateFontFile* AsPrivateFontFile() { return this; } + + bool GetFontTable(uint32_t table, + void* output, + uint32_t* output_length); + + private: + int fd_; +}; +#endif + +namespace { + +struct ResourceImageInfo { + PP_ResourceImage pp_id; + int res_id; +}; + +static const ResourceImageInfo kResourceImageMap[] = { + { PP_RESOURCEIMAGE_PDF_BUTTON_FTH, IDR_PDF_BUTTON_FTH }, + { PP_RESOURCEIMAGE_PDF_BUTTON_FTH_HOVER, IDR_PDF_BUTTON_FTH_HOVER }, + { PP_RESOURCEIMAGE_PDF_BUTTON_FTH_PRESSED, IDR_PDF_BUTTON_FTH_PRESSED }, + { PP_RESOURCEIMAGE_PDF_BUTTON_FTW, IDR_PDF_BUTTON_FTW }, + { PP_RESOURCEIMAGE_PDF_BUTTON_FTW_HOVER, IDR_PDF_BUTTON_FTW_HOVER }, + { PP_RESOURCEIMAGE_PDF_BUTTON_FTW_PRESSED, IDR_PDF_BUTTON_FTW_PRESSED }, + { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN, IDR_PDF_BUTTON_ZOOMIN }, + { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_HOVER, IDR_PDF_BUTTON_ZOOMIN_HOVER }, + { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_PRESSED, IDR_PDF_BUTTON_ZOOMIN_PRESSED }, + { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT, IDR_PDF_BUTTON_ZOOMOUT }, + { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_HOVER, IDR_PDF_BUTTON_ZOOMOUT_HOVER }, + { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_PRESSED, + IDR_PDF_BUTTON_ZOOMOUT_PRESSED }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_0, IDR_PDF_THUMBNAIL_0 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_1, IDR_PDF_THUMBNAIL_1 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_2, IDR_PDF_THUMBNAIL_2 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_3, IDR_PDF_THUMBNAIL_3 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_4, IDR_PDF_THUMBNAIL_4 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_5, IDR_PDF_THUMBNAIL_5 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_6, IDR_PDF_THUMBNAIL_6 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_7, IDR_PDF_THUMBNAIL_7 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_8, IDR_PDF_THUMBNAIL_8 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_9, IDR_PDF_THUMBNAIL_9 }, + { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_NUM_BACKGROUND, + IDR_PDF_THUMBNAIL_NUM_BACKGROUND }, +}; + +PP_Var GetLocalizedString(PP_Module module_id, PP_ResourceString string_id) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return PP_MakeUndefined(); + + std::string rv; + if (string_id == PP_RESOURCESTRING_PDFGETPASSWORD) { + rv = UTF16ToUTF8(webkit_glue::GetLocalizedString(IDS_PDF_NEED_PASSWORD)); + } else if (string_id == PP_RESOURCESTRING_PDFLOADING) { + rv = UTF16ToUTF8(webkit_glue::GetLocalizedString(IDS_PDF_PAGE_LOADING)); + } else if (string_id == PP_RESOURCESTRING_PDFLOAD_FAILED) { + rv = UTF16ToUTF8(webkit_glue::GetLocalizedString(IDS_PDF_PAGE_LOAD_FAILED)); + } else { + NOTREACHED(); + } + + return StringVar::StringToPPVar(module, rv); +} + +PP_Resource GetResourceImage(PP_Module module_id, PP_ResourceImage image_id) { + int res_id = 0; + for (size_t i = 0; i < arraysize(kResourceImageMap); ++i) { + if (kResourceImageMap[i].pp_id == image_id) { + res_id = kResourceImageMap[i].res_id; + break; + } + } + if (res_id == 0) + return 0; + + SkBitmap* res_bitmap = + ResourceBundle::GetSharedInstance().GetBitmapNamed(res_id); + + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + scoped_refptr<PPB_ImageData_Impl> image_data(new PPB_ImageData_Impl(module)); + if (!image_data->Init(PPB_ImageData_Impl::GetNativeImageDataFormat(), + res_bitmap->width(), res_bitmap->height(), false)) { + return 0; + } + + ImageDataAutoMapper mapper(image_data); + if (!mapper.is_valid()) + return 0; + + skia::PlatformCanvas* canvas = image_data->mapped_canvas(); + SkBitmap& ret_bitmap = + const_cast<SkBitmap&>(canvas->getTopPlatformDevice().accessBitmap(true)); + if (!res_bitmap->copyTo(&ret_bitmap, SkBitmap::kARGB_8888_Config, NULL)) { + return 0; + } + + return image_data->GetReference(); +} + +PP_Resource GetFontFileWithFallback( + PP_Module module_id, + const PP_FontDescription_Dev* description, + PP_PrivateFontCharset charset) { +#if defined(OS_LINUX) + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + + scoped_refptr<StringVar> face_name(StringVar::FromPPVar(description->face)); + if (!face_name) + return 0; + + int fd = webkit_glue::MatchFontWithFallback( + face_name->value().c_str(), + description->weight >= PP_FONTWEIGHT_BOLD, + description->italic, + charset); + if (fd == -1) + return 0; + + scoped_refptr<PrivateFontFile> font(new PrivateFontFile(module, fd)); + + return font->GetReference(); +#else + // For trusted PPAPI plugins, this is only needed in Linux since font loading + // on Windows and Mac works through the renderer sandbox. + return 0; +#endif +} + +bool GetFontTableForPrivateFontFile(PP_Resource font_file, + uint32_t table, + void* output, + uint32_t* output_length) { +#if defined(OS_LINUX) + scoped_refptr<PrivateFontFile> font( + Resource::GetAs<PrivateFontFile>(font_file)); + if (!font.get()) + return false; + return font->GetFontTable(table, output, output_length); +#else + return false; +#endif +} + +void SearchString(PP_Module module, + const unsigned short* input_string, + const unsigned short* input_term, + bool case_sensitive, + PP_PrivateFindResult** results, + int* count) { + const char16* string = reinterpret_cast<const char16*>(input_string); + const char16* term = reinterpret_cast<const char16*>(input_term); + + UErrorCode status = U_ZERO_ERROR; + UStringSearch* searcher = usearch_open( + term, -1, string, -1, webkit_glue::GetWebKitLocale().c_str(), 0, + &status); + DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING || + status == U_USING_DEFAULT_WARNING); + UCollationStrength strength = case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY; + + UCollator* collator = usearch_getCollator(searcher); + if (ucol_getStrength(collator) != strength) { + ucol_setStrength(collator, strength); + usearch_reset(searcher); + } + + status = U_ZERO_ERROR; + int match_start = usearch_first(searcher, &status); + DCHECK(status == U_ZERO_ERROR); + + std::vector<PP_PrivateFindResult> pp_results; + while (match_start != USEARCH_DONE) { + size_t matched_length = usearch_getMatchedLength(searcher); + PP_PrivateFindResult result; + result.start_index = match_start; + result.length = matched_length; + pp_results.push_back(result); + match_start = usearch_next(searcher, &status); + DCHECK(status == U_ZERO_ERROR); + } + + *count = pp_results.size(); + if (*count) { + *results = reinterpret_cast<PP_PrivateFindResult*>( + malloc(*count * sizeof(PP_PrivateFindResult))); + memcpy(*results, &pp_results[0], *count * sizeof(PP_PrivateFindResult)); + } else { + *results = NULL; + } + + usearch_close(searcher); +} + +void DidStartLoading(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return; + instance->delegate()->DidStartLoading(); +} + +void DidStopLoading(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return; + instance->delegate()->DidStopLoading(); +} + +void SetContentRestriction(PP_Instance instance_id, int restrictions) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return; + instance->delegate()->SetContentRestriction(restrictions); +} + +void HistogramPDFPageCount(int count) { + UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count); +} + +void UserMetricsRecordAction(PP_Var action) { + scoped_refptr<StringVar> action_str(StringVar::FromPPVar(action)); + if (action_str) + webkit_glue::UserMetricsRecordAction(action_str->value()); +} + +const PPB_PDF ppb_pdf = { + &GetLocalizedString, + &GetResourceImage, + &GetFontFileWithFallback, + &GetFontTableForPrivateFontFile, + &SearchString, + &DidStartLoading, + &DidStopLoading, + &SetContentRestriction, + &HistogramPDFPageCount, + &UserMetricsRecordAction +}; + +} // namespace + +// static +const PPB_PDF* PPB_PDF_Impl::GetInterface() { + return &ppb_pdf; +} + +#if defined(OS_LINUX) +bool PrivateFontFile::GetFontTable(uint32_t table, + void* output, + uint32_t* output_length) { + size_t temp_size = static_cast<size_t>(*output_length); + bool rv = webkit_glue::GetFontTable( + fd_, table, static_cast<uint8_t*>(output), &temp_size); + *output_length = static_cast<uint32_t>(temp_size); + return rv; +} +#endif + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_pdf_impl.h b/webkit/plugins/ppapi/ppb_pdf_impl.h new file mode 100644 index 0000000..f630667 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_pdf_impl.h @@ -0,0 +1,25 @@ +// 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 WEBKIT_GLUE_PLUGINS_PPB_PDF_IMPL_H_ +#define WEBKIT_GLUE_PLUGINS_PPB_PDF_IMPL_H_ + +#include "webkit/plugins/ppapi/resource.h" + +struct PPB_PDF; + +namespace webkit { +namespace ppapi { + +class PPB_PDF_Impl { + public: + // Returns a pointer to the interface implementing PPB_PDF that is exposed + // to the plugin. + static const PPB_PDF* GetInterface(); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_GLUE_PLUGINS_PPB_PDF_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_scrollbar_impl.cc b/webkit/plugins/ppapi/ppb_scrollbar_impl.cc new file mode 100644 index 0000000..c436748 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_scrollbar_impl.cc @@ -0,0 +1,256 @@ +// 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 "webkit/plugins/ppapi/ppb_scrollbar_impl.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "ppapi/c/dev/ppp_scrollbar_dev.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebScrollbar.h" +#include "third_party/WebKit/WebKit/chromium/public/WebVector.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/event_conversion.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" +#include "webkit/glue/webkit_glue.h" + +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#endif + +using WebKit::WebInputEvent; +using WebKit::WebRect; +using WebKit::WebScrollbar; + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Resource Create(PP_Instance instance_id, PP_Bool vertical) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return 0; + + scoped_refptr<PPB_Scrollbar_Impl> scrollbar( + new PPB_Scrollbar_Impl(instance, PPBoolToBool(vertical))); + return scrollbar->GetReference(); +} + +PP_Bool IsScrollbar(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_Scrollbar_Impl>(resource)); +} + +uint32_t GetThickness() { + return WebScrollbar::defaultThickness(); +} + +uint32_t GetValue(PP_Resource resource) { + scoped_refptr<PPB_Scrollbar_Impl> scrollbar( + Resource::GetAs<PPB_Scrollbar_Impl>(resource)); + if (!scrollbar) + return 0; + return scrollbar->GetValue(); +} + +void SetValue(PP_Resource resource, uint32_t value) { + scoped_refptr<PPB_Scrollbar_Impl> scrollbar( + Resource::GetAs<PPB_Scrollbar_Impl>(resource)); + if (scrollbar) + scrollbar->SetValue(value); +} + +void SetDocumentSize(PP_Resource resource, uint32_t size) { + scoped_refptr<PPB_Scrollbar_Impl> scrollbar( + Resource::GetAs<PPB_Scrollbar_Impl>(resource)); + if (scrollbar) + scrollbar->SetDocumentSize(size); +} + +void SetTickMarks(PP_Resource resource, + const PP_Rect* tick_marks, + uint32_t count) { + scoped_refptr<PPB_Scrollbar_Impl> scrollbar( + Resource::GetAs<PPB_Scrollbar_Impl>(resource)); + if (scrollbar) + scrollbar->SetTickMarks(tick_marks, count); +} + +void ScrollBy(PP_Resource resource, PP_ScrollBy_Dev unit, int32_t multiplier) { + scoped_refptr<PPB_Scrollbar_Impl> scrollbar( + Resource::GetAs<PPB_Scrollbar_Impl>(resource)); + if (scrollbar) + scrollbar->ScrollBy(unit, multiplier); +} + +const PPB_Scrollbar_Dev ppb_scrollbar = { + &Create, + &IsScrollbar, + &GetThickness, + &GetValue, + &SetValue, + &SetDocumentSize, + &SetTickMarks, + &ScrollBy +}; + +} // namespace + +PPB_Scrollbar_Impl::PPB_Scrollbar_Impl(PluginInstance* instance, bool vertical) + : PPB_Widget_Impl(instance) { + scrollbar_.reset(WebScrollbar::create( + static_cast<WebKit::WebScrollbarClient*>(this), + vertical ? WebScrollbar::Vertical : WebScrollbar::Horizontal)); +} + +PPB_Scrollbar_Impl::~PPB_Scrollbar_Impl() { +} + +// static +const PPB_Scrollbar_Dev* PPB_Scrollbar_Impl::GetInterface() { + return &ppb_scrollbar; +} + +PPB_Scrollbar_Impl* PPB_Scrollbar_Impl::AsPPB_Scrollbar_Impl() { + return this; +} + +uint32_t PPB_Scrollbar_Impl::GetValue() { + return scrollbar_->value(); +} + +void PPB_Scrollbar_Impl::SetValue(uint32_t value) { + scrollbar_->setValue(value); +} + +void PPB_Scrollbar_Impl::SetDocumentSize(uint32_t size) { + scrollbar_->setDocumentSize(size); +} + +void PPB_Scrollbar_Impl::SetTickMarks(const PP_Rect* tick_marks, + uint32_t count) { + tickmarks_.resize(count); + for (uint32 i = 0; i < count; ++i) { + tickmarks_[i] = WebRect(tick_marks[i].point.x, + tick_marks[i].point.y, + tick_marks[i].size.width, + tick_marks[i].size.height);; + } + PP_Rect rect = location(); + Invalidate(&rect); +} + +void PPB_Scrollbar_Impl::ScrollBy(PP_ScrollBy_Dev unit, int32_t multiplier) { + WebScrollbar::ScrollDirection direction = multiplier >= 0 ? + WebScrollbar::ScrollForward : WebScrollbar::ScrollBackward; + float fmultiplier = 1.0; + + WebScrollbar::ScrollGranularity granularity; + if (unit == PP_SCROLLBY_LINE) { + granularity = WebScrollbar::ScrollByLine; + } else if (unit == PP_SCROLLBY_PAGE) { + granularity = WebScrollbar::ScrollByPage; + } else if (unit == PP_SCROLLBY_DOCUMENT) { + granularity = WebScrollbar::ScrollByDocument; + } else { + granularity = WebScrollbar::ScrollByPixel; + fmultiplier = static_cast<float>(multiplier); + if (fmultiplier < 0) + fmultiplier *= -1; + } + scrollbar_->scroll(direction, granularity, fmultiplier); +} + +bool PPB_Scrollbar_Impl::Paint(const PP_Rect* rect, PPB_ImageData_Impl* image) { + gfx::Rect gfx_rect(rect->point.x, + rect->point.y, + rect->size.width, + rect->size.height); + skia::PlatformCanvas* canvas = image->mapped_canvas(); + if (!canvas) + return false; + scrollbar_->paint(webkit_glue::ToWebCanvas(canvas), gfx_rect); + +#if defined(OS_WIN) + if (base::win::GetVersion() == base::win::VERSION_XP) { + canvas->getTopPlatformDevice().makeOpaque( + gfx_rect.x(), gfx_rect.y(), gfx_rect.width(), gfx_rect.height()); + } +#endif + + return true; +} + +bool PPB_Scrollbar_Impl::HandleEvent(const PP_InputEvent* event) { + scoped_ptr<WebInputEvent> web_input_event(CreateWebInputEvent(*event)); + if (!web_input_event.get()) + return false; + + return scrollbar_->handleInputEvent(*web_input_event.get()); +} + +void PPB_Scrollbar_Impl::SetLocationInternal(const PP_Rect* location) { + scrollbar_->setLocation(WebRect(location->point.x, + location->point.y, + location->size.width, + location->size.height)); +} + +void PPB_Scrollbar_Impl::valueChanged(WebKit::WebScrollbar* scrollbar) { + const PPP_Scrollbar_Dev* ppp_scrollbar = + static_cast<const PPP_Scrollbar_Dev*>( + module()->GetPluginInterface(PPP_SCROLLBAR_DEV_INTERFACE)); + if (!ppp_scrollbar) + return; + ScopedResourceId resource(this); + ppp_scrollbar->ValueChanged( + instance()->pp_instance(), resource.id, scrollbar_->value()); +} + +void PPB_Scrollbar_Impl::invalidateScrollbarRect( + WebKit::WebScrollbar* scrollbar, + const WebKit::WebRect& rect) { + gfx::Rect gfx_rect(rect.x, + rect.y, + rect.width, + rect.height); + dirty_ = dirty_.Union(gfx_rect); + // Can't call into the client to tell them about the invalidate right away, + // since the PPB_Scrollbar_Impl code is still in the middle of updating its + // internal state. + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &PPB_Scrollbar_Impl::NotifyInvalidate)); +} + +void PPB_Scrollbar_Impl::getTickmarks( + WebKit::WebScrollbar* scrollbar, + WebKit::WebVector<WebKit::WebRect>* tick_marks) const { + if (tickmarks_.empty()) { + WebRect* rects = NULL; + tick_marks->assign(rects, 0); + } else { + tick_marks->assign(&tickmarks_[0], tickmarks_.size()); + } +} + +void PPB_Scrollbar_Impl::NotifyInvalidate() { + if (dirty_.IsEmpty()) + return; + PP_Rect pp_rect; + pp_rect.point.x = dirty_.x(); + pp_rect.point.y = dirty_.y(); + pp_rect.size.width = dirty_.width(); + pp_rect.size.height = dirty_.height(); + dirty_ = gfx::Rect(); + Invalidate(&pp_rect); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_scrollbar_impl.h b/webkit/plugins/ppapi/ppb_scrollbar_impl.h new file mode 100644 index 0000000..532c05b --- /dev/null +++ b/webkit/plugins/ppapi/ppb_scrollbar_impl.h @@ -0,0 +1,67 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_SCROLLBAR_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_SCROLLBAR_IMPL_H_ + +#include <vector> + +#include "gfx/rect.h" +#include "ppapi/c/dev/ppb_scrollbar_dev.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebScrollbarClient.h" +#include "webkit/plugins/ppapi/ppb_widget_impl.h" + +namespace webkit { +namespace ppapi { + +class PluginInstance; + +class PPB_Scrollbar_Impl : public PPB_Widget_Impl, + public WebKit::WebScrollbarClient { + public: + PPB_Scrollbar_Impl(PluginInstance* instance, bool vertical); + virtual ~PPB_Scrollbar_Impl(); + + // Returns a pointer to the interface implementing PPB_Scrollbar that is + // exposed to the plugin. + static const PPB_Scrollbar_Dev* GetInterface(); + + // Resource overrides. + virtual PPB_Scrollbar_Impl* AsPPB_Scrollbar_Impl(); + + // PPB_Scrollbar implementation. + uint32_t GetValue(); + void SetValue(uint32_t value); + void SetDocumentSize(uint32_t size); + void SetTickMarks(const PP_Rect* tick_marks, uint32_t count); + void ScrollBy(PP_ScrollBy_Dev unit, int32_t multiplier); + + // PPB_Widget implementation. + virtual bool Paint(const PP_Rect* rect, PPB_ImageData_Impl* image); + virtual bool HandleEvent(const PP_InputEvent* event); + virtual void SetLocationInternal(const PP_Rect* location); + + private: + // WebKit::WebScrollbarClient implementation. + virtual void valueChanged(WebKit::WebScrollbar* scrollbar); + virtual void invalidateScrollbarRect(WebKit::WebScrollbar* scrollbar, + const WebKit::WebRect& rect); + virtual void getTickmarks( + WebKit::WebScrollbar* scrollbar, + WebKit::WebVector<WebKit::WebRect>* tick_marks) const; + + void NotifyInvalidate(); + + gfx::Rect dirty_; + std::vector<WebKit::WebRect> tickmarks_; + scoped_ptr<WebKit::WebScrollbar> scrollbar_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Scrollbar_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_SCROLLBAR_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_transport_impl.cc b/webkit/plugins/ppapi/ppb_transport_impl.cc new file mode 100644 index 0000000..bcd4f6a --- /dev/null +++ b/webkit/plugins/ppapi/ppb_transport_impl.cc @@ -0,0 +1,145 @@ +// 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 "webkit/plugins/ppapi/ppb_transport_impl.h" + +#include "base/singleton.h" +#include "base/thread_local.h" +#include "ppapi/c/dev/ppb_transport_dev.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +namespace webkit { +namespace ppapi { + +namespace { + +// Creates a new transport object with the specified name +// using the specified protocol. +PP_Resource CreateTransport(PP_Module module, + const char* name, + const char* proto) { + // TODO(juberti): implement me + PP_Resource p(0); + return p; +} + +// Returns whether or not resource is PPB_Transport_Impl +PP_Bool IsTransport(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_Transport_Impl>(resource)); +} + +// Returns whether the transport is currently writable +// (i.e. can send data to the remote peer) +PP_Bool IsWritable(PP_Resource transport) { + // TODO(juberti): impelement me + return PP_FALSE; +} + + +// TODO(juberti): other getters/setters +// connect state +// connect type, protocol +// RTT + + +// Establishes a connection to the remote peer. +// Returns PP_ERROR_WOULDBLOCK and notifies on |cb| +// when connectivity is established (or timeout occurs). +int32_t Connect(PP_Resource transport, + PP_CompletionCallback cb) { + // TODO(juberti): impelement me + return 0; +} + + +// Obtains another ICE candidate address to be provided +// to the remote peer. Returns PP_ERROR_WOULDBLOCK +// if there are no more addresses to be sent. +int32_t GetNextAddress(PP_Resource transport, + PP_Var* address, + PP_CompletionCallback cb) { + // TODO(juberti): implement me + return 0; +} + + +// Provides an ICE candidate address that was received +// from the remote peer. +int32_t ReceiveRemoteAddress(PP_Resource transport, + PP_Var address) { + // TODO(juberti): implement me + return 0; +} + + +// Like recv(), receives data. Returns PP_ERROR_WOULDBLOCK +// if there is currently no data to receive. +int32_t Recv(PP_Resource transport, + void* data, + uint32_t len, + PP_CompletionCallback cb) { + // TODO(juberti): implement me + return 0; +} + + +// Like send(), sends data. Returns PP_ERROR_WOULDBLOCK +// if the socket is currently flow-controlled. +int32_t Send(PP_Resource transport, + const void* data, + uint32_t len, + PP_CompletionCallback cb) { + // TODO(juberti): implement me + return 0; +} + + +// Disconnects from the remote peer. +int32_t Close(PP_Resource transport) { + // TODO(juberti): implement me + return 0; +} + + +const PPB_Transport_Dev ppb_transport = { + &CreateTransport, + &IsTransport, + &IsWritable, + &Connect, + &GetNextAddress, + &ReceiveRemoteAddress, + &Recv, + &Send, + &Close, +}; + +} // namespace + +PPB_Transport_Impl::PPB_Transport_Impl(PluginModule* module) + : Resource(module) { + // TODO(juberti): impl +} + +const PPB_Transport_Dev* PPB_Transport_Impl::GetInterface() { + return &ppb_transport; +} + +PPB_Transport_Impl::~PPB_Transport_Impl() { + // TODO(juberti): teardown +} + +PPB_Transport_Impl* PPB_Transport_Impl::AsPPB_Transport_Impl() { + return this; +} + +bool PPB_Transport_Impl::Init(const char* name, const char* proto) { + // TODO(juberti): impl + return false; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_transport_impl.h b/webkit/plugins/ppapi/ppb_transport_impl.h new file mode 100644 index 0000000..7a98a37 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_transport_impl.h @@ -0,0 +1,38 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_TRANSPORT_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_TRANSPORT_IMPL_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "ppapi/c/pp_instance.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PPB_Transport_Dev; + +namespace webkit { +namespace ppapi { + +class PPB_Transport_Impl : public Resource { + public: + explicit PPB_Transport_Impl(PluginModule* module); + virtual ~PPB_Transport_Impl(); + + static const PPB_Transport_Dev* GetInterface(); + virtual PPB_Transport_Impl* AsPPB_Transport_Impl(); + + bool Init(const char* name, + const char* proto); + + private: + DISALLOW_COPY_AND_ASSIGN(PPB_Transport_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_TRANSPORT_IMPL_H_ + diff --git a/webkit/plugins/ppapi/ppb_url_loader_impl.cc b/webkit/plugins/ppapi/ppb_url_loader_impl.cc new file mode 100644 index 0000000..14b91f8 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_url_loader_impl.cc @@ -0,0 +1,559 @@ +// 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 "webkit/plugins/ppapi/ppb_url_loader_impl.h" + +#include "base/logging.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_url_loader.h" +#include "ppapi/c/trusted/ppb_url_loader_trusted.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebElement.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebKit.h" +#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" +#include "webkit/appcache/web_application_cache_host_impl.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_url_request_info_impl.h" +#include "webkit/plugins/ppapi/ppb_url_response_info_impl.h" + +using appcache::WebApplicationCacheHostImpl; +using WebKit::WebFrame; +using WebKit::WebString; +using WebKit::WebURL; +using WebKit::WebURLError; +using WebKit::WebURLLoader; +using WebKit::WebURLRequest; +using WebKit::WebURLResponse; + +#ifdef _MSC_VER +// Do not warn about use of std::copy with raw pointers. +#pragma warning(disable : 4996) +#endif + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Resource Create(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return 0; + + PPB_URLLoader_Impl* loader = new PPB_URLLoader_Impl(instance, false); + return loader->GetReference(); +} + +PP_Bool IsURLLoader(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_URLLoader_Impl>(resource)); +} + +int32_t Open(PP_Resource loader_id, + PP_Resource request_id, + PP_CompletionCallback callback) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return PP_ERROR_BADRESOURCE; + + scoped_refptr<PPB_URLRequestInfo_Impl> request( + Resource::GetAs<PPB_URLRequestInfo_Impl>(request_id)); + if (!request) + return PP_ERROR_BADRESOURCE; + + return loader->Open(request, callback); +} + +int32_t FollowRedirect(PP_Resource loader_id, + PP_CompletionCallback callback) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return PP_ERROR_BADRESOURCE; + + return loader->FollowRedirect(callback); +} + +PP_Bool GetUploadProgress(PP_Resource loader_id, + int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return PP_FALSE; + + return BoolToPPBool(loader->GetUploadProgress(bytes_sent, + total_bytes_to_be_sent)); +} + +PP_Bool GetDownloadProgress(PP_Resource loader_id, + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return PP_FALSE; + + return BoolToPPBool(loader->GetDownloadProgress(bytes_received, + total_bytes_to_be_received)); +} + +PP_Resource GetResponseInfo(PP_Resource loader_id) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return 0; + + PPB_URLResponseInfo_Impl* response_info = loader->response_info(); + if (!response_info) + return 0; + + return response_info->GetReference(); +} + +int32_t ReadResponseBody(PP_Resource loader_id, + char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return PP_ERROR_BADRESOURCE; + + return loader->ReadResponseBody(buffer, bytes_to_read, callback); +} + +int32_t FinishStreamingToFile(PP_Resource loader_id, + PP_CompletionCallback callback) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return PP_ERROR_BADRESOURCE; + + return loader->FinishStreamingToFile(callback); +} + +void Close(PP_Resource loader_id) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return; + + loader->Close(); +} + +const PPB_URLLoader ppb_urlloader = { + &Create, + &IsURLLoader, + &Open, + &FollowRedirect, + &GetUploadProgress, + &GetDownloadProgress, + &GetResponseInfo, + &ReadResponseBody, + &FinishStreamingToFile, + &Close +}; + +void GrantUniversalAccess(PP_Resource loader_id) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return; + + loader->GrantUniversalAccess(); +} + +void SetStatusCallback(PP_Resource loader_id, + PP_URLLoaderTrusted_StatusCallback cb) { + scoped_refptr<PPB_URLLoader_Impl> loader( + Resource::GetAs<PPB_URLLoader_Impl>(loader_id)); + if (!loader) + return; + loader->SetStatusCallback(cb); +} + +const PPB_URLLoaderTrusted ppb_urlloadertrusted = { + &GrantUniversalAccess, + &SetStatusCallback +}; + +WebKit::WebFrame* GetFrame(PluginInstance* instance) { + return instance->container()->element().document().frame(); +} + +} // namespace + +PPB_URLLoader_Impl::PPB_URLLoader_Impl(PluginInstance* instance, + bool main_document_loader) + : Resource(instance->module()), + instance_(instance), + main_document_loader_(main_document_loader), + pending_callback_(), + bytes_sent_(0), + total_bytes_to_be_sent_(-1), + bytes_received_(0), + total_bytes_to_be_received_(-1), + user_buffer_(NULL), + user_buffer_size_(0), + done_status_(PP_ERROR_WOULDBLOCK), + has_universal_access_(false), + status_callback_(NULL) { + instance->AddObserver(this); +} + +PPB_URLLoader_Impl::~PPB_URLLoader_Impl() { + if (instance_) + instance_->RemoveObserver(this); +} + +// static +const PPB_URLLoader* PPB_URLLoader_Impl::GetInterface() { + return &ppb_urlloader; +} + +// static +const PPB_URLLoaderTrusted* PPB_URLLoader_Impl::GetTrustedInterface() { + return &ppb_urlloadertrusted; +} + +PPB_URLLoader_Impl* PPB_URLLoader_Impl::AsPPB_URLLoader_Impl() { + return this; +} + +int32_t PPB_URLLoader_Impl::Open(PPB_URLRequestInfo_Impl* request, + PP_CompletionCallback callback) { + if (loader_.get()) + return PP_ERROR_INPROGRESS; + + // We only support non-blocking calls. + if (!callback.func) + return PP_ERROR_BADARGUMENT; + + WebFrame* frame = GetFrame(instance_); + if (!frame) + return PP_ERROR_FAILED; + WebURLRequest web_request(request->ToWebURLRequest(frame)); + + int32_t rv = CanRequest(frame, web_request.url()); + if (rv != PP_OK) + return rv; + + frame->dispatchWillSendRequest(web_request); + + // Sets the appcache host id to allow retrieval from the appcache. + if (WebApplicationCacheHostImpl* appcache_host = + WebApplicationCacheHostImpl::FromFrame(frame)) { + appcache_host->willStartSubResourceRequest(web_request); + } + + loader_.reset(WebKit::webKitClient()->createURLLoader()); + if (!loader_.get()) + return PP_ERROR_FAILED; + + loader_->loadAsynchronously(web_request, this); + + request_info_ = scoped_refptr<PPB_URLRequestInfo_Impl>(request); + pending_callback_ = callback; + + // Notify completion when we receive a redirect or response headers. + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_URLLoader_Impl::FollowRedirect(PP_CompletionCallback callback) { + if (pending_callback_.func) + return PP_ERROR_INPROGRESS; + + // We only support non-blocking calls. + if (!callback.func) + return PP_ERROR_BADARGUMENT; + + WebURL redirect_url = GURL(response_info_->redirect_url()); + + int32_t rv = CanRequest(GetFrame(instance_), redirect_url); + if (rv != PP_OK) + return rv; + + pending_callback_ = callback; + loader_->setDefersLoading(false); // Allow the redirect to continue. + return PP_ERROR_WOULDBLOCK; +} + +bool PPB_URLLoader_Impl::GetUploadProgress(int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent) { + if (!RecordUploadProgress()) { + *bytes_sent = 0; + *total_bytes_to_be_sent = 0; + return false; + } + *bytes_sent = bytes_sent_; + *total_bytes_to_be_sent = total_bytes_to_be_sent_; + return true; +} + +bool PPB_URLLoader_Impl::GetDownloadProgress( + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) { + if (!RecordDownloadProgress()) { + *bytes_received = 0; + *total_bytes_to_be_received = 0; + return false; + } + *bytes_received = bytes_received_; + *total_bytes_to_be_received = total_bytes_to_be_received_; + return true; +} + +int32_t PPB_URLLoader_Impl::ReadResponseBody(char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) { + if (!response_info_ || response_info_->body()) + return PP_ERROR_FAILED; + if (bytes_to_read <= 0 || !buffer) + return PP_ERROR_BADARGUMENT; + if (pending_callback_.func) + return PP_ERROR_INPROGRESS; + + // We only support non-blocking calls. + if (!callback.func) + return PP_ERROR_BADARGUMENT; + + user_buffer_ = buffer; + user_buffer_size_ = bytes_to_read; + + if (!buffer_.empty()) + return FillUserBuffer(); + + // We may have already reached EOF. + if (done_status_ != PP_ERROR_WOULDBLOCK) { + user_buffer_ = NULL; + user_buffer_size_ = 0; + return done_status_; + } + + pending_callback_ = callback; + return PP_ERROR_WOULDBLOCK; +} + +int32_t PPB_URLLoader_Impl::FinishStreamingToFile( + PP_CompletionCallback callback) { + if (!response_info_ || !response_info_->body()) + return PP_ERROR_FAILED; + if (pending_callback_.func) + return PP_ERROR_INPROGRESS; + + // We may have already reached EOF. + if (done_status_ != PP_ERROR_WOULDBLOCK) + return done_status_; + + // Wait for didFinishLoading / didFail. + pending_callback_ = callback; + return PP_ERROR_WOULDBLOCK; +} + +void PPB_URLLoader_Impl::Close() { + if (loader_.get()) { + loader_->cancel(); + } else if (main_document_loader_) { + WebFrame* frame = instance_->container()->element().document().frame(); + frame->stopLoading(); + } +} + +void PPB_URLLoader_Impl::GrantUniversalAccess() { + has_universal_access_ = true; +} + +void PPB_URLLoader_Impl::SetStatusCallback( + PP_URLLoaderTrusted_StatusCallback cb) { + status_callback_ = cb; +} + +void PPB_URLLoader_Impl::willSendRequest( + WebURLLoader* loader, + WebURLRequest& new_request, + const WebURLResponse& redirect_response) { + if (!request_info_->follow_redirects()) { + SaveResponse(redirect_response); + loader_->setDefersLoading(true); + RunCallback(PP_OK); + } else { + int32_t rv = CanRequest(GetFrame(instance_), new_request.url()); + if (rv != PP_OK) { + loader_->setDefersLoading(true); + RunCallback(rv); + } + } +} + +void PPB_URLLoader_Impl::didSendData( + WebURLLoader* loader, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent) { + // TODO(darin): Bounds check input? + bytes_sent_ = static_cast<int64_t>(bytes_sent); + total_bytes_to_be_sent_ = static_cast<int64_t>(total_bytes_to_be_sent); + UpdateStatus(); +} + +void PPB_URLLoader_Impl::didReceiveResponse(WebURLLoader* loader, + const WebURLResponse& response) { + SaveResponse(response); + + // Sets -1 if the content length is unknown. + total_bytes_to_be_received_ = response.expectedContentLength(); + UpdateStatus(); + + RunCallback(PP_OK); +} + +void PPB_URLLoader_Impl::didDownloadData(WebURLLoader* loader, + int data_length) { + bytes_received_ += data_length; + UpdateStatus(); +} + +void PPB_URLLoader_Impl::didReceiveData(WebURLLoader* loader, + const char* data, + int data_length) { + bytes_received_ += data_length; + + buffer_.insert(buffer_.end(), data, data + data_length); + if (user_buffer_) { + RunCallback(FillUserBuffer()); + } else { + DCHECK(!pending_callback_.func); + } +} + +void PPB_URLLoader_Impl::didFinishLoading(WebURLLoader* loader, + double finish_time) { + done_status_ = PP_OK; + RunCallback(done_status_); +} + +void PPB_URLLoader_Impl::didFail(WebURLLoader* loader, + const WebURLError& error) { + // TODO(darin): Provide more detailed error information. + done_status_ = PP_ERROR_FAILED; + RunCallback(done_status_); +} + +void PPB_URLLoader_Impl::InstanceDestroyed(PluginInstance* instance) { + // When the instance is destroyed, we force delete any associated loads. + DCHECK(instance == instance_); + instance_ = NULL; + + // Normally the only ref to this class will be from the plugin which + // ForceDeletePluginResourceRefs will free. We don't want our object to be + // deleted out from under us until the function completes. + scoped_refptr<PPB_URLLoader_Impl> death_grip(this); + + // Force delete any plugin refs to us. If the instance is being deleted, we + // don't want to allow the requests to continue to use bandwidth and send us + // callbacks (for which we might have no plugin). + ResourceTracker *tracker = ResourceTracker::Get(); + PP_Resource loader_resource = GetReferenceNoAddRef(); + if (loader_resource) + tracker->ForceDeletePluginResourceRefs(loader_resource); + + // Also force free the response from the plugin, both the plugin's ref(s) + // and ours. + if (response_info_.get()) { + PP_Resource response_info_resource = response_info_->GetReferenceNoAddRef(); + if (response_info_resource) + tracker->ForceDeletePluginResourceRefs(response_info_resource); + response_info_ = NULL; + } + + // Free the WebKit request. + loader_.reset(); + + // Often, |this| will be deleted at the end of this function when death_grip + // goes out of scope. +} + +void PPB_URLLoader_Impl::RunCallback(int32_t result) { + if (!pending_callback_.func) + return; + + PP_CompletionCallback callback = {0}; + std::swap(callback, pending_callback_); + PP_RunCompletionCallback(&callback, result); +} + +size_t PPB_URLLoader_Impl::FillUserBuffer() { + DCHECK(user_buffer_); + DCHECK(user_buffer_size_); + + size_t bytes_to_copy = std::min(buffer_.size(), user_buffer_size_); + std::copy(buffer_.begin(), buffer_.begin() + bytes_to_copy, user_buffer_); + buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_to_copy); + + // Reset for next time. + user_buffer_ = NULL; + user_buffer_size_ = 0; + return bytes_to_copy; +} + +void PPB_URLLoader_Impl::SaveResponse(const WebKit::WebURLResponse& response) { + scoped_refptr<PPB_URLResponseInfo_Impl> response_info( + new PPB_URLResponseInfo_Impl(module())); + if (response_info->Initialize(response)) + response_info_ = response_info; +} + +// Checks that the client can request the URL. Returns a PPAPI error code. +int32_t PPB_URLLoader_Impl::CanRequest(const WebKit::WebFrame* frame, + const WebKit::WebURL& url) { + if (!has_universal_access_ && + !frame->securityOrigin().canRequest(url)) + return PP_ERROR_NOACCESS; + + return PP_OK; +} + +void PPB_URLLoader_Impl::UpdateStatus() { + if (status_callback_ && + (RecordDownloadProgress() || RecordUploadProgress())) { + PP_Resource pp_resource = GetReferenceNoAddRef(); + if (pp_resource) { + // The PP_Resource on the plugin will be NULL if the plugin has no + // reference to this object. That's fine, because then we don't need to + // call UpdateStatus. + // + // Here we go through some effort to only send the exact information that + // the requestor wanted in the request flags. It would be just as + // efficient to send all of it, but we don't want people to rely on + // getting download progress when they happen to set the upload progress + // flag. + status_callback_( + instance_->pp_instance(), pp_resource, + RecordUploadProgress() ? bytes_sent_ : -1, + RecordUploadProgress() ? total_bytes_to_be_sent_ : -1, + RecordDownloadProgress() ? bytes_received_ : -1, + RecordDownloadProgress() ? total_bytes_to_be_received_ : -1); + } + } +} + +bool PPB_URLLoader_Impl::RecordDownloadProgress() const { + return request_info_ && request_info_->record_download_progress(); +} + +bool PPB_URLLoader_Impl::RecordUploadProgress() const { + return request_info_ && request_info_->record_upload_progress(); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_url_loader_impl.h b/webkit/plugins/ppapi/ppb_url_loader_impl.h new file mode 100644 index 0000000..6b05adc --- /dev/null +++ b/webkit/plugins/ppapi/ppb_url_loader_impl.h @@ -0,0 +1,145 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_URL_LOADER_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_URL_LOADER_IMPL_H_ + +#include <deque> + +#include "base/scoped_ptr.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/trusted/ppb_url_loader_trusted.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PPB_URLLoader; +struct PPB_URLLoaderTrusted; + +namespace WebKit { +class WebFrame; +class WebURL; +} + +namespace webkit { +namespace ppapi { + +class PluginInstance; +class PPB_URLRequestInfo_Impl; +class PPB_URLResponseInfo_Impl; + +class PPB_URLLoader_Impl : public Resource, + public WebKit::WebURLLoaderClient, + public PluginInstance::Observer { + public: + PPB_URLLoader_Impl(PluginInstance* instance, bool main_document_loader); + virtual ~PPB_URLLoader_Impl(); + + // Returns a pointer to the interface implementing PPB_URLLoader that is + // exposed to the plugin. + static const PPB_URLLoader* GetInterface(); + + // Returns a pointer to the interface implementing PPB_URLLoaderTrusted that + // is exposed to the plugin. + static const PPB_URLLoaderTrusted* GetTrustedInterface(); + + // Resource overrides. + virtual PPB_URLLoader_Impl* AsPPB_URLLoader_Impl(); + + // PPB_URLLoader implementation. + int32_t Open(PPB_URLRequestInfo_Impl* request, + PP_CompletionCallback callback); + int32_t FollowRedirect(PP_CompletionCallback callback); + bool GetUploadProgress(int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent); + bool GetDownloadProgress(int64_t* bytes_received, + int64_t* total_bytes_to_be_received); + int32_t ReadResponseBody(char* buffer, int32_t bytes_to_read, + PP_CompletionCallback callback); + int32_t FinishStreamingToFile(PP_CompletionCallback callback); + void Close(); + + // PPB_URLLoaderTrusted implementation. + void GrantUniversalAccess(); + void SetStatusCallback(PP_URLLoaderTrusted_StatusCallback cb); + + // WebKit::WebURLLoaderClient implementation. + virtual void willSendRequest(WebKit::WebURLLoader* loader, + WebKit::WebURLRequest& new_request, + const WebKit::WebURLResponse& redir_response); + virtual void didSendData(WebKit::WebURLLoader* loader, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent); + virtual void didReceiveResponse(WebKit::WebURLLoader* loader, + const WebKit::WebURLResponse& response); + virtual void didDownloadData(WebKit::WebURLLoader* loader, + int data_length); + virtual void didReceiveData(WebKit::WebURLLoader* loader, + const char* data, + int data_length); + virtual void didFinishLoading(WebKit::WebURLLoader* loader, + double finish_time); + virtual void didFail(WebKit::WebURLLoader* loader, + const WebKit::WebURLError& error); + + // PluginInstance::Observer implementation. + virtual void InstanceDestroyed(PluginInstance* instance); + + PPB_URLResponseInfo_Impl* response_info() const { return response_info_; } + + private: + void RunCallback(int32_t result); + size_t FillUserBuffer(); + + // Converts a WebURLResponse to a URLResponseInfo and saves it. + void SaveResponse(const WebKit::WebURLResponse& response); + + int32_t CanRequest(const WebKit::WebFrame* frame, const WebKit::WebURL& url); + + // Calls the status_callback_ (if any) with the current upload and download + // progress. Call this function if you update any of these values to + // synchronize an out-of-process plugin's state. + void UpdateStatus(); + + // Returns true if the plugin has requested we record download or upload + // progress. When false, we don't need to update the counters. We go out of + // our way not to allow access to this information unless it's requested, + // even when it would be easier just to return it and not check, so that + // plugins don't depend on access without setting the flag. + bool RecordDownloadProgress() const; + bool RecordUploadProgress() const; + + // This will be NULL if the instance has been deleted but this PPB_URLLoader_Impl was + // somehow leaked. In general, you should not need to check this for NULL. + // However, if you see a NULL pointer crash, that means somebody is holding + // a reference to this object longer than the PluginInstance's lifetime. + PluginInstance* instance_; + + // If true, then the plugin instance is a full-frame plugin and we're just + // wrapping the main document's loader (i.e. loader_ is null). + bool main_document_loader_; + scoped_ptr<WebKit::WebURLLoader> loader_; + scoped_refptr<PPB_URLRequestInfo_Impl> request_info_; + scoped_refptr<PPB_URLResponseInfo_Impl> response_info_; + PP_CompletionCallback pending_callback_; + std::deque<char> buffer_; + int64_t bytes_sent_; + int64_t total_bytes_to_be_sent_; + int64_t bytes_received_; + int64_t total_bytes_to_be_received_; + char* user_buffer_; + size_t user_buffer_size_; + int32_t done_status_; + + bool has_universal_access_; + + PP_URLLoaderTrusted_StatusCallback status_callback_; + + DISALLOW_COPY_AND_ASSIGN(PPB_URLLoader_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_URL_LOADER_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_url_request_info_impl.cc b/webkit/plugins/ppapi/ppb_url_request_info_impl.cc new file mode 100644 index 0000000..1886af5 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_url_request_info_impl.cc @@ -0,0 +1,287 @@ +// 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 "webkit/plugins/ppapi/ppb_url_request_info_impl.h" + +#include "base/logging.h" +#include "base/string_util.h" +#include "googleurl/src/gurl.h" +#include "net/http/http_util.h" +#include "ppapi/c/pp_var.h" +#include "third_party/WebKit/WebKit/chromium/public/WebData.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebHTTPBody.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURL.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" +#include "webkit/plugins/ppapi/string.h" +#include "webkit/plugins/ppapi/var.h" +#include "webkit/glue/webkit_glue.h" + +using WebKit::WebData; +using WebKit::WebHTTPBody; +using WebKit::WebString; +using WebKit::WebFrame; +using WebKit::WebURL; +using WebKit::WebURLRequest; + +namespace webkit { +namespace ppapi { + +namespace { + +// If any of these request headers are specified, they will not be sent. +// TODO(darin): Add more based on security considerations? +const char* const kIgnoredRequestHeaders[] = { + "content-length" +}; + +PP_Bool IsIgnoredRequestHeader(const std::string& name) { + for (size_t i = 0; i < arraysize(kIgnoredRequestHeaders); ++i) { + if (LowerCaseEqualsASCII(name, kIgnoredRequestHeaders[i])) + return PP_TRUE; + } + return PP_FALSE; +} + +PP_Resource Create(PP_Module module_id) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return 0; + + PPB_URLRequestInfo_Impl* request = new PPB_URLRequestInfo_Impl(module); + + return request->GetReference(); +} + +PP_Bool IsURLRequestInfo(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_URLRequestInfo_Impl>(resource)); +} + +PP_Bool SetProperty(PP_Resource request_id, + PP_URLRequestProperty property, + PP_Var var) { + scoped_refptr<PPB_URLRequestInfo_Impl> request( + Resource::GetAs<PPB_URLRequestInfo_Impl>(request_id)); + if (!request) + return PP_FALSE; + + if (var.type == PP_VARTYPE_BOOL) { + return BoolToPPBool( + request->SetBooleanProperty(property, + PPBoolToBool(var.value.as_bool))); + } + + if (var.type == PP_VARTYPE_STRING) { + scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); + if (string) { + return BoolToPPBool(request->SetStringProperty(property, + string->value())); + } + } + + return PP_FALSE; +} + +PP_Bool AppendDataToBody(PP_Resource request_id, + const char* data, + uint32_t len) { + scoped_refptr<PPB_URLRequestInfo_Impl> request( + Resource::GetAs<PPB_URLRequestInfo_Impl>(request_id)); + if (!request) + return PP_FALSE; + + return BoolToPPBool(request->AppendDataToBody(std::string(data, len))); +} + +PP_Bool AppendFileToBody(PP_Resource request_id, + PP_Resource file_ref_id, + int64_t start_offset, + int64_t number_of_bytes, + PP_Time expected_last_modified_time) { + scoped_refptr<PPB_URLRequestInfo_Impl> request( + Resource::GetAs<PPB_URLRequestInfo_Impl>(request_id)); + if (!request) + return PP_FALSE; + + scoped_refptr<PPB_FileRef_Impl> file_ref( + Resource::GetAs<PPB_FileRef_Impl>(file_ref_id)); + if (!file_ref) + return PP_FALSE; + + return BoolToPPBool(request->AppendFileToBody(file_ref, + start_offset, + number_of_bytes, + expected_last_modified_time)); +} + +const PPB_URLRequestInfo ppb_urlrequestinfo = { + &Create, + &IsURLRequestInfo, + &SetProperty, + &AppendDataToBody, + &AppendFileToBody +}; + +} // namespace + +struct PPB_URLRequestInfo_Impl::BodyItem { + BodyItem(const std::string& data) + : data(data), + start_offset(0), + number_of_bytes(-1), + expected_last_modified_time(0.0) { + } + + BodyItem(PPB_FileRef_Impl* file_ref, + int64_t start_offset, + int64_t number_of_bytes, + PP_Time expected_last_modified_time) + : file_ref(file_ref), + start_offset(start_offset), + number_of_bytes(number_of_bytes), + expected_last_modified_time(expected_last_modified_time) { + } + + std::string data; + scoped_refptr<PPB_FileRef_Impl> file_ref; + int64_t start_offset; + int64_t number_of_bytes; + PP_Time expected_last_modified_time; +}; + +PPB_URLRequestInfo_Impl::PPB_URLRequestInfo_Impl(PluginModule* module) + : Resource(module), + stream_to_file_(false), + follow_redirects_(true), + record_download_progress_(false), + record_upload_progress_(false) { +} + +PPB_URLRequestInfo_Impl::~PPB_URLRequestInfo_Impl() { +} + +// static +const PPB_URLRequestInfo* PPB_URLRequestInfo_Impl::GetInterface() { + return &ppb_urlrequestinfo; +} + +PPB_URLRequestInfo_Impl* PPB_URLRequestInfo_Impl::AsPPB_URLRequestInfo_Impl() { + return this; +} + +bool PPB_URLRequestInfo_Impl::SetBooleanProperty(PP_URLRequestProperty property, + bool value) { + switch (property) { + case PP_URLREQUESTPROPERTY_STREAMTOFILE: + stream_to_file_ = value; + return true; + case PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS: + follow_redirects_ = value; + return true; + case PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS: + record_download_progress_ = value; + return true; + case PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS: + record_upload_progress_ = value; + return true; + default: + //NOTIMPLEMENTED(); // TODO(darin): Implement me! + return false; + } +} + +bool PPB_URLRequestInfo_Impl::SetStringProperty(PP_URLRequestProperty property, + const std::string& value) { + // TODO(darin): Validate input. Perhaps at a different layer? + switch (property) { + case PP_URLREQUESTPROPERTY_URL: + url_ = value; // NOTE: This may be a relative URL. + return true; + case PP_URLREQUESTPROPERTY_METHOD: + method_ = value; + return true; + case PP_URLREQUESTPROPERTY_HEADERS: + headers_ = value; + return true; + default: + return false; + } +} + +bool PPB_URLRequestInfo_Impl::AppendDataToBody(const std::string& data) { + if (!data.empty()) + body_.push_back(BodyItem(data)); + return true; +} + +bool PPB_URLRequestInfo_Impl::AppendFileToBody( + PPB_FileRef_Impl* file_ref, + int64_t start_offset, + int64_t number_of_bytes, + PP_Time expected_last_modified_time) { + // Ignore a call to append nothing. + if (number_of_bytes == 0) + return true; + + // Check for bad values. (-1 means read until end of file.) + if (start_offset < 0 || number_of_bytes < -1) + return false; + + body_.push_back(BodyItem(file_ref, + start_offset, + number_of_bytes, + expected_last_modified_time)); + return true; +} + +WebURLRequest PPB_URLRequestInfo_Impl::ToWebURLRequest(WebFrame* frame) const { + WebURLRequest web_request; + web_request.initialize(); + web_request.setURL(frame->document().completeURL(WebString::fromUTF8(url_))); + web_request.setDownloadToFile(stream_to_file_); + + if (!method_.empty()) + web_request.setHTTPMethod(WebString::fromUTF8(method_)); + + if (!headers_.empty()) { + net::HttpUtil::HeadersIterator it(headers_.begin(), headers_.end(), "\n"); + while (it.GetNext()) { + if (!IsIgnoredRequestHeader(it.name())) { + web_request.addHTTPHeaderField( + WebString::fromUTF8(it.name()), + WebString::fromUTF8(it.values())); + } + } + } + + if (!body_.empty()) { + WebHTTPBody http_body; + http_body.initialize(); + for (size_t i = 0; i < body_.size(); ++i) { + if (body_[i].file_ref) { + http_body.appendFileRange( + webkit_glue::FilePathToWebString( + body_[i].file_ref->GetSystemPath()), + body_[i].start_offset, + body_[i].number_of_bytes, + body_[i].expected_last_modified_time); + } else { + DCHECK(!body_[i].data.empty()); + http_body.appendData(WebData(body_[i].data)); + } + } + web_request.setHTTPBody(http_body); + } + + frame->setReferrerForRequest(web_request, WebURL()); // Use default. + return web_request; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_url_request_info_impl.h b/webkit/plugins/ppapi/ppb_url_request_info_impl.h new file mode 100644 index 0000000..a55edfe --- /dev/null +++ b/webkit/plugins/ppapi/ppb_url_request_info_impl.h @@ -0,0 +1,74 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_URL_REQUEST_INFO_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_URL_REQUEST_INFO_IMPL_H_ + +#include <string> +#include <vector> + +#include "base/ref_counted.h" +#include "ppapi/c/ppb_url_request_info.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace WebKit { +class WebFrame; +class WebURLRequest; +} + +namespace webkit { +namespace ppapi { + +class PPB_FileRef_Impl; + +class PPB_URLRequestInfo_Impl : public Resource { + public: + explicit PPB_URLRequestInfo_Impl(PluginModule* module); + virtual ~PPB_URLRequestInfo_Impl(); + + // Returns a pointer to the interface implementing PPB_URLRequestInfo that is + // exposed to the plugin. + static const PPB_URLRequestInfo* GetInterface(); + + // Resource overrides. + virtual PPB_URLRequestInfo_Impl* AsPPB_URLRequestInfo_Impl(); + + // PPB_URLRequestInfo implementation. + bool SetBooleanProperty(PP_URLRequestProperty property, bool value); + bool SetStringProperty(PP_URLRequestProperty property, + const std::string& value); + bool AppendDataToBody(const std::string& data); + bool AppendFileToBody(PPB_FileRef_Impl* file_ref, + int64_t start_offset, + int64_t number_of_bytes, + PP_Time expected_last_modified_time); + + WebKit::WebURLRequest ToWebURLRequest(WebKit::WebFrame* frame) const; + + bool follow_redirects() { return follow_redirects_; } + + bool record_download_progress() const { return record_download_progress_; } + bool record_upload_progress() const { return record_upload_progress_; } + + private: + struct BodyItem; + typedef std::vector<BodyItem> Body; + + std::string url_; + std::string method_; + std::string headers_; + Body body_; + + bool stream_to_file_; + bool follow_redirects_; + bool record_download_progress_; + bool record_upload_progress_; + + DISALLOW_COPY_AND_ASSIGN(PPB_URLRequestInfo_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_URL_REQUEST_INFO_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_url_response_info_impl.cc b/webkit/plugins/ppapi/ppb_url_response_info_impl.cc new file mode 100644 index 0000000..43e3d9e --- /dev/null +++ b/webkit/plugins/ppapi/ppb_url_response_info_impl.cc @@ -0,0 +1,146 @@ +// 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 "webkit/plugins/ppapi/ppb_url_response_info_impl.h" + +#include "base/logging.h" +#include "ppapi/c/pp_var.h" +#include "third_party/WebKit/WebKit/chromium/public/WebHTTPHeaderVisitor.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURL.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" +#include "webkit/plugins/ppapi/var.h" +#include "webkit/glue/webkit_glue.h" + +using WebKit::WebHTTPHeaderVisitor; +using WebKit::WebString; +using WebKit::WebURLResponse; + +namespace webkit { +namespace ppapi { + +namespace { + +class HeaderFlattener : public WebHTTPHeaderVisitor { + public: + const std::string& buffer() const { return buffer_; } + + virtual void visitHeader(const WebString& name, const WebString& value) { + if (!buffer_.empty()) + buffer_.append("\n"); + buffer_.append(name.utf8()); + buffer_.append(": "); + buffer_.append(value.utf8()); + } + + private: + std::string buffer_; +}; + +PP_Bool IsURLResponseInfo(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_URLResponseInfo_Impl>(resource)); +} + +PP_Var GetProperty(PP_Resource response_id, + PP_URLResponseProperty property) { + scoped_refptr<PPB_URLResponseInfo_Impl> response( + Resource::GetAs<PPB_URLResponseInfo_Impl>(response_id)); + if (!response) + return PP_MakeUndefined(); + + return response->GetProperty(property); +} + +PP_Resource GetBody(PP_Resource response_id) { + scoped_refptr<PPB_URLResponseInfo_Impl> response( + Resource::GetAs<PPB_URLResponseInfo_Impl>(response_id)); + if (!response.get()) + return 0; + + PPB_FileRef_Impl* body = response->body(); + if (!body) + return 0; + body->AddRef(); // AddRef for the caller. + + return body->GetReference(); +} + +const PPB_URLResponseInfo ppb_urlresponseinfo = { + &IsURLResponseInfo, + &GetProperty, + &GetBody +}; + +bool IsRedirect(int32_t status) { + return status >= 300 && status <= 399; +} + +} // namespace + +PPB_URLResponseInfo_Impl::PPB_URLResponseInfo_Impl(PluginModule* module) + : Resource(module), + status_code_(-1) { +} + +PPB_URLResponseInfo_Impl::~PPB_URLResponseInfo_Impl() { +} + +// static +const PPB_URLResponseInfo* PPB_URLResponseInfo_Impl::GetInterface() { + return &ppb_urlresponseinfo; +} + +PPB_URLResponseInfo_Impl* +PPB_URLResponseInfo_Impl::AsPPB_URLResponseInfo_Impl() { + return this; +} + +PP_Var PPB_URLResponseInfo_Impl::GetProperty(PP_URLResponseProperty property) { + switch (property) { + case PP_URLRESPONSEPROPERTY_URL: + return StringVar::StringToPPVar(module(), url_); + case PP_URLRESPONSEPROPERTY_REDIRECTURL: + if (IsRedirect(status_code_)) + return StringVar::StringToPPVar(module(), redirect_url_); + break; + case PP_URLRESPONSEPROPERTY_REDIRECTMETHOD: + if (IsRedirect(status_code_)) + return StringVar::StringToPPVar(module(), status_text_); + break; + case PP_URLRESPONSEPROPERTY_STATUSCODE: + return PP_MakeInt32(status_code_); + case PP_URLRESPONSEPROPERTY_STATUSLINE: + return StringVar::StringToPPVar(module(), status_text_); + case PP_URLRESPONSEPROPERTY_HEADERS: + return StringVar::StringToPPVar(module(), headers_); + } + // The default is to return an undefined PP_Var. + return PP_MakeUndefined(); +} + +bool PPB_URLResponseInfo_Impl::Initialize(const WebURLResponse& response) { + url_ = response.url().spec(); + status_code_ = response.httpStatusCode(); + status_text_ = response.httpStatusText().utf8(); + if (IsRedirect(status_code_)) { + redirect_url_ = response.httpHeaderField( + WebString::fromUTF8("Location")).utf8(); + } + + HeaderFlattener flattener; + response.visitHTTPHeaderFields(&flattener); + headers_ = flattener.buffer(); + + WebString file_path = response.downloadFilePath(); + if (!file_path.isEmpty()) + body_ = new PPB_FileRef_Impl(module(), + webkit_glue::WebStringToFilePath(file_path)); + return true; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_url_response_info_impl.h b/webkit/plugins/ppapi/ppb_url_response_info_impl.h new file mode 100644 index 0000000..ee12d35c --- /dev/null +++ b/webkit/plugins/ppapi/ppb_url_response_info_impl.h @@ -0,0 +1,58 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_URL_RESPONSE_INFO_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_URL_RESPONSE_INFO_IMPL_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ppapi/c/ppb_url_response_info.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace WebKit { +class WebURLResponse; +} + +namespace webkit { +namespace ppapi { + +class PPB_FileRef_Impl; + +class PPB_URLResponseInfo_Impl : public Resource { + public: + explicit PPB_URLResponseInfo_Impl(PluginModule* module); + virtual ~PPB_URLResponseInfo_Impl(); + + // Returns a pointer to the interface implementing PPB_URLResponseInfo that + // is exposed to the plugin. + static const PPB_URLResponseInfo* GetInterface(); + + // Resource overrides. + virtual PPB_URLResponseInfo_Impl* AsPPB_URLResponseInfo_Impl(); + + // PPB_URLResponseInfo implementation. + PP_Var GetProperty(PP_URLResponseProperty property); + + bool Initialize(const WebKit::WebURLResponse& response); + + PPB_FileRef_Impl* body() { return body_; } + + std::string redirect_url() { return redirect_url_; } + + private: + std::string url_; + std::string headers_; + int32_t status_code_; + std::string status_text_; + std::string redirect_url_; + scoped_refptr<PPB_FileRef_Impl> body_; + + DISALLOW_COPY_AND_ASSIGN(PPB_URLResponseInfo_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_URL_RESPONSE_INFO_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_url_util_impl.cc b/webkit/plugins/ppapi/ppb_url_util_impl.cc new file mode 100644 index 0000000..47980e4 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_url_util_impl.cc @@ -0,0 +1,180 @@ +// 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 "webkit/plugins/ppapi/ppb_url_util_impl.h" + +#include "googleurl/src/gurl.h" +#include "ppapi/c/dev/ppb_url_util_dev.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebElement.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebNode.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h" +#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURL.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/string.h" +#include "webkit/plugins/ppapi/var.h" + +namespace webkit { +namespace ppapi { + +namespace { + +void ConvertComponent(const url_parse::Component& input, + PP_UrlComponent_Dev* output) { + output->begin = input.begin; + output->len = input.len; +} + +// Output can be NULL to specify "do nothing." This rule is followed by all the +// url util functions, so we implement it once here. +void ConvertComponents(const url_parse::Parsed& input, + PP_UrlComponents_Dev* output) { + if (!output) + return; + + ConvertComponent(input.scheme, &output->scheme); + ConvertComponent(input.username, &output->username); + ConvertComponent(input.password, &output->password); + ConvertComponent(input.host, &output->host); + ConvertComponent(input.port, &output->port); + ConvertComponent(input.path, &output->path); + ConvertComponent(input.query, &output->query); + ConvertComponent(input.ref, &output->ref); +} + +// Used for returning the given GURL from a PPAPI function, with an optional +// out param indicating the components. +PP_Var GenerateUrlReturn(PluginModule* module, const GURL& url, + PP_UrlComponents_Dev* components) { + if (!url.is_valid()) + return PP_MakeNull(); + ConvertComponents(url.parsed_for_possibly_invalid_spec(), components); + return StringVar::StringToPPVar(module, url.possibly_invalid_spec()); +} + +// Sets |*security_origin| to be the WebKit security origin associated with the +// document containing the given plugin instance. On success, returns true. If +// the instance is invalid, returns false and |*security_origin| will be +// unchanged. +bool SecurityOriginForInstance(PP_Instance instance_id, + WebKit::WebSecurityOrigin* security_origin) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return false; + + WebKit::WebElement plugin_element = instance->container()->element(); + WebKit::WebFrame* plugin_frame = plugin_element.document().frame(); + if (!plugin_frame) + return false; + + *security_origin = plugin_frame->securityOrigin(); + return true; +} + +PP_Var Canonicalize(PP_Var url, PP_UrlComponents_Dev* components) { + scoped_refptr<StringVar> url_string(StringVar::FromPPVar(url)); + if (!url_string) + return PP_MakeNull(); + return GenerateUrlReturn(url_string->module(), + GURL(url_string->value()), components); +} + +PP_Var ResolveRelativeToUrl(PP_Var base_url, + PP_Var relative, + PP_UrlComponents_Dev* components) { + scoped_refptr<StringVar> base_url_string(StringVar::FromPPVar(base_url)); + scoped_refptr<StringVar> relative_string(StringVar::FromPPVar(relative)); + if (!base_url_string || !relative_string) + return PP_MakeNull(); + + GURL base_gurl(base_url_string->value()); + if (!base_gurl.is_valid()) + return PP_MakeNull(); + return GenerateUrlReturn(base_url_string->module(), + base_gurl.Resolve(relative_string->value()), + components); +} + +PP_Var ResolveRelativeToDocument(PP_Instance instance_id, + PP_Var relative, + PP_UrlComponents_Dev* components) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_MakeNull(); + + scoped_refptr<StringVar> relative_string(StringVar::FromPPVar(relative)); + if (!relative_string) + return PP_MakeNull(); + + WebKit::WebElement plugin_element = instance->container()->element(); + GURL document_url = plugin_element.document().baseURL(); + return GenerateUrlReturn(instance->module(), + document_url.Resolve(relative_string->value()), + components); +} + +PP_Bool IsSameSecurityOrigin(PP_Var url_a, PP_Var url_b) { + scoped_refptr<StringVar> url_a_string(StringVar::FromPPVar(url_a)); + scoped_refptr<StringVar> url_b_string(StringVar::FromPPVar(url_b)); + if (!url_a_string || !url_b_string) + return PP_FALSE; + + GURL gurl_a(url_a_string->value()); + GURL gurl_b(url_b_string->value()); + if (!gurl_a.is_valid() || !gurl_b.is_valid()) + return PP_FALSE; + + return BoolToPPBool(gurl_a.GetOrigin() == gurl_b.GetOrigin()); +} + +PP_Bool DocumentCanRequest(PP_Instance instance, PP_Var url) { + scoped_refptr<StringVar> url_string(StringVar::FromPPVar(url)); + if (!url_string) + return PP_FALSE; + + WebKit::WebSecurityOrigin security_origin; + if (!SecurityOriginForInstance(instance, &security_origin)) + return PP_FALSE; + + GURL gurl(url_string->value()); + if (!gurl.is_valid()) + return PP_FALSE; + + return BoolToPPBool(security_origin.canRequest(gurl)); +} + +PP_Bool DocumentCanAccessDocument(PP_Instance active, PP_Instance target) { + WebKit::WebSecurityOrigin active_origin; + if (!SecurityOriginForInstance(active, &active_origin)) + return PP_FALSE; + + WebKit::WebSecurityOrigin target_origin; + if (!SecurityOriginForInstance(active, &target_origin)) + return PP_FALSE; + + return BoolToPPBool(active_origin.canAccess(target_origin)); +} + +} // namespace + +const PPB_UrlUtil_Dev ppb_url_util = { + &Canonicalize, + &ResolveRelativeToUrl, + &ResolveRelativeToDocument, + &IsSameSecurityOrigin, + &DocumentCanRequest, + &DocumentCanAccessDocument +}; + +// static +const PPB_UrlUtil_Dev* PPB_UrlUtil_Impl::GetInterface() { + return &ppb_url_util; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_url_util_impl.h b/webkit/plugins/ppapi/ppb_url_util_impl.h new file mode 100644 index 0000000..8cba6a9 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_url_util_impl.h @@ -0,0 +1,21 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_URL_UTIL_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_URL_UTIL_IMPL_H_ + +struct PPB_UrlUtil_Dev; + +namespace webkit { +namespace ppapi { + +class PPB_UrlUtil_Impl { + public: + static const PPB_UrlUtil_Dev* GetInterface(); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_URL_UTIL_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_video_decoder_impl.cc b/webkit/plugins/ppapi/ppb_video_decoder_impl.cc new file mode 100644 index 0000000..bd7f204 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_video_decoder_impl.cc @@ -0,0 +1,152 @@ +// 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 "webkit/plugins/ppapi/ppb_video_decoder_impl.h" + +#include "base/logging.h" +#include "ppapi/c/dev/pp_video_dev.h" +#include "ppapi/c/dev/ppb_video_decoder_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_file_ref_impl.h" +#include "webkit/plugins/ppapi/resource_tracker.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Bool GetConfig(PP_Instance instance_id, + PP_VideoCodecId_Dev codec, + PP_VideoConfig_Dev* configs, + int32_t config_size, + int32_t *num_config) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + *num_config = 0; + if (!instance) + return PP_FALSE; + + // Get configs based on codec. + + if (configs) { + // Fill in the array of configs. + } + + // Update *num_config. + + return PP_TRUE; +} + +PP_Resource Create(PP_Instance instance_id, + const PP_VideoDecoderConfig_Dev* decoder_config) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return 0; + + scoped_refptr<PPB_VideoDecoder_Impl> decoder( + new PPB_VideoDecoder_Impl(instance)); + + if (!decoder->Init(*decoder_config)) + return 0; + + return decoder->GetReference(); +} + +PP_Bool Decode(PP_Resource decoder_id, + PP_VideoCompressedDataBuffer_Dev* input_buffer) { + scoped_refptr<PPB_VideoDecoder_Impl> decoder( + Resource::GetAs<PPB_VideoDecoder_Impl>(decoder_id)); + if (!decoder) + return PP_FALSE; + + decoder->Decode(*input_buffer); + return PP_TRUE; +} + +int32_t Flush(PP_Resource decoder_id, PP_CompletionCallback callback) { + scoped_refptr<PPB_VideoDecoder_Impl> decoder( + Resource::GetAs<PPB_VideoDecoder_Impl>(decoder_id)); + if (!decoder) + return PP_ERROR_BADRESOURCE; + + return decoder->Flush(callback); +} + +PP_Bool ReturnUncompressedDataBuffer( + PP_Resource decoder_id, + PP_VideoUncompressedDataBuffer_Dev* buffer) { + scoped_refptr<PPB_VideoDecoder_Impl> decoder( + Resource::GetAs<PPB_VideoDecoder_Impl>(decoder_id)); + if (!decoder) + return PP_FALSE; + + return BoolToPPBool(decoder->ReturnUncompressedDataBuffer(*buffer)); +} + +const PPB_VideoDecoder_Dev ppb_videodecoder = { + &GetConfig, + &Create, + &Decode, + &Flush, + &ReturnUncompressedDataBuffer +}; + +} // namespace + +PPB_VideoDecoder_Impl::PPB_VideoDecoder_Impl(PluginInstance* instance) + : Resource(instance->module()), + instance_(instance) { +} + +PPB_VideoDecoder_Impl::~PPB_VideoDecoder_Impl() { +} + +// static +const PPB_VideoDecoder_Dev* PPB_VideoDecoder_Impl::GetInterface() { + return &ppb_videodecoder; +} + +PPB_VideoDecoder_Impl* PPB_VideoDecoder_Impl::AsPPB_VideoDecoder_Impl() { + return this; +} + +bool PPB_VideoDecoder_Impl::Init( + const PP_VideoDecoderConfig_Dev& decoder_config) { + if (!instance()) + return false; + + platform_video_decoder_.reset( + instance()->delegate()->CreateVideoDecoder(decoder_config)); + + return platform_video_decoder_.get()? true : false; +} + +bool PPB_VideoDecoder_Impl::Decode( + PP_VideoCompressedDataBuffer_Dev& input_buffer) { + if (!platform_video_decoder_.get()) + return false; + + return platform_video_decoder_->Decode(input_buffer); +} + +int32_t PPB_VideoDecoder_Impl::Flush(PP_CompletionCallback& callback) { + if (!platform_video_decoder_.get()) + return PP_ERROR_FAILED; + + return platform_video_decoder_->Flush(callback); +} + +bool PPB_VideoDecoder_Impl::ReturnUncompressedDataBuffer( + PP_VideoUncompressedDataBuffer_Dev& buffer) { + if (!platform_video_decoder_.get()) + return false; + + return platform_video_decoder_->ReturnUncompressedDataBuffer(buffer); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_video_decoder_impl.h b/webkit/plugins/ppapi/ppb_video_decoder_impl.h new file mode 100644 index 0000000..169ebed --- /dev/null +++ b/webkit/plugins/ppapi/ppb_video_decoder_impl.h @@ -0,0 +1,55 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_VIDEO_DECODER_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_VIDEO_DECODER_IMPL_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PP_VideoDecoderConfig_Dev; +struct PP_VideoCompressedDataBuffer_Dev; +struct PP_VideoUncompressedDataBuffer_Dev; +struct PPB_VideoDecoder_Dev; + +namespace webkit { +namespace ppapi { + +class PluginInstance; + +class PPB_VideoDecoder_Impl : public Resource { + public: + PPB_VideoDecoder_Impl(PluginInstance* instance); + virtual ~PPB_VideoDecoder_Impl(); + + // Returns a pointer to the interface implementing PPB_VideoDecoder that is + // exposed to the plugin. + static const PPB_VideoDecoder_Dev* GetInterface(); + + // Resource overrides. + virtual PPB_VideoDecoder_Impl* AsPPB_VideoDecoder_Impl(); + + PluginInstance* instance() { return instance_.get(); } + + // PPB_VideoDecoder implementation. + bool Init(const PP_VideoDecoderConfig_Dev& decoder_config); + bool Decode(PP_VideoCompressedDataBuffer_Dev& input_buffer); + int32_t Flush(PP_CompletionCallback& callback); + bool ReturnUncompressedDataBuffer(PP_VideoUncompressedDataBuffer_Dev& buffer); + + private: + // This is NULL before initialization, and if this PPB_VideoDecoder_Impl is + // swapped with another. + scoped_ptr<PluginDelegate::PlatformVideoDecoder> platform_video_decoder_; + scoped_refptr<PluginInstance> instance_; + + DISALLOW_COPY_AND_ASSIGN(PPB_VideoDecoder_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_VIDEO_DECODER_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_widget_impl.cc b/webkit/plugins/ppapi/ppb_widget_impl.cc new file mode 100644 index 0000000..57491b5 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_widget_impl.cc @@ -0,0 +1,109 @@ +// 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 "webkit/plugins/ppapi/ppb_widget_impl.h" + +#include "base/logging.h" +#include "ppapi/c/dev/ppb_widget_dev.h" +#include "ppapi/c/dev/ppp_widget_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/ppb_image_data_impl.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/plugin_module.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Bool IsWidget(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_Widget_Impl>(resource)); +} + +PP_Bool Paint(PP_Resource resource, + const PP_Rect* rect, + PP_Resource image_id) { + scoped_refptr<PPB_Widget_Impl> widget( + Resource::GetAs<PPB_Widget_Impl>(resource)); + if (!widget) + return PP_FALSE; + + scoped_refptr<PPB_ImageData_Impl> image( + Resource::GetAs<PPB_ImageData_Impl>(image_id)); + if (!image) + return PP_FALSE; + + return BoolToPPBool(widget->Paint(rect, image)); +} + +PP_Bool HandleEvent(PP_Resource resource, const PP_InputEvent* event) { + scoped_refptr<PPB_Widget_Impl> widget( + Resource::GetAs<PPB_Widget_Impl>(resource)); + return BoolToPPBool(widget && widget->HandleEvent(event)); +} + +PP_Bool GetLocation(PP_Resource resource, PP_Rect* location) { + scoped_refptr<PPB_Widget_Impl> widget( + Resource::GetAs<PPB_Widget_Impl>(resource)); + return BoolToPPBool(widget && widget->GetLocation(location)); +} + +void SetLocation(PP_Resource resource, const PP_Rect* location) { + scoped_refptr<PPB_Widget_Impl> widget( + Resource::GetAs<PPB_Widget_Impl>(resource)); + if (widget) + widget->SetLocation(location); +} + +const PPB_Widget_Dev ppb_widget = { + &IsWidget, + &Paint, + &HandleEvent, + &GetLocation, + &SetLocation, +}; + +} // namespace + +PPB_Widget_Impl::PPB_Widget_Impl(PluginInstance* instance) + : Resource(instance->module()), + instance_(instance) { +} + +PPB_Widget_Impl::~PPB_Widget_Impl() { +} + +// static +const PPB_Widget_Dev* PPB_Widget_Impl::GetInterface() { + return &ppb_widget; +} + +PPB_Widget_Impl* PPB_Widget_Impl::AsPPB_Widget_Impl() { + return this; +} + +bool PPB_Widget_Impl::GetLocation(PP_Rect* location) { + *location = location_; + return true; +} + +void PPB_Widget_Impl::SetLocation(const PP_Rect* location) { + location_ = *location; + SetLocationInternal(location); +} + +void PPB_Widget_Impl::Invalidate(const PP_Rect* dirty) { + const PPP_Widget_Dev* widget = static_cast<const PPP_Widget_Dev*>( + module()->GetPluginInterface(PPP_WIDGET_DEV_INTERFACE)); + if (!widget) + return; + ScopedResourceId resource(this); + widget->Invalidate(instance_->pp_instance(), resource.id, dirty); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/ppb_widget_impl.h b/webkit/plugins/ppapi/ppb_widget_impl.h new file mode 100644 index 0000000..1cd9761 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_widget_impl.h @@ -0,0 +1,58 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPB_WIDGET_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_WIDGET_IMPL_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "ppapi/c/pp_rect.h" +#include "webkit/plugins/ppapi/resource.h" + +struct PPB_Widget_Dev; +struct PP_InputEvent; + +namespace webkit { +namespace ppapi { + +class PPB_ImageData_Impla; +class PluginInstance; + +class PPB_Widget_Impl : public Resource { + public: + explicit PPB_Widget_Impl(PluginInstance* instance); + virtual ~PPB_Widget_Impl(); + + // Returns a pointer to the interface implementing PPB_Widget that is + // exposed to the plugin. + static const PPB_Widget_Dev* GetInterface(); + + // Resource overrides. + virtual PPB_Widget_Impl* AsPPB_Widget_Impl(); + + // PPB_Widget implementation. + virtual bool Paint(const PP_Rect* rect, PPB_ImageData_Impl* image) = 0; + virtual bool HandleEvent(const PP_InputEvent* event) = 0; + bool GetLocation(PP_Rect* location); + void SetLocation(const PP_Rect* location); + + // Notifies the plugin instance that the given rect needs to be repainted. + void Invalidate(const PP_Rect* dirty); + PluginInstance* instance() { return instance_; } + + protected: + virtual void SetLocationInternal(const PP_Rect* location) = 0; + PP_Rect location() const { return location_; } + + private: + scoped_refptr<PluginInstance> instance_; + PP_Rect location_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Widget_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_WIDGET_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppp_pdf.h b/webkit/plugins/ppapi/ppp_pdf.h new file mode 100644 index 0000000..6405225 --- /dev/null +++ b/webkit/plugins/ppapi/ppp_pdf.h @@ -0,0 +1,20 @@ +// 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 WEBKIT_PLUGINS_PPAPI_PPP_PDF_H_ +#define WEBKIT_PLUGINS_PPAPI_PPP_PDF_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_var.h" + +#define PPP_PDF_INTERFACE "PPP_Pdf;1" + +struct PPP_Pdf { + // Returns an absolute URL if the position is over a link. + PP_Var (*GetLinkAtPosition)(PP_Instance instance, + PP_Point point); +}; + +#endif // WEBKIT_PLUGINS_PPAPI_PPP_PDF_H_ diff --git a/webkit/plugins/ppapi/resource.cc b/webkit/plugins/ppapi/resource.cc new file mode 100644 index 0000000..0f8fbf9 --- /dev/null +++ b/webkit/plugins/ppapi/resource.cc @@ -0,0 +1,45 @@ +// 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 "webkit/plugins/ppapi/resource.h" + +#include "base/logging.h" +#include "webkit/plugins/ppapi/resource_tracker.h" + +namespace webkit { +namespace ppapi { + +Resource::Resource(PluginModule* module) + : resource_id_(0), module_(module) { +} + +Resource::~Resource() { +} + +PP_Resource Resource::GetReference() { + ResourceTracker *tracker = ResourceTracker::Get(); + if (resource_id_) + tracker->AddRefResource(resource_id_); + else + resource_id_ = tracker->AddResource(this); + return resource_id_; +} + +PP_Resource Resource::GetReferenceNoAddRef() const { + return resource_id_; +} + +void Resource::StoppedTracking() { + DCHECK(resource_id_ != 0); + resource_id_ = 0; +} + +#define DEFINE_TYPE_GETTER(RESOURCE) \ + RESOURCE* Resource::As##RESOURCE() { return NULL; } +FOR_ALL_RESOURCES(DEFINE_TYPE_GETTER) +#undef DEFINE_TYPE_GETTER + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/resource.h b/webkit/plugins/ppapi/resource.h new file mode 100644 index 0000000..45f114c --- /dev/null +++ b/webkit/plugins/ppapi/resource.h @@ -0,0 +1,141 @@ +// 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 WEBKIT_PLUGINS_PPAPI_RESOURCE_H_ +#define WEBKIT_PLUGINS_PPAPI_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "ppapi/c/pp_resource.h" +#include "webkit/plugins/ppapi/resource_tracker.h" + +namespace webkit { +namespace ppapi { + +// If you inherit from resource, make sure you add the class name here. +#define FOR_ALL_RESOURCES(F) \ + F(MockResource) \ + F(ObjectVar) \ + F(PPB_AudioConfig_Impl) \ + F(PPB_Audio_Impl) \ + F(PPB_Buffer_Impl) \ + F(PPB_DirectoryReader_Impl) \ + F(PPB_FileChooser_Impl) \ + F(PPB_FileIO_Impl) \ + F(PPB_FileRef_Impl) \ + F(PPB_FileSystem_Impl) \ + F(PPB_Font_Impl) \ + F(PPB_Graphics2D_Impl) \ + F(PPB_Graphics3D_Impl) \ + F(PPB_ImageData_Impl) \ + F(PPB_Scrollbar_Impl) \ + F(PPB_Transport_Impl) \ + F(PPB_URLLoader_Impl) \ + F(PPB_URLRequestInfo_Impl) \ + F(PPB_URLResponseInfo_Impl) \ + F(PPB_VideoDecoder_Impl) \ + F(PPB_Widget_Impl) \ + F(PrivateFontFile) \ + F(StringVar) \ + F(Var) \ + F(VarObjectClass) + +// Forward declaration of Resource classes. +#define DECLARE_RESOURCE_CLASS(RESOURCE) class RESOURCE; +FOR_ALL_RESOURCES(DECLARE_RESOURCE_CLASS) +#undef DECLARE_RESOURCE_CLASS + +class Resource : public base::RefCountedThreadSafe<Resource> { + public: + explicit Resource(PluginModule* module); + virtual ~Resource(); + + // Returns NULL if the resource is invalid or is a different type. + template<typename T> + static scoped_refptr<T> GetAs(PP_Resource res) { + scoped_refptr<Resource> resource = ResourceTracker::Get()->GetResource(res); + return resource ? resource->Cast<T>() : NULL; + } + + PluginModule* module() const { return module_; } + + // Cast the resource into a specified type. This will return NULL if the + // resource does not match the specified type. Specializations of this + // template call into As* functions. + template <typename T> T* Cast() { return NULL; } + + // Returns an resource id of this object. If the object doesn't have a + // resource id, new one is created with plugin refcount of 1. If it does, + // the refcount is incremented. Use this when you need to return a new + // reference to the plugin. + PP_Resource GetReference(); + + // Returns the resource ID of this object OR NULL IF THERE IS NONE ASSIGNED. + // This will happen if the plugin doesn't have a reference to the given + // resource. The resource will not be addref'ed. + // + // This should only be used as an input parameter to the plugin for status + // updates in the proxy layer, where if the plugin has no reference, it will + // just give up since nothing needs to be updated. + // + // Generally you should use GetReference instead. This is why it has this + // obscure name rather than pp_resource(). + PP_Resource GetReferenceNoAddRef() const; + + // When you need to ensure that a resource has a reference, but you do not + // want to increase the refcount (for example, if you need to call a plugin + // callback function with a reference), you can use this class. For example: + // + // plugin_callback(.., ScopedResourceId(resource).id, ...); + class ScopedResourceId { + public: + explicit ScopedResourceId(Resource* resource) + : id(resource->GetReference()) {} + ~ScopedResourceId() { + ResourceTracker::Get()->UnrefResource(id); + } + const PP_Resource id; + }; + + private: + // Type-specific getters for individual resource types. These will return + // NULL if the resource does not match the specified type. Used by the Cast() + // function. + #define DEFINE_TYPE_GETTER(RESOURCE) \ + virtual RESOURCE* As##RESOURCE(); + FOR_ALL_RESOURCES(DEFINE_TYPE_GETTER) + #undef DEFINE_TYPE_GETTER + + // If referenced by a plugin, holds the id of this resource object. Do not + // access this member directly, because it is possible that the plugin holds + // no references to the object, and therefore the resource_id_ is zero. Use + // either GetReference() to obtain a new resource_id and increase the + // refcount, or TemporaryReference when you do not want to increase the + // refcount. + PP_Resource resource_id_; + + // Non-owning pointer to our module. + PluginModule* module_; + + // Called by the resource tracker when the last plugin reference has been + // dropped. + friend class ResourceTracker; + void StoppedTracking(); + + DISALLOW_COPY_AND_ASSIGN(Resource); +}; + +// Cast() specializations. +#define DEFINE_RESOURCE_CAST(Type) \ + template <> inline Type* Resource::Cast<Type>() { \ + return As##Type(); \ + } + +FOR_ALL_RESOURCES(DEFINE_RESOURCE_CAST) +#undef DEFINE_RESOURCE_CAST + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_RESOURCE_H_ diff --git a/webkit/plugins/ppapi/resource_tracker.cc b/webkit/plugins/ppapi/resource_tracker.cc new file mode 100644 index 0000000..7f66160 --- /dev/null +++ b/webkit/plugins/ppapi/resource_tracker.cc @@ -0,0 +1,196 @@ +// 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 "webkit/plugins/ppapi/resource_tracker.h" + +#include <limits> +#include <set> + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/rand_util.h" +#include "ppapi/c/pp_resource.h" +#include "webkit/plugins/ppapi/resource.h" + +namespace webkit { +namespace ppapi { + +static base::LazyInstance<ResourceTracker> g_resource_tracker( + base::LINKER_INITIALIZED); + +scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const { + ResourceMap::const_iterator result = live_resources_.find(res); + if (result == live_resources_.end()) { + return scoped_refptr<Resource>(); + } + return result->second.first; +} + +// static +ResourceTracker* ResourceTracker::singleton_override_ = NULL; + +ResourceTracker::ResourceTracker() + : last_id_(0) { +} + +ResourceTracker::~ResourceTracker() { +} + +// static +ResourceTracker* ResourceTracker::Get() { + if (singleton_override_) + return singleton_override_; + return g_resource_tracker.Pointer(); +} + +PP_Resource ResourceTracker::AddResource(Resource* resource) { + // If the plugin manages to create 4B resources... + if (last_id_ == std::numeric_limits<PP_Resource>::max()) { + return 0; + } + // Add the resource with plugin use-count 1. + ++last_id_; + live_resources_.insert(std::make_pair(last_id_, std::make_pair(resource, 1))); + return last_id_; +} + +bool ResourceTracker::AddRefResource(PP_Resource res) { + ResourceMap::iterator i = live_resources_.find(res); + if (i != live_resources_.end()) { + // We don't protect against overflow, since a plugin as malicious as to ref + // once per every byte in the address space could have just as well unrefed + // one time too many. + ++i->second.second; + return true; + } else { + return false; + } +} + +bool ResourceTracker::UnrefResource(PP_Resource res) { + ResourceMap::iterator i = live_resources_.find(res); + if (i != live_resources_.end()) { + if (!--i->second.second) { + i->second.first->StoppedTracking(); + live_resources_.erase(i); + } + return true; + } else { + return false; + } +} + +void ResourceTracker::ForceDeletePluginResourceRefs(PP_Resource res) { + ResourceMap::iterator i = live_resources_.find(res); + if (i == live_resources_.end()) + return; // Nothing to do. + + i->second.second = 0; + i->second.first->StoppedTracking(); + live_resources_.erase(i); +} + +uint32 ResourceTracker::GetLiveObjectsForModule(PluginModule* module) const { + // Since this is for testing only, we'll just go through all of them and + // count. + // + // TODO(brettw) we will eventually need to implement more efficient + // module->resource lookup to free resources when a module is unloaded. In + // this case, this function can be implemented using that system. + uint32 count = 0; + for (ResourceMap::const_iterator i = live_resources_.begin(); + i != live_resources_.end(); ++i) + count++; + return count; +} + +PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) { +#ifndef NDEBUG + // Make sure we're not adding one more than once. + for (InstanceMap::const_iterator i = instance_map_.begin(); + i != instance_map_.end(); ++i) + DCHECK(i->second != instance); +#endif + + // Use a random 64-bit number for the instance ID. This helps prevent some + // mischeif where you could misallocate resources if you gave a different + // instance ID. + // + // See also AddModule below. + // + // Need to make sure the random number isn't a duplicate or 0. + PP_Instance new_instance; + do { + new_instance = static_cast<PP_Instance>(base::RandUint64()); + } while (!new_instance || + instance_map_.find(new_instance) != instance_map_.end()); + instance_map_[new_instance] = instance; + return new_instance; +} + +void ResourceTracker::InstanceDeleted(PP_Instance instance) { + InstanceMap::iterator found = instance_map_.find(instance); + if (found == instance_map_.end()) { + NOTREACHED(); + return; + } + instance_map_.erase(found); +} + +PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) { + InstanceMap::iterator found = instance_map_.find(instance); + if (found == instance_map_.end()) + return NULL; + return found->second; +} + +PP_Module ResourceTracker::AddModule(PluginModule* module) { +#ifndef NDEBUG + // Make sure we're not adding one more than once. + for (ModuleMap::const_iterator i = module_map_.begin(); + i != module_map_.end(); ++i) + DCHECK(i->second != module); +#endif + + // See AddInstance above. + PP_Module new_module; + do { + new_module = static_cast<PP_Module>(base::RandUint64()); + } while (!new_module || + module_map_.find(new_module) != module_map_.end()); + module_map_[new_module] = module; + return new_module; +} + +void ResourceTracker::ModuleDeleted(PP_Module module) { + ModuleMap::iterator found = module_map_.find(module); + if (found == module_map_.end()) { + NOTREACHED(); + return; + } + module_map_.erase(found); +} + +PluginModule* ResourceTracker::GetModule(PP_Module module) { + ModuleMap::iterator found = module_map_.find(module); + if (found == module_map_.end()) + return NULL; + return found->second; +} + +// static +void ResourceTracker::SetSingletonOverride(ResourceTracker* tracker) { + DCHECK(!singleton_override_); + singleton_override_ = tracker; +} + +// static +void ResourceTracker::ClearSingletonOverride() { + DCHECK(singleton_override_); + singleton_override_ = NULL; +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/resource_tracker.h b/webkit/plugins/ppapi/resource_tracker.h new file mode 100644 index 0000000..7a5e002 --- /dev/null +++ b/webkit/plugins/ppapi/resource_tracker.h @@ -0,0 +1,149 @@ +// 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 WEBKIT_PLUGINS_PPAPI_RESOURCE_TRACKER_H_ +#define WEBKIT_PLUGINS_PPAPI_RESOURCE_TRACKER_H_ + +#include <map> +#include <utility> + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "base/hash_tables.h" +#include "base/ref_counted.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" + +namespace base { +template <typename T> struct DefaultLazyInstanceTraits; +} + +namespace webkit { +namespace ppapi { + +class PluginInstance; +class PluginModule; +class Resource; +class ResourceTrackerTest; + +// This class maintains a global list of all live pepper resources. It allows +// us to check resource ID validity and to map them to a specific module. +// +// This object is threadsafe. +class ResourceTracker { + public: + // Returns the pointer to the singleton object. + static ResourceTracker* Get(); + + // PP_Resources -------------------------------------------------------------- + + // 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 lookup 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; + + // Increment resource's plugin refcount. See ResourceAndRefCount comments + // below. + bool AddRefResource(PP_Resource res); + bool UnrefResource(PP_Resource res); + + // Forces the plugin refcount of the given resource to 0. This can be used to + // delete an object the plugin has leaked or whose lifetime is otherwise + // exceeded. + // + // Note that this may not necessarily delete the resource object since the + // regular refcount is maintained separately from the plugin refcount and + // random components in the Pepper implementation could still have + // references to it. + void ForceDeletePluginResourceRefs(PP_Resource res); + + // Returns the number of resources associated with this module. + // + // This is slow, use only for testing. + uint32 GetLiveObjectsForModule(PluginModule* module) const; + + // PP_Modules ---------------------------------------------------------------- + + // Adds a new plugin module to the list of tracked module, and returns a new + // module handle to identify it. + PP_Module AddModule(PluginModule* module); + + // Called when a plugin modulde was deleted and should no longer be tracked. + // The given handle should be one generated by AddModule. + void ModuleDeleted(PP_Module module); + + // Returns a pointer to the plugin modulde object associated with the given + // modulde handle. The return value will be NULL if the handle is invalid. + PluginModule* GetModule(PP_Module module); + + // PP_Instances -------------------------------------------------------------- + + // Adds a new plugin instance to the list of tracked instances, and returns a + // new instance handle to identify it. + PP_Instance AddInstance(PluginInstance* instance); + + // Called when a plugin instance was deleted and should no longer be tracked. + // The given handle should be one generated by AddInstance. + void InstanceDeleted(PP_Instance instance); + + // Returns a pointer to the plugin instance object associated with the given + // instance handle. The return value will be NULL if the handle is invalid. + PluginInstance* GetInstance(PP_Instance instance); + + private: + friend struct base::DefaultLazyInstanceTraits<ResourceTracker>; + friend class Resource; + friend class ResourceTrackerTest; + + // Prohibit creation other then by the Singleton class. + ResourceTracker(); + ~ResourceTracker(); + + // Adds the given resource to the tracker and assigns it a resource ID and + // refcount of 1. The assigned resource ID will be returned. Used only by the + // Resource class. + PP_Resource AddResource(Resource* resource); + + // Overrides the singleton object. This is used for tests which want to + // specify their own tracker (otherwise, you can get cross-talk between + // tests since the data will live into the subsequent tests). + static void SetSingletonOverride(ResourceTracker* tracker); + static void ClearSingletonOverride(); + + // See SetSingletonOverride above. + static ResourceTracker* singleton_override_; + + // Last assigned resource ID. + PP_Resource last_id_; + + // For each PP_Resource, keep the Resource* (as refptr) and plugin use count. + // This use count is different then Resource's RefCount, and is manipulated + // using this RefResource/UnrefResource. When it drops to zero, we just remove + // the resource from this resource tracker, but the resource object will be + // alive so long as some scoped_refptr still holds it's reference. This + // prevents plugins from forcing destruction of Resource objects. + typedef std::pair<scoped_refptr<Resource>, size_t> ResourceAndRefCount; + typedef base::hash_map<PP_Resource, ResourceAndRefCount> ResourceMap; + ResourceMap live_resources_; + + // Tracks all live instances. The pointers are non-owning, the PluginInstance + // destructor will notify us when the instance is deleted. + typedef std::map<PP_Instance, PluginInstance*> InstanceMap; + InstanceMap instance_map_; + + // Tracks all live modules. The pointers are non-owning, the PluginModule + // destructor will notify us when the module is deleted. + typedef std::map<PP_Module, PluginModule*> ModuleMap; + ModuleMap module_map_; + + DISALLOW_COPY_AND_ASSIGN(ResourceTracker); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_RESOURCE_TRACKER_H_ diff --git a/webkit/plugins/ppapi/resource_tracker_unittest.cc b/webkit/plugins/ppapi/resource_tracker_unittest.cc new file mode 100644 index 0000000..60910df --- /dev/null +++ b/webkit/plugins/ppapi/resource_tracker_unittest.cc @@ -0,0 +1,119 @@ +// 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 "webkit/plugins/ppapi/ppapi_unittest.h" + +#include "webkit/plugins/ppapi/resource_tracker.h" +#include "webkit/plugins/ppapi/mock_resource.h" + +namespace webkit { +namespace ppapi { + +namespace { + +class TrackedMockResource : public MockResource { + public: + static int tracked_objects_alive; + + TrackedMockResource(PluginModule* module) : MockResource(module) { + tracked_objects_alive++; + } + ~TrackedMockResource() { + tracked_objects_alive--; + } +}; + +int TrackedMockResource::tracked_objects_alive = 0; + +} // namespace + +class ResourceTrackerTest : public PpapiUnittest { + public: + ResourceTrackerTest() { + } + + virtual void SetUp() { + PpapiUnittest::SetUp(); + ResourceTracker::SetSingletonOverride(&tracker_); + } + virtual void TearDown() { + ResourceTracker::ClearSingletonOverride(); + PpapiUnittest::TearDown(); + } + + ResourceTracker& tracker() { return tracker_; } + + private: + ResourceTracker tracker_; +}; + +TEST_F(ResourceTrackerTest, Ref) { + ASSERT_EQ(0, TrackedMockResource::tracked_objects_alive); + EXPECT_EQ(0u, tracker().GetLiveObjectsForModule(module())); + { + scoped_refptr<TrackedMockResource> new_resource( + new TrackedMockResource(module())); + ASSERT_EQ(1, TrackedMockResource::tracked_objects_alive); + + // Since we haven't gotten a PP_Resource, it's not associated with the + // module. + EXPECT_EQ(0u, tracker().GetLiveObjectsForModule(module())); + } + ASSERT_EQ(0, TrackedMockResource::tracked_objects_alive); + + // Make a new resource and get it as a PP_Resource. + PP_Resource resource_id = 0; + { + scoped_refptr<TrackedMockResource> new_resource( + new TrackedMockResource(module())); + ASSERT_EQ(1, TrackedMockResource::tracked_objects_alive); + resource_id = new_resource->GetReference(); + EXPECT_EQ(1u, tracker().GetLiveObjectsForModule(module())); + + // Resource IDs should be consistent. + PP_Resource resource_id_2 = new_resource->GetReference(); + ASSERT_EQ(resource_id, resource_id_2); + } + + // This time it should not have been deleted since the PP_Resource carries + // a ref. + ASSERT_EQ(1, TrackedMockResource::tracked_objects_alive); + + // Now we have two refs, derefing twice should delete the object. + tracker().UnrefResource(resource_id); + ASSERT_EQ(1, TrackedMockResource::tracked_objects_alive); + tracker().UnrefResource(resource_id); + ASSERT_EQ(0, TrackedMockResource::tracked_objects_alive); +} + +TEST_F(ResourceTrackerTest, ForceDelete) { + // Make two resources. + scoped_refptr<TrackedMockResource> resource1( + new TrackedMockResource(module())); + PP_Resource pp_resource1 = resource1->GetReference(); + scoped_refptr<TrackedMockResource> resource2( + new TrackedMockResource(module())); + PP_Resource pp_resource2 = resource2->GetReference(); + + // Keep an "internal" ref to only the first (the PP_Resource also holds a + // ref to each resource on behalf of the plugin). + resource2 = NULL; + + ASSERT_EQ(2, TrackedMockResource::tracked_objects_alive); + EXPECT_EQ(2u, tracker().GetLiveObjectsForModule(module())); + + // Force delete both refs. + tracker().ForceDeletePluginResourceRefs(pp_resource1); + tracker().ForceDeletePluginResourceRefs(pp_resource2); + EXPECT_EQ(0u, tracker().GetLiveObjectsForModule(module())); + + // The resource we have a scoped_refptr to should still be alive. + ASSERT_EQ(1, TrackedMockResource::tracked_objects_alive); + resource1 = NULL; + ASSERT_EQ(0, TrackedMockResource::tracked_objects_alive); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/string.cc b/webkit/plugins/ppapi/string.cc new file mode 100644 index 0000000..d8b95de --- /dev/null +++ b/webkit/plugins/ppapi/string.cc @@ -0,0 +1,16 @@ +// 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 "webkit/plugins/ppapi/string.h" + +namespace webkit { +namespace ppapi { + +String::String(const char* str, uint32 len) : value_(str, len) {} + +String::~String() {} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/string.h b/webkit/plugins/ppapi/string.h new file mode 100644 index 0000000..6880b3b --- /dev/null +++ b/webkit/plugins/ppapi/string.h @@ -0,0 +1,32 @@ +// 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 WEBKIT_GLUE_PLUGINS_PEPPER_STRING_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_STRING_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/ref_counted.h" + +namespace webkit { +namespace ppapi { + +class String : public base::RefCountedThreadSafe<String> { + public: + String(const char* str, uint32 len); + virtual ~String(); + + const std::string& value() const { return value_; } + + private: + std::string value_; + + DISALLOW_COPY_AND_ASSIGN(String); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_STRING_H_ diff --git a/webkit/plugins/ppapi/var.cc b/webkit/plugins/ppapi/var.cc new file mode 100644 index 0000000..132cdfb --- /dev/null +++ b/webkit/plugins/ppapi/var.cc @@ -0,0 +1,872 @@ +// 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 "webkit/plugins/ppapi/var.h" + +#include <limits> + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/c/pp_var.h" +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/plugin_object.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "v8/include/v8.h" + +using WebKit::WebBindings; + +namespace webkit { +namespace ppapi { + +namespace { + +const char kInvalidObjectException[] = "Error: Invalid object"; +const char kInvalidPropertyException[] = "Error: Invalid property"; +const char kInvalidValueException[] = "Error: Invalid value"; +const char kUnableToGetPropertyException[] = "Error: Unable to get property"; +const char kUnableToSetPropertyException[] = "Error: Unable to set property"; +const char kUnableToRemovePropertyException[] = + "Error: Unable to remove property"; +const char kUnableToGetAllPropertiesException[] = + "Error: Unable to get all properties"; +const char kUnableToCallMethodException[] = "Error: Unable to call method"; +const char kUnableToConstructException[] = "Error: Unable to construct"; + +// --------------------------------------------------------------------------- +// Utilities + +// Converts the given PP_Var to an NPVariant, returning true on success. +// False means that the given variant is invalid. In this case, the result +// NPVariant will be set to a void one. +// +// The contents of the PP_Var will NOT be copied, so you need to ensure that +// the PP_Var remains valid while the resultant NPVariant is in use. +bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) { + switch (var.type) { + case PP_VARTYPE_UNDEFINED: + VOID_TO_NPVARIANT(*result); + break; + case PP_VARTYPE_NULL: + NULL_TO_NPVARIANT(*result); + break; + case PP_VARTYPE_BOOL: + BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result); + break; + case PP_VARTYPE_INT32: + INT32_TO_NPVARIANT(var.value.as_int, *result); + break; + case PP_VARTYPE_DOUBLE: + DOUBLE_TO_NPVARIANT(var.value.as_double, *result); + break; + case PP_VARTYPE_STRING: { + scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); + if (!string) { + VOID_TO_NPVARIANT(*result); + return false; + } + const std::string& value = string->value(); + STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result); + break; + } + case PP_VARTYPE_OBJECT: { + scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var)); + if (!object) { + VOID_TO_NPVARIANT(*result); + return false; + } + OBJECT_TO_NPVARIANT(object->np_object(), *result); + break; + } + default: + VOID_TO_NPVARIANT(*result); + return false; + } + return true; +} + +// ObjectAccessorTryCatch ------------------------------------------------------ + +// Automatically sets up a TryCatch for accessing the object identified by the +// given PP_Var. The module from the object will be used for the exception +// strings generated by the TryCatch. +// +// This will automatically retrieve the ObjectVar from the object and throw +// an exception if it's invalid. At the end of construction, if there is no +// exception, you know that there is no previously set exception, that the +// object passed in is valid and ready to use (via the object() getter), and +// that the TryCatch's module() getter is also set up properly and ready to +// use. +class ObjectAccessorTryCatch : public TryCatch { + public: + ObjectAccessorTryCatch(PP_Var object, PP_Var* exception) + : TryCatch(NULL, exception), + object_(ObjectVar::FromPPVar(object)) { + if (!object_) { + // No object or an invalid object was given. This means we have no module + // to associated with the exception text, so use the magic invalid object + // exception. + SetInvalidObjectException(); + } else { + // When the object is valid, we have a valid module to associate + set_module(object_->module()); + } + } + + ObjectVar* object() { return object_.get(); } + + protected: + scoped_refptr<ObjectVar> object_; + + DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch); +}; + +// ObjectAccessiorWithIdentifierTryCatch --------------------------------------- + +// Automatically sets up a TryCatch for accessing the identifier on the given +// object. This just extends ObjectAccessorTryCatch to additionally convert +// the given identifier to an NPIdentifier and validate it, throwing an +// exception if it's invalid. +// +// At the end of construction, if there is no exception, you know that there is +// no previously set exception, that the object passed in is valid and ready to +// use (via the object() getter), that the identifier is valid and ready to +// use (via the identifier() getter), and that the TryCatch's module() getter +// is also set up properly and ready to use. +class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch { + public: + ObjectAccessorWithIdentifierTryCatch(PP_Var object, + PP_Var identifier, + PP_Var* exception) + : ObjectAccessorTryCatch(object, exception), + identifier_(0) { + if (!has_exception()) { + identifier_ = Var::PPVarToNPIdentifier(identifier); + if (!identifier_) + SetException(kInvalidPropertyException); + } + } + + NPIdentifier identifier() const { return identifier_; } + + private: + NPIdentifier identifier_; + + DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch); +}; + +PP_Var RunJSFunction(PP_Var scope_var, + const char* function_script, + PP_Var* argv, + unsigned argc, + PP_Var* exception) { + TryCatch try_catch(NULL, exception); + if (try_catch.has_exception()) + return PP_MakeUndefined(); + + scoped_refptr<ObjectVar> obj = ObjectVar::FromPPVar(scope_var); + if (!obj) { + try_catch.SetInvalidObjectException(); + return PP_MakeUndefined(); + } + + try_catch.set_module(obj->module()); + + scoped_array<NPVariant> args; + if (argc) { + args.reset(new NPVariant[argc]); + for (uint32_t i = 0; i < argc; ++i) { + if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { + // This argument was invalid, throw an exception & give up. + try_catch.SetException(kInvalidValueException); + return PP_MakeUndefined(); + } + } + } + + NPVariant function_var; + VOID_TO_NPVARIANT(function_var); + NPString function_string = { function_script, strlen(function_script) }; + if (!WebBindings::evaluate(NULL, obj->np_object(), &function_string, + &function_var)) { + try_catch.SetException(kInvalidValueException); + return PP_MakeUndefined(); + } + DCHECK(NPVARIANT_IS_OBJECT(function_var)); + DCHECK(!try_catch.has_exception()); + + NPVariant result_var; + VOID_TO_NPVARIANT(result_var); + PP_Var result; + + if (WebBindings::invokeDefault(NULL, NPVARIANT_TO_OBJECT(function_var), + args.get(), argc, &result_var)) { + result = Var::NPVariantToPPVar(obj->module(), &result_var); + } else { + DCHECK(try_catch.has_exception()); + result = PP_MakeUndefined(); + } + + WebBindings::releaseVariantValue(&function_var); + WebBindings::releaseVariantValue(&result_var); + return result; +} + +// PPB_Var methods ------------------------------------------------------------- + +PP_Var VarFromUtf8(PP_Module module_id, const char* data, uint32_t len) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return PP_MakeNull(); + return StringVar::StringToPPVar(module, data, len); +} + +const char* VarToUtf8(PP_Var var, uint32_t* len) { + scoped_refptr<StringVar> str(StringVar::FromPPVar(var)); + if (!str) { + *len = 0; + return NULL; + } + *len = static_cast<uint32_t>(str->value().size()); + if (str->value().empty()) + return ""; // Don't return NULL on success. + return str->value().data(); +} + +PP_Var ConvertType(PP_Instance instance, + struct PP_Var var, + PP_VarType new_type, + PP_Var* exception) { + TryCatch try_catch(NULL, exception); + if (try_catch.has_exception()) + return PP_MakeUndefined(); + + if (var.type == new_type) + return var; + + PluginInstance* plugin_instance = + ResourceTracker::Get()->GetInstance(instance); + if (!plugin_instance) { + try_catch.SetInvalidObjectException(); + return PP_MakeUndefined(); + } + + try_catch.set_module(plugin_instance->module()); + PP_Var object = plugin_instance->GetWindowObject(); + + PP_Var params[] = { + var, + PP_MakeInt32(new_type), + PP_MakeInt32(PP_VARTYPE_NULL), + PP_MakeInt32(PP_VARTYPE_BOOL), + PP_MakeInt32(PP_VARTYPE_INT32), + PP_MakeInt32(PP_VARTYPE_DOUBLE), + PP_MakeInt32(PP_VARTYPE_STRING), + PP_MakeInt32(PP_VARTYPE_OBJECT) + }; + PP_Var result = RunJSFunction(object, + "(function(v, new_type, type_null, type_bool, type_int32, type_double," + " type_string, type_object) {" + " switch(new_type) {" + " case type_null: return null;" + " case type_bool: return Boolean(v);" + " case type_int32: case type_double: return Number(v);" + " case type_string: return String(v);" + " case type_object: return Object(v);" + " default: return undefined;" + " }})", + params, sizeof(params) / sizeof(PP_Var), exception); + + // Massage Number into the correct type. + if (new_type == PP_VARTYPE_INT32 && result.type == PP_VARTYPE_DOUBLE) { + double value = result.value.as_double; + // Exclusive test wouldn't deal with NaNs correctly. + if (value >= std::numeric_limits<int32_t>::max() + && value <= std::numeric_limits<int32_t>::min()) + result = PP_MakeInt32(static_cast<int32_t>(value)); + else + result = PP_MakeInt32(0); + } else if (new_type == PP_VARTYPE_DOUBLE && result.type == PP_VARTYPE_INT32) { + result = PP_MakeDouble(result.value.as_int); + } + + Var::PluginReleasePPVar(object); + return result; +} + +PP_Var BoolToPPVar(bool value) { + return PP_MakeBool(BoolToPPBool(value)); +} + +void DefineProperty(struct PP_Var object, + struct PP_ObjectProperty property, + PP_Var* exception) { + PP_Var params[] = { + object, property.name, + BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_HASVALUE)), + property.value, + BoolToPPVar(property.getter.type == PP_VARTYPE_OBJECT), + property.getter, + BoolToPPVar(property.setter.type == PP_VARTYPE_OBJECT), + property.setter, + BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_READONLY)), + BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTDELETE)), + BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTENUM)) + }; + + RunJSFunction(object, + "(function(o, name," + " has_value, value," + " has_getter, getter," + " has_setter, setter," + " modifier_readonly, modifier_dontdelete, modifier_dontenum) {" + " prop = { 'enumerable': !modifier_dontenum," + " 'configurable': !modifier_dontdelete };" + " if (has_value && !modifier_readonly) prop.writable = true;" + " if (has_value) prop.value = value;" + " if (has_getter) prop.get = getter;" + " if (has_setter) prop.set = setter;" + " return Object.defineProperty(o, name, prop); })", + params, sizeof(params) / sizeof(PP_Var), exception); +} + +PP_Bool HasProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) + return PP_FALSE; + return BoolToPPBool(WebBindings::hasProperty(NULL, + accessor.object()->np_object(), + accessor.identifier())); +} + +bool HasPropertyDeprecated(PP_Var var, + PP_Var name, + PP_Var* exception) { + return PPBoolToBool(HasProperty(var, name, exception)); +} + +bool HasMethodDeprecated(PP_Var var, + PP_Var name, + PP_Var* exception) { + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) + return false; + return WebBindings::hasMethod(NULL, accessor.object()->np_object(), + accessor.identifier()); +} + +PP_Var GetProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) + return PP_MakeUndefined(); + + NPVariant result; + if (!WebBindings::getProperty(NULL, accessor.object()->np_object(), + accessor.identifier(), &result)) { + // An exception may have been raised. + accessor.SetException(kUnableToGetPropertyException); + return PP_MakeUndefined(); + } + + PP_Var ret = Var::NPVariantToPPVar(accessor.object()->module(), &result); + WebBindings::releaseVariantValue(&result); + return ret; +} + +void EnumerateProperties(PP_Var var, + uint32_t* property_count, + PP_Var** properties, + PP_Var* exception) { + *properties = NULL; + *property_count = 0; + + ObjectAccessorTryCatch accessor(var, exception); + if (accessor.has_exception()) + return; + + NPIdentifier* identifiers = NULL; + uint32_t count = 0; + if (!WebBindings::enumerate(NULL, accessor.object()->np_object(), + &identifiers, &count)) { + accessor.SetException(kUnableToGetAllPropertiesException); + return; + } + + if (count == 0) + return; + + *property_count = count; + *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count)); + for (uint32_t i = 0; i < count; ++i) { + (*properties)[i] = Var::NPIdentifierToPPVar(accessor.object()->module(), + identifiers[i]); + } + free(identifiers); +} + +void SetPropertyDeprecated(PP_Var var, + PP_Var name, + PP_Var value, + PP_Var* exception) { + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) + return; + + NPVariant variant; + if (!PPVarToNPVariantNoCopy(value, &variant)) { + accessor.SetException(kInvalidValueException); + return; + } + if (!WebBindings::setProperty(NULL, accessor.object()->np_object(), + accessor.identifier(), &variant)) + accessor.SetException(kUnableToSetPropertyException); +} + +PP_Bool DeleteProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) + return PP_FALSE; + + return BoolToPPBool( + WebBindings::removeProperty(NULL, + accessor.object()->np_object(), + accessor.identifier())); +} + +void DeletePropertyDeprecated(PP_Var var, + PP_Var name, + PP_Var* exception) { + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) + return; + + if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(), + accessor.identifier())) + accessor.SetException(kUnableToRemovePropertyException); +} + +PP_Bool IsCallable(struct PP_Var object) { + PP_Var result = RunJSFunction(object, + "(function() { return typeof(this) == 'function' })", NULL, 0, NULL); + if (result.type == PP_VARTYPE_BOOL) + return result.value.as_bool; + return PP_FALSE; +} + +struct PP_Var Call(struct PP_Var object, + struct PP_Var this_object, + uint32_t argc, + struct PP_Var* argv, + struct PP_Var* exception) { + ObjectAccessorTryCatch accessor(object, exception); + if (accessor.has_exception()) + return PP_MakeUndefined(); + + scoped_array<NPVariant> args; + if (argc) { + args.reset(new NPVariant[argc]); + for (uint32_t i = 0; i < argc; ++i) { + if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { + // This argument was invalid, throw an exception & give up. + accessor.SetException(kInvalidValueException); + return PP_MakeUndefined(); + } + } + } + + NPVariant result; + if (!WebBindings::invokeDefault(NULL, accessor.object()->np_object(), + args.get(), argc, &result)) { + // An exception may have been raised. + accessor.SetException(kUnableToCallMethodException); + return PP_MakeUndefined(); + } + + PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result); + WebBindings::releaseVariantValue(&result); + return ret; +} + +PP_Var CallDeprecated(PP_Var var, + PP_Var method_name, + uint32_t argc, + PP_Var* argv, + PP_Var* exception) { + ObjectAccessorTryCatch accessor(var, exception); + if (accessor.has_exception()) + return PP_MakeUndefined(); + + NPIdentifier identifier; + if (method_name.type == PP_VARTYPE_UNDEFINED) { + identifier = NULL; + } else if (method_name.type == PP_VARTYPE_STRING) { + // Specifically allow only string functions to be called. + identifier = Var::PPVarToNPIdentifier(method_name); + if (!identifier) { + accessor.SetException(kInvalidPropertyException); + return PP_MakeUndefined(); + } + } else { + accessor.SetException(kInvalidPropertyException); + return PP_MakeUndefined(); + } + + scoped_array<NPVariant> args; + if (argc) { + args.reset(new NPVariant[argc]); + for (uint32_t i = 0; i < argc; ++i) { + if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { + // This argument was invalid, throw an exception & give up. + accessor.SetException(kInvalidValueException); + return PP_MakeUndefined(); + } + } + } + + bool ok; + + NPVariant result; + if (identifier) { + ok = WebBindings::invoke(NULL, accessor.object()->np_object(), + identifier, args.get(), argc, &result); + } else { + ok = WebBindings::invokeDefault(NULL, accessor.object()->np_object(), + args.get(), argc, &result); + } + + if (!ok) { + // An exception may have been raised. + accessor.SetException(kUnableToCallMethodException); + return PP_MakeUndefined(); + } + + PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result); + WebBindings::releaseVariantValue(&result); + return ret; +} + +PP_Var Construct(PP_Var var, + uint32_t argc, + PP_Var* argv, + PP_Var* exception) { + ObjectAccessorTryCatch accessor(var, exception); + if (accessor.has_exception()) + return PP_MakeUndefined(); + + scoped_array<NPVariant> args; + if (argc) { + args.reset(new NPVariant[argc]); + for (uint32_t i = 0; i < argc; ++i) { + if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { + // This argument was invalid, throw an exception & give up. + accessor.SetException(kInvalidValueException); + return PP_MakeUndefined(); + } + } + } + + NPVariant result; + if (!WebBindings::construct(NULL, accessor.object()->np_object(), + args.get(), argc, &result)) { + // An exception may have been raised. + accessor.SetException(kUnableToConstructException); + return PP_MakeUndefined(); + } + + PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result); + WebBindings::releaseVariantValue(&result); + return ret; +} + +bool IsInstanceOfDeprecated(PP_Var var, + const PPP_Class_Deprecated* ppp_class, + void** ppp_class_data) { + scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var)); + if (!object) + return false; // Not an object at all. + + return PluginObject::IsInstanceOf(object->np_object(), + ppp_class, ppp_class_data); +} + +PP_Var CreateObjectDeprecated(PP_Module module_id, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + PluginModule* module = ResourceTracker::Get()->GetModule(module_id); + if (!module) + return PP_MakeNull(); + return PluginObject::Create(module, ppp_class, ppp_class_data); +} + +const PPB_Var_Deprecated var_deprecated_interface = { + &Var::PluginAddRefPPVar, + &Var::PluginReleasePPVar, + &VarFromUtf8, + &VarToUtf8, + &HasPropertyDeprecated, + &HasMethodDeprecated, + &GetProperty, + &EnumerateProperties, + &SetPropertyDeprecated, + &DeletePropertyDeprecated, + &CallDeprecated, + &Construct, + &IsInstanceOfDeprecated, + &CreateObjectDeprecated +}; + +const PPB_Var var_interface = { + &Var::PluginAddRefPPVar, + &Var::PluginReleasePPVar, + &VarFromUtf8, + &VarToUtf8, + &ConvertType, + &DefineProperty, + &HasProperty, + &GetProperty, + &DeleteProperty, + &EnumerateProperties, + &IsCallable, + &Call, + &Construct, +}; + + +} // namespace + +// Var ------------------------------------------------------------------------- + +Var::Var(PluginModule* module) : Resource(module) { +} + +Var::~Var() { +} + +Var* Var::AsVar() { + return this; +} + +// static +PP_Var Var::NPVariantToPPVar(PluginModule* module, const NPVariant* variant) { + switch (variant->type) { + case NPVariantType_Void: + return PP_MakeUndefined(); + case NPVariantType_Null: + return PP_MakeNull(); + case NPVariantType_Bool: + return BoolToPPVar(NPVARIANT_TO_BOOLEAN(*variant)); + case NPVariantType_Int32: + return PP_MakeInt32(NPVARIANT_TO_INT32(*variant)); + case NPVariantType_Double: + return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant)); + case NPVariantType_String: + return StringVar::StringToPPVar( + module, + NPVARIANT_TO_STRING(*variant).UTF8Characters, + NPVARIANT_TO_STRING(*variant).UTF8Length); + case NPVariantType_Object: + return ObjectVar::NPObjectToPPVar(module, NPVARIANT_TO_OBJECT(*variant)); + } + NOTREACHED(); + return PP_MakeUndefined(); +} + +// static +NPIdentifier Var::PPVarToNPIdentifier(PP_Var var) { + switch (var.type) { + case PP_VARTYPE_STRING: { + scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); + if (!string) + return NULL; + return WebBindings::getStringIdentifier(string->value().c_str()); + } + case PP_VARTYPE_INT32: + return WebBindings::getIntIdentifier(var.value.as_int); + default: + return NULL; + } +} + +// static +PP_Var Var::NPIdentifierToPPVar(PluginModule* module, NPIdentifier id) { + const NPUTF8* string_value = NULL; + int32_t int_value = 0; + bool is_string = false; + WebBindings::extractIdentifierData(id, string_value, int_value, is_string); + if (is_string) + return StringVar::StringToPPVar(module, string_value); + + return PP_MakeInt32(int_value); +} + +// static +void Var::PluginAddRefPPVar(PP_Var var) { + if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) { + // TODO(brettw) consider checking that the ID is actually a var ID rather + // than some random other resource ID. + PP_Resource resource = static_cast<PP_Resource>(var.value.as_id); + if (!ResourceTracker::Get()->AddRefResource(resource)) + DLOG(WARNING) << "AddRefVar()ing a nonexistant string/object var."; + } +} + +// static +void Var::PluginReleasePPVar(PP_Var var) { + if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) { + // TODO(brettw) consider checking that the ID is actually a var ID rather + // than some random other resource ID. + PP_Resource resource = static_cast<PP_Resource>(var.value.as_id); + if (!ResourceTracker::Get()->UnrefResource(resource)) + DLOG(WARNING) << "ReleaseVar()ing a nonexistant string/object var."; + } +} + +// static +const PPB_Var_Deprecated* Var::GetDeprecatedInterface() { + return &var_deprecated_interface; +} + +const PPB_Var* Var::GetInterface() { + return &var_interface; +} + +// StringVar ------------------------------------------------------------------- + +StringVar::StringVar(PluginModule* module, const char* str, uint32 len) + : Var(module), + value_(str, len) { +} + +StringVar::~StringVar() { +} + +StringVar* StringVar::AsStringVar() { + return this; +} + +// static +PP_Var StringVar::StringToPPVar(PluginModule* module, const std::string& var) { + return StringToPPVar(module, var.c_str(), var.size()); +} + +// static +PP_Var StringVar::StringToPPVar(PluginModule* module, + const char* data, uint32 len) { + scoped_refptr<StringVar> str(new StringVar(module, data, len)); + if (!str || !IsStringUTF8(str->value())) + return PP_MakeNull(); + + PP_Var ret; + ret.type = PP_VARTYPE_STRING; + + // The caller takes ownership now. + ret.value.as_id = str->GetReference(); + return ret; +} + +// static +scoped_refptr<StringVar> StringVar::FromPPVar(PP_Var var) { + if (var.type != PP_VARTYPE_STRING) + return scoped_refptr<StringVar>(NULL); + PP_Resource resource = static_cast<PP_Resource>(var.value.as_id); + return Resource::GetAs<StringVar>(resource); +} + +// ObjectVar ------------------------------------------------------------- + +ObjectVar::ObjectVar(PluginModule* module, NPObject* np_object) + : Var(module), + np_object_(np_object) { + WebBindings::retainObject(np_object_); + module->AddNPObjectVar(this); +} + +ObjectVar::~ObjectVar() { + module()->RemoveNPObjectVar(this); + WebBindings::releaseObject(np_object_); +} + +ObjectVar* ObjectVar::AsObjectVar() { + return this; +} + +// static +PP_Var ObjectVar::NPObjectToPPVar(PluginModule* module, NPObject* object) { + scoped_refptr<ObjectVar> object_var(module->ObjectVarForNPObject(object)); + if (!object_var) // No object for this module yet, make a new one. + object_var = new ObjectVar(module, object); + + if (!object_var) + return PP_MakeUndefined(); + + // Convert to a PP_Var, GetReference will AddRef for us. + PP_Var result; + result.type = PP_VARTYPE_OBJECT; + result.value.as_id = object_var->GetReference(); + return result; +} + +// static +scoped_refptr<ObjectVar> ObjectVar::FromPPVar(PP_Var var) { + if (var.type != PP_VARTYPE_OBJECT) + return scoped_refptr<ObjectVar>(NULL); + PP_Resource resource = static_cast<PP_Resource>(var.value.as_id); + return Resource::GetAs<ObjectVar>(resource); +} + +// TryCatch -------------------------------------------------------------------- + +TryCatch::TryCatch(PluginModule* module, PP_Var* exception) + : module_(module), + has_exception_(exception && exception->type != PP_VARTYPE_UNDEFINED), + exception_(exception) { + WebBindings::pushExceptionHandler(&TryCatch::Catch, this); +} + +TryCatch::~TryCatch() { + WebBindings::popExceptionHandler(); +} + +void TryCatch::SetException(const char* message) { + if (!module_) { + // Don't have a module to make the string. + SetInvalidObjectException(); + return; + } + + if (!has_exception()) { + has_exception_ = true; + if (exception_) + *exception_ = StringVar::StringToPPVar(module_, message, strlen(message)); + } +} + +void TryCatch::SetInvalidObjectException() { + if (!has_exception()) { + has_exception_ = true; + // TODO(brettw) bug 54504: Have a global singleton string that can hold + // a generic error message. + if (exception_) + *exception_ = PP_MakeInt32(1); + } +} + +// static +void TryCatch::Catch(void* self, const char* message) { + static_cast<TryCatch*>(self)->SetException(message); +} + +} // namespace ppapi +} // namespace webkit + diff --git a/webkit/plugins/ppapi/var.h b/webkit/plugins/ppapi/var.h new file mode 100644 index 0000000..8f74733 --- /dev/null +++ b/webkit/plugins/ppapi/var.h @@ -0,0 +1,253 @@ +// 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 WEBKIT_PLUGINS_PPAPI_VAR_H_ +#define WEBKIT_PLUGINS_PPAPI_VAR_H_ + +#include <string> + +#include "webkit/plugins/ppapi/resource.h" + +struct PP_Var; +struct PPB_Var; +struct PPB_Var_Deprecated; +typedef struct NPObject NPObject; +typedef struct _NPVariant NPVariant; +typedef void* NPIdentifier; + +namespace webkit { +namespace ppapi { + +// Var ------------------------------------------------------------------------- + +// Represents a non-POD var. This is derived from a resource even though it +// isn't a resource from the plugin's perspective. This allows us to re-use +// the refcounting and the association with the module from the resource code. +class Var : public Resource { + public: + virtual ~Var(); + + // Resource overrides. + virtual Var* AsVar(); + + // Returns a PP_Var that corresponds to the given NPVariant. The contents of + // the NPVariant will be copied unless the NPVariant corresponds to an + // object. This will handle all Variant types including POD, strings, and + // objects. + // + // The returned PP_Var will have a refcount of 1, this passing ownership of + // the reference to the caller. This is suitable for returning to a plugin. + static PP_Var NPVariantToPPVar(PluginModule* module, + const NPVariant* variant); + + // Returns a NPIdentifier that corresponds to the given PP_Var. The contents + // of the PP_Var will be copied. Returns 0 if the given PP_Var is not a a + // string or integer type. + static NPIdentifier PPVarToNPIdentifier(PP_Var var); + + // Returns a PP_Var corresponding to the given identifier. In the case of + // a string identifier, the string will be allocated associated with the + // given module. A returned string will have a reference count of 1. + static PP_Var NPIdentifierToPPVar(PluginModule* module, NPIdentifier id); + + // Provides access to the manual refcounting of a PP_Var from the plugin's + // perspective. This is different than the AddRef/Release on this scoped + // object. This uses the ResourceTracker, which keeps a separate "plugin + // refcount" that prevents the plugin from messing up our refcounting or + // freeing something out from under us. + // + // You should not generally need to use these functions. However, if you + // call a plugin function that returns a var, it will transfer a ref to us + // (the caller) which in the case of a string or object var will need to + // be released. + // + // Example, assuming we're expecting the plugin to return a string: + // PP_Var rv = some_ppp_interface->DoSomething(a, b, c); + // + // // Get the string value. This will take a reference to the object which + // // will prevent it from being deleted out from under us when we call + // // PluginReleasePPVar(). + // scoped_refptr<StringVar> string(StringVar::FromPPVar(rv)); + // + // // Release the reference the plugin gave us when returning the value. + // // This is legal to do for all types of vars. + // Var::PluginReleasePPVar(rv); + // + // // Use the string. + // if (!string) + // return false; // It didn't return a proper string. + // UseTheString(string->value()); + static void PluginAddRefPPVar(PP_Var var); + static void PluginReleasePPVar(PP_Var var); + + // Returns the PPB_Var_Deprecated interface for the plugin to use. + static const PPB_Var_Deprecated* GetDeprecatedInterface(); + + // Returns the PPB_Var interface for the plugin to use. + static const PPB_Var* GetInterface(); + + protected: + // This can only be constructed as a StringVar or an ObjectVar. + explicit Var(PluginModule* module); + + private: + DISALLOW_COPY_AND_ASSIGN(Var); +}; + +// StringVar ------------------------------------------------------------------- + +// Represents a string-based Var. +// +// Returning a given string as a PP_Var: +// return StringVar::StringToPPVar(module, my_string); +// +// Converting a PP_Var to a string: +// scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); +// if (!string) +// return false; // Not a string or an invalid var. +// DoSomethingWithTheString(string->value()); +class StringVar : public Var { + public: + StringVar(PluginModule* module, const char* str, uint32 len); + virtual ~StringVar(); + + const std::string& value() const { return value_; } + + // Resource overrides. + virtual StringVar* AsStringVar(); + + // Helper function to create a PP_Var of type string that contains a copy of + // the given string. The input data must be valid UTF-8 encoded text, if it + // is not valid UTF-8, a NULL var will be returned. + // + // The return value will have a reference count of 1. Internally, this will + // create a StringVar, associate it with a module, and return the reference + // to it in the var. + static PP_Var StringToPPVar(PluginModule* module, const std::string& str); + static PP_Var StringToPPVar(PluginModule* module, + const char* str, uint32 len); + + // Helper function that converts a PP_Var to a string. This will return NULL + // if the PP_Var is not of string type or the string is invalid. + static scoped_refptr<StringVar> FromPPVar(PP_Var var); + + private: + std::string value_; + + DISALLOW_COPY_AND_ASSIGN(StringVar); +}; + +// ObjectVar ------------------------------------------------------------------- + +// Represents a JavaScript object Var. By itself, this represents random +// NPObjects that a given plugin (identified by the resource's module) wants to +// reference. If two different modules reference the same NPObject (like the +// "window" object), then there will be different ObjectVar's (and hence PP_Var +// IDs) for each module. This allows us to track all references owned by a +// given module and free them when the plugin exits independently of other +// plugins that may be running at the same time. +// +// See StringVar for examples, except obviously using NPObjects instead of +// strings. +class ObjectVar : public Var { + public: + virtual ~ObjectVar(); + + // Resource overrides. + virtual ObjectVar* AsObjectVar(); + + // Returns the underlying NPObject corresponding to this ObjectVar. + // Guaranteed non-NULL. + NPObject* np_object() const { return np_object_; } + + // Helper function to create a PP_Var of type object that contains the given + // NPObject for use byt he given module. Calling this function multiple times + // given the same module + NPObject results in the same PP_Var, assuming that + // there is still a PP_Var with a reference open to it from the previous + // call. + // + // The module is necessary because we can have different modules pointing to + // the same NPObject, and we want to keep their refs separate. + // + // If no ObjectVar currently exists corresponding to the NPObject, one is + // created associated with the given module. + static PP_Var NPObjectToPPVar(PluginModule* module, NPObject* object); + + // Helper function that converts a PP_Var to an object. This will return NULL + // if the PP_Var is not of object type or the object is invalid. + static scoped_refptr<ObjectVar> FromPPVar(PP_Var var); + + protected: + // You should always use FromNPObject to create an ObjectVar. This function + // guarantees that we maintain the 1:1 mapping between NPObject and + // ObjectVar. + ObjectVar(PluginModule* module, NPObject* np_object); + + private: + // Guaranteed non-NULL, this is the underlying object used by WebKit. We + // hold a reference to this object. + NPObject* np_object_; + + DISALLOW_COPY_AND_ASSIGN(ObjectVar); +}; + +// TryCatch -------------------------------------------------------------------- + +// Instantiate this object on the stack to catch V8 exceptions and pass them +// to an optional out parameter supplied by the plugin. +class TryCatch { + public: + // The given exception may be NULL if the consumer isn't interested in + // catching exceptions. If non-NULL, the given var will be updated if any + // exception is thrown (so it must outlive the TryCatch object). + // + // The module associated with the exception is passed so we know which module + // to associate any exception string with. It may be NULL if you don't know + // the module at construction time, in which case you should set it later + // by calling set_module(). + // + // If an exception is thrown when the module is NULL, setting *any* exception + // will result in using the InvalidObjectException. + TryCatch(PluginModule* module, PP_Var* exception); + ~TryCatch(); + + // Get and set the module. This may be NULL (see the constructor). + PluginModule* module() { return module_; } + void set_module(PluginModule* module) { module_ = module; } + + // Returns true is an exception has been thrown. This can be true immediately + // after construction if the var passed to the constructor is non-void. + bool has_exception() const { return has_exception_; } + + // Sets the given exception. If no module has been set yet, the message will + // be ignored (since we have no module to associate the string with) and the + // SetInvalidObjectException() will be used instead. + // + // If an exception has been previously set, this function will do nothing + // (normally you want only the first exception). + void SetException(const char* message); + + // Sets the exception to be a generic message contained in a magic string + // not associated with any module. + void SetInvalidObjectException(); + + private: + static void Catch(void* self, const char* message); + + PluginModule* module_; + + // True if an exception has been thrown. Since the exception itself may be + // NULL if the plugin isn't interested in getting the exception, this will + // always indicate if SetException has been called, regardless of whether + // the exception itself has been stored. + bool has_exception_; + + // May be null if the consumer isn't interesting in catching exceptions. + PP_Var* exception_; +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_VAR_H_ diff --git a/webkit/plugins/ppapi/var_object_class.cc b/webkit/plugins/ppapi/var_object_class.cc new file mode 100644 index 0000000..282ad72 --- /dev/null +++ b/webkit/plugins/ppapi/var_object_class.cc @@ -0,0 +1,286 @@ +// 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 "webkit/plugins/ppapi/var_object_class.h" + +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" +#include "webkit/plugins/ppapi/npapi_glue.h" +#include "webkit/plugins/ppapi/resource_tracker.h" +#include "webkit/plugins/ppapi/var.h" + +using WebKit::WebBindings; + +namespace webkit { +namespace ppapi { + +namespace { + +// VarObjectAccessorWithIdentifier --------------------------------------------- + +// Helper class for the new (PPB_Class) NPObject wrapper. This converts a call +// from WebKit where it gives us an NPObject and an NPIdentifier to an +// easily-accessible InstanceData (corresponding to the NPObject) and +// std::string and Property (corresponding to the NPIdentifier). +class VarObjectAccessorWithIdentifier { + public: + VarObjectAccessorWithIdentifier(NPObject* object, NPIdentifier identifier) + : exists_(false), + instance_(static_cast<VarObjectClass::InstanceData*>(object)), + property_(NULL) { + if (instance_) { + const NPUTF8* string_value = NULL; + int32_t int_value = 0; + bool is_string = false; + WebBindings::extractIdentifierData(identifier, string_value, int_value, + is_string); + if (is_string) { + property_name_ = string_value; + + const VarObjectClass::PropertyMap& properties = + instance_->object_class->properties(); + VarObjectClass::PropertyMap::const_iterator it = + properties.find(property_name_); + if (it != properties.end()) { + property_ = &it->second; + exists_ = true; + } + } + } + } + + // Return true if the object is valid, the identifier is valid, and the + // property with said name exists. + bool exists() const { return exists_; } + bool is_method() const { return exists() && property_->method; } + bool is_readable() const { return exists() && property_->getter; } + bool is_writable() const { + return exists() && property_->setter && property_->writable; + } + const VarObjectClass::InstanceData* instance() const { return instance_; } + const VarObjectClass::Property* property() const { return property_; } + PluginModule* module() const { + return instance_ ? instance_->object_class->module() : NULL; + } + + private: + bool exists_; + const VarObjectClass::InstanceData* instance_; + std::string property_name_; + const VarObjectClass::Property* property_; + + DISALLOW_COPY_AND_ASSIGN(VarObjectAccessorWithIdentifier); +}; + +NPObject* VarObjectClassAllocate(NPP npp, NPClass* the_class) { + return new VarObjectClass::InstanceData; +} + +void VarObjectClassDeallocate(NPObject* object) { + VarObjectClass::InstanceData* instance = + static_cast<VarObjectClass::InstanceData*>(object); + if (instance->object_class->instance_native_destructor()) + instance->object_class->instance_native_destructor()(instance->native_data); + delete instance; +} + +bool VarObjectClassHasMethod(NPObject* np_obj, NPIdentifier name) { + VarObjectAccessorWithIdentifier accessor(np_obj, name); + return accessor.is_method(); +} + +bool VarObjectClassInvoke(NPObject* np_obj, NPIdentifier name, + const NPVariant* args, uint32 arg_count, + NPVariant* result) { + VarObjectAccessorWithIdentifier accessor(np_obj, name); + if (!accessor.is_method()) + return false; + + PPResultAndExceptionToNPResult result_converter(np_obj, result); + PPVarArrayFromNPVariantArray arguments(accessor.module(), arg_count, args); + PPVarFromNPObject self(accessor.module(), np_obj); + + return result_converter.SetResult(accessor.property()->method( + accessor.instance()->native_data, self.var(), arguments.array(), arg_count, + result_converter.exception())); +} + +bool VarObjectClassInvokeDefault(NPObject* np_obj, + const NPVariant* args, + uint32 arg_count, + NPVariant* result) { + VarObjectClass::InstanceData* instance = + static_cast<VarObjectClass::InstanceData*>(np_obj); + if (!instance || !instance->object_class->instance_invoke()) + return false; + + PPResultAndExceptionToNPResult result_converter(np_obj, result); + PPVarArrayFromNPVariantArray arguments(instance->object_class->module(), + arg_count, args); + PPVarFromNPObject self(instance->object_class->module(), np_obj); + + return result_converter.SetResult(instance->object_class->instance_invoke()( + instance->native_data, self.var(), arguments.array(), arg_count, + result_converter.exception())); +} + +bool VarObjectClassHasProperty(NPObject* np_obj, NPIdentifier name) { + VarObjectAccessorWithIdentifier accessor(np_obj, name); + return accessor.is_readable(); +} + +bool VarObjectClassGetProperty(NPObject* np_obj, NPIdentifier name, + NPVariant* result) { + VarObjectAccessorWithIdentifier accessor(np_obj, name); + if (!accessor.is_readable()) { + return false; + } + + PPResultAndExceptionToNPResult result_converter(np_obj, result); + PPVarFromNPObject self(accessor.module(), np_obj); + + return result_converter.SetResult(accessor.property()->getter( + accessor.instance()->native_data, self.var(), 0, 0, + result_converter.exception())); +} + +bool VarObjectClassSetProperty(NPObject* np_obj, NPIdentifier name, + const NPVariant* variant) { + VarObjectAccessorWithIdentifier accessor(np_obj, name); + if (!accessor.is_writable()) { + return false; + } + + PPResultAndExceptionToNPResult result_converter(np_obj, NULL); + PPVarArrayFromNPVariantArray arguments(accessor.module(), 1, variant); + PPVarFromNPObject self(accessor.module(), np_obj); + + // Ignore return value. + Var::PluginReleasePPVar(accessor.property()->setter( + accessor.instance()->native_data, self.var(), arguments.array(), 1, + result_converter.exception())); + + return result_converter.CheckExceptionForNoResult(); +} + +bool VarObjectClassEnumerate(NPObject *np_obj, NPIdentifier **value, + uint32_t *count) { + VarObjectClass::InstanceData* instance = + static_cast<VarObjectClass::InstanceData*>(np_obj); + *count = 0; + *value = NULL; + if (!instance) + return false; + + const VarObjectClass::PropertyMap& properties = + instance->object_class->properties(); + + // Don't bother calculating the size of enumerable properties, just allocate + // enough for all and then fill it partially. + *value = static_cast<NPIdentifier*>( + malloc(sizeof(NPIdentifier) * properties.size())); + + NPIdentifier* inserter = *value; + for (VarObjectClass::PropertyMap::const_iterator i = properties.begin(); + i != properties.end(); ++i) + if (i->second.enumerable) + *inserter++ = WebBindings::getStringIdentifier(i->first.c_str()); + + *count = inserter - *value; + return true; +} + +NPClass objectclassvar_class = { + NP_CLASS_STRUCT_VERSION, + &VarObjectClassAllocate, + &VarObjectClassDeallocate, + NULL, + &VarObjectClassHasMethod, + &VarObjectClassInvoke, + &VarObjectClassInvokeDefault, + &VarObjectClassHasProperty, + &VarObjectClassGetProperty, + &VarObjectClassSetProperty, + NULL, + &VarObjectClassEnumerate, +}; + +// PPB_Class ------------------------------------------------------------------- + +PP_Resource Create(PP_Module module, PP_ClassDestructor destruct, + PP_ClassFunction invoke, PP_ClassProperty* properties) { + PluginModule* plugin_module = ResourceTracker::Get()->GetModule(module); + if (!properties || !plugin_module) + return 0; + scoped_refptr<VarObjectClass> cls = new VarObjectClass(plugin_module, + destruct, + invoke, + properties); + if (!cls) + return 0; + return cls->GetReference(); +} + +PP_Var Instantiate(PP_Resource class_object, void* native_data, + PP_Var* exception) { + scoped_refptr<VarObjectClass> object_class = + Resource::GetAs<VarObjectClass>(class_object); + if (!object_class) + return PP_MakeUndefined(); + NPObject* obj = WebBindings::createObject(NULL, &objectclassvar_class); + VarObjectClass::InstanceData* instance_data = + static_cast<VarObjectClass::InstanceData*>(obj); + instance_data->object_class = object_class; + instance_data->native_data = native_data; + return ObjectVar::NPObjectToPPVar(object_class->module(), obj); +} + +} // namespace + +// VarObjectClass -------------------------------------------------------------- + +VarObjectClass::Property::Property(const PP_ClassProperty& prop) + : method(prop.method), + getter(prop.getter), + setter(prop.setter), + writable(!(prop.modifiers & PP_OBJECTPROPERTY_MODIFIER_READONLY)), + enumerable(!(prop.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTENUM)) { +} + +VarObjectClass::InstanceData::InstanceData() : native_data(NULL) { +} + +VarObjectClass::VarObjectClass(PluginModule* module, + PP_ClassDestructor destruct, + PP_ClassFunction invoke, + PP_ClassProperty* properties) + : Resource(module), + instance_native_destructor_(destruct), + instance_invoke_(invoke) { + PP_ClassProperty* prop = properties; + while (prop->name) { + properties_.insert(std::make_pair(std::string(prop->name), + Property(*prop))); + ++prop; + } +} + +// virtual +VarObjectClass::~VarObjectClass() { +} + +VarObjectClass* VarObjectClass::AsVarObjectClass() { + return this; +} + +// static +const PPB_Class* VarObjectClass::GetInterface() { + static PPB_Class interface = { + &Create, + &Instantiate + }; + return &interface; +} + +} // namespace ppapi +} // namespace webkit diff --git a/webkit/plugins/ppapi/var_object_class.h b/webkit/plugins/ppapi/var_object_class.h new file mode 100644 index 0000000..7f9cb98 --- /dev/null +++ b/webkit/plugins/ppapi/var_object_class.h @@ -0,0 +1,75 @@ +// 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 WEBKIT_PLUGINS_PPAPI_CLASS_H_ +#define WEBKIT_PLUGINS_PPAPI_CLASS_H_ + +#include "webkit/plugins/ppapi/resource.h" + +#include <string> + +#include "base/hash_tables.h" +#include "base/ref_counted.h" +#include "ppapi/c/ppb_class.h" +#include "third_party/npapi/bindings/npruntime.h" + +namespace webkit { +namespace ppapi { + +class PluginModule; + +class VarObjectClass : public Resource { + public: + struct Property { + explicit Property(const PP_ClassProperty& prop); + + const PP_ClassFunction method; + const PP_ClassFunction getter; + const PP_ClassFunction setter; + const bool writable; + const bool enumerable; + }; + + struct InstanceData : public NPObject { + InstanceData(); + + scoped_refptr<VarObjectClass> object_class; + void* native_data; + }; + + typedef base::hash_map<std::string, Property> PropertyMap; + + VarObjectClass(PluginModule* module, PP_ClassDestructor destruct, + PP_ClassFunction invoke, PP_ClassProperty* properties); + virtual ~VarObjectClass(); + + // Resource override. + virtual VarObjectClass* AsVarObjectClass(); + + // Returns the PPB_Var interface for the plugin to use. + static const PPB_Class* GetInterface(); + + const PropertyMap &properties() const { return properties_; } + + PP_ClassDestructor instance_native_destructor() { + return instance_native_destructor_; + } + + PP_ClassFunction instance_invoke() { + return instance_invoke_; + } + + private: + PropertyMap properties_; + PP_ClassDestructor instance_native_destructor_; + PP_ClassFunction instance_invoke_; + + DISALLOW_COPY_AND_ASSIGN(VarObjectClass); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_CLASS_H_ + |