diff options
Diffstat (limited to 'webkit/glue/plugins')
25 files changed, 3842 insertions, 0 deletions
diff --git a/webkit/glue/plugins/pepper_audio.cc b/webkit/glue/plugins/pepper_audio.cc new file mode 100644 index 0000000..3babc2f --- /dev/null +++ b/webkit/glue/plugins/pepper_audio.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/glue/plugins/pepper_audio.h" + +#include "base/logging.h" +#include "third_party/ppapi/c/dev/ppb_audio_dev.h" +#include "third_party/ppapi/c/dev/ppb_audio_trusted_dev.h" + +namespace pepper { + +namespace { + +// PPB_AudioConfig functions + +PP_Resource CreateStereo16bit(PP_Module module_id, uint32_t sample_rate, + uint32_t sample_frame_count) { + PluginModule* module = PluginModule::FromPPModule(module_id); + if (!module) + return 0; + + scoped_refptr<AudioConfig> config(new AudioConfig(module, sample_rate, + sample_frame_count)); + return config->GetReference(); +} + +uint32_t GetSampleRate(PP_Resource config_id) { + scoped_refptr<AudioConfig> config = Resource::GetAs<AudioConfig>(config_id); + return config ? config->sample_rate() : 0; +} + +uint32_t GetSampleFrameCount(PP_Resource config_id) { + scoped_refptr<AudioConfig> config = Resource::GetAs<AudioConfig>(config_id); + return config ? config->sample_frame_count() : 0; +} + +// PPB_Audio functions + +PP_Resource Create(PP_Instance instance_id, PP_Resource config_id, + PPB_Audio_Callback callback, void* user_data) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + if (!instance) + return 0; + // TODO(neb): Require callback to be present for untrusted plugins. + scoped_refptr<Audio> audio(new Audio(instance->module())); + if (!audio->Init(instance->delegate(), config_id, callback, user_data)) + return 0; + return audio->GetReference(); +} + +PP_Resource GetCurrentConfiguration(PP_Resource audio_id) { + scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); + return audio ? audio->GetCurrentConfiguration() : 0; +} + +bool StartPlayback(PP_Resource audio_id) { + scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); + return audio ? audio->StartPlayback() : false; +} + +bool StopPlayback(PP_Resource audio_id) { + scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); + return audio ? audio->StopPlayback() : false; +} + +// PPB_AudioTrusted functions + +PP_Resource GetBuffer(PP_Resource audio_id) { + // TODO(neb): Implement me! + return 0; +} + +int GetOSDescriptor(PP_Resource audio_id) { + // TODO(neb): Implement me! + return -1; +} + +const PPB_AudioConfig_Dev ppb_audioconfig = { + &CreateStereo16bit, + &GetSampleRate, + &GetSampleFrameCount +}; + +const PPB_Audio_Dev ppb_audio = { + &Create, + &GetCurrentConfiguration, + &StartPlayback, + &StopPlayback, +}; + +const PPB_AudioTrusted_Dev ppb_audiotrusted = { + &GetBuffer, + &GetOSDescriptor +}; + +} // namespace + +AudioConfig::AudioConfig(PluginModule* module, int32_t sample_rate, + int32_t sample_frame_count) + : Resource(module), + sample_rate_(sample_rate), + sample_frame_count_(sample_frame_count) { +} + +const PPB_AudioConfig_Dev* AudioConfig::GetInterface() { + return &ppb_audioconfig; +} + +AudioConfig* AudioConfig::AsAudioConfig() { + return this; +} + +Audio::Audio(PluginModule* module) + : Resource(module), + playing_(false), + socket_(NULL), + shared_memory_(NULL), + shared_memory_size_(0), + callback_(NULL), + user_data_(NULL) { +} + +Audio::~Audio() { + // Calling ShutDown() makes sure StreamCreated cannot be called anymore. + audio_->ShutDown(); + // Closing the socket causes the thread to exit - wait for it. + socket_->Close(); + if (audio_thread_.get()) { + audio_thread_->Join(); + audio_thread_.reset(); + } + // Shared memory destructor will unmap the memory automatically. +} + + +const PPB_Audio_Dev* Audio::GetInterface() { + return &ppb_audio; +} + +const PPB_AudioTrusted_Dev* Audio::GetTrustedInterface() { + return &ppb_audiotrusted; +} + +Audio* Audio::AsAudio() { + return this; +} + +bool Audio::Init(PluginDelegate* plugin_delegate, PP_Resource config_id, + PPB_Audio_Callback callback, void* user_data) { + CHECK(!audio_.get()); + config_ = Resource::GetAs<AudioConfig>(config_id); + if (!config_) + return false; + callback_ = callback; + user_data_ = user_data; + // When the stream is created, we'll get called back in StreamCreated(). + audio_.reset(plugin_delegate->CreateAudio(config_->sample_rate(), + config_->sample_frame_count(), + this)); + return audio_.get() != NULL; +} + +bool Audio::StartPlayback() { + if (playing_) + return true; + + CHECK(!audio_thread_.get()); + if (callback_ && socket_.get()) { + audio_thread_.reset(new base::DelegateSimpleThread(this, + "plugin_audio_thread")); + audio_thread_->Start(); + } + playing_ = true; + return audio_->StartPlayback(); +} + +bool Audio::StopPlayback() { + if (!playing_) + return true; + + if (!audio_->StopPlayback()) + return false; + + if (audio_thread_.get()) { + audio_thread_->Join(); + audio_thread_.reset(); + } + playing_ = false; + return true; +} + +void Audio::StreamCreated(base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size, + base::SyncSocket::Handle socket_handle) { + socket_.reset(new base::SyncSocket(socket_handle)); + shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); + shared_memory_size_ = shared_memory_size; + + if (callback_) { + shared_memory_->Map(shared_memory_size_); + // In common case StartPlayback() was called before StreamCreated(). + if (playing_) { + audio_thread_.reset(new base::DelegateSimpleThread(this, + "plugin_audio_thread")); + audio_thread_->Start(); + } + } +} + +void Audio::Run() { + int pending_data; + void* buffer = shared_memory_->memory(); + + while (sizeof(pending_data) == + socket_->Receive(&pending_data, sizeof(pending_data)) && + pending_data >= 0) { + // Exit the thread on pause. + if (pending_data < 0) + return; + callback_(buffer, user_data_); + } +} + +} // namespace pepper + diff --git a/webkit/glue/plugins/pepper_audio.h b/webkit/glue/plugins/pepper_audio.h new file mode 100644 index 0000000..d9a9e86 --- /dev/null +++ b/webkit/glue/plugins/pepper_audio.h @@ -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 "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/shared_memory.h" +#include "base/simple_thread.h" +#include "base/sync_socket.h" +#include "third_party/ppapi/c/dev/ppb_audio_dev.h" +#include "third_party/ppapi/c/dev/ppb_audio_config_dev.h" +#include "third_party/ppapi/c/dev/ppb_audio_trusted_dev.h" +#include "webkit/glue/plugins/pepper_plugin_delegate.h" +#include "webkit/glue/plugins/pepper_plugin_instance.h" +#include "webkit/glue/plugins/pepper_plugin_module.h" +#include "webkit/glue/plugins/pepper_resource.h" + +#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_AUDIO_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_AUDIO_H_ + +namespace pepper { + +class PluginInstance; +class PluginModule; + +class AudioConfig : public Resource { + public: + AudioConfig(PluginModule* module, int32_t sample_rate, + int32_t sample_frame_count); + + static const PPB_AudioConfig_Dev* GetInterface(); + + uint32_t sample_rate() { return sample_rate_; } + uint32_t sample_frame_count() { return sample_frame_count_; } + + private: + // Resource override. + virtual AudioConfig* AsAudioConfig(); + + int sample_rate_; + int sample_frame_count_; +}; + +class Audio : public Resource, + public PluginDelegate::PlatformAudio::Client, + public base::DelegateSimpleThread::Delegate { + public: + explicit Audio(PluginModule* module); + virtual ~Audio(); + + static const PPB_Audio_Dev* GetInterface(); + static const PPB_AudioTrusted_Dev* GetTrustedInterface(); + + bool Init(PluginDelegate* plugin_delegate, PP_Resource config_id, + PPB_Audio_Callback callback, void* user_data); + + PP_Resource GetCurrentConfiguration() { + return config_->GetReference(); + } + + bool StartPlayback(); + + bool StopPlayback(); + + // Resource override. + virtual Audio* AsAudio(); + + private: + // pepper::PluginDelegate::PlatformAudio::Client implementation. + virtual void StreamCreated(base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size_, + base::SyncSocket::Handle socket); + // End of pepper::PluginDelegate::PlatformAudio::Client implementation. + + // Audio thread. DelegateSimpleThread::Delegate implementation. + virtual void Run(); + // End of DelegateSimpleThread::Delegate implementation. + + // True if playing the stream. + bool playing_; + + // AudioConfig used for creating this Audio object. + scoped_refptr<AudioConfig> config_; + + // PluginDelegate audio object that we delegate audio IPC through. + scoped_ptr<PluginDelegate::PlatformAudio> audio_; + + // Socket used to notify us when audio is ready to accept new samples. This + // pointer is created in StreamCreated(). + scoped_ptr<base::SyncSocket> socket_; + + // Sample buffer in shared memory. This pointer is created in + // StreamCreated(). The memory is only mapped when the audio thread is + // created. + scoped_ptr<base::SharedMemory> shared_memory_; + + // The size of the sample buffer in bytes. + size_t shared_memory_size_; + + // When the callback is set, this thread is spawned for calling it. + scoped_ptr<base::DelegateSimpleThread> audio_thread_; + + // Callback to call when audio is ready to accept new samples. + volatile PPB_Audio_Callback callback_; + + // User data pointer passed verbatim to the callback function. + void* user_data_; +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_AUDIO_H_ + diff --git a/webkit/glue/plugins/pepper_char_set.cc b/webkit/glue/plugins/pepper_char_set.cc new file mode 100644 index 0000000..1e5fc0a --- /dev/null +++ b/webkit/glue/plugins/pepper_char_set.cc @@ -0,0 +1,166 @@ +// 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/glue/plugins/pepper_char_set.h" + +#include <stdlib.h> + +#include "base/i18n/icu_string_conversions.h" +#include "third_party/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/glue/plugins/pepper_plugin_delegate.h" +#include "webkit/glue/plugins/pepper_plugin_instance.h" +#include "webkit/glue/plugins/pepper_plugin_module.h" +#include "webkit/glue/plugins/pepper_var.h" + +namespace pepper { + +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 pepper 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 = PluginModule::FromPPModule(pp_module); + if (!module) + return PP_MakeVoid(); + + 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* CharSet::GetInterface() { + return &ppb_charset; +} + +} // namespace pepper diff --git a/webkit/glue/plugins/pepper_char_set.h b/webkit/glue/plugins/pepper_char_set.h new file mode 100644 index 0000000..5abb54d --- /dev/null +++ b/webkit/glue/plugins/pepper_char_set.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_GLUE_PLUGINS_PEPPER_CHAR_SET_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_CHAR_SET_H_ + +struct PPB_CharSet_Dev; + +namespace pepper { + +class CharSet { + public: + // Returns a pointer to the interface implementing PPB_CharSet that is + // exposed to the plugin. + static const PPB_CharSet_Dev* GetInterface(); +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_CHAR_SET_H_ diff --git a/webkit/glue/plugins/pepper_cursor_control.cc b/webkit/glue/plugins/pepper_cursor_control.cc new file mode 100644 index 0000000..de3c166 --- /dev/null +++ b/webkit/glue/plugins/pepper_cursor_control.cc @@ -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. + +#include "webkit/glue/plugins/pepper_cursor_control.h" + +#include "base/logging.h" +#include "base/ref_counted.h" +#include "third_party/ppapi/c/dev/pp_cursor_type_dev.h" +#include "third_party/ppapi/c/dev/ppb_cursor_control_dev.h" +#include "third_party/ppapi/c/pp_point.h" +#include "third_party/ppapi/c/pp_resource.h" +#include "webkit/glue/plugins/pepper_image_data.h" +#include "webkit/glue/plugins/pepper_plugin_instance.h" +#include "webkit/glue/plugins/pepper_resource.h" + +namespace pepper { + +namespace { + +bool SetCursor(PP_Instance instance_id, + PP_CursorType_Dev type, + PP_Resource custom_image_id, + const PP_Point* hot_spot) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + if (!instance) + return false; + + scoped_refptr<ImageData> custom_image( + Resource::GetAs<ImageData>(custom_image_id)); + if (custom_image.get()) { + // TODO(neb): implement custom cursors. + NOTIMPLEMENTED(); + return false; + } + + return instance->SetCursor(type); +} + +bool LockCursor(PP_Instance instance_id) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + if (!instance) + return false; + + // TODO(neb): implement cursor locking. + return false; +} + +bool UnlockCursor(PP_Instance instance_id) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + if (!instance) + return false; + + // TODO(neb): implement cursor locking. + return false; +} + +bool HasCursorLock(PP_Instance instance_id) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + if (!instance) + return false; + + // TODO(neb): implement cursor locking. + return false; +} + +bool CanLockCursor(PP_Instance instance_id) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + if (!instance) + return false; + + // TODO(neb): implement cursor locking. + return false; +} + +const PPB_CursorControl_Dev cursor_control_interface = { + &SetCursor, + &LockCursor, + &UnlockCursor, + &HasCursorLock, + &CanLockCursor +}; + +} // namespace + +const PPB_CursorControl_Dev* GetCursorControlInterface() { + return &cursor_control_interface; +} + +} // namespace pepper + diff --git a/webkit/glue/plugins/pepper_cursor_control.h b/webkit/glue/plugins/pepper_cursor_control.h new file mode 100644 index 0000000..693fb4a --- /dev/null +++ b/webkit/glue/plugins/pepper_cursor_control.h @@ -0,0 +1,19 @@ +// 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_CURSOR_CONTROL_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_CURSOR_CONTROL_H_ + +struct PPB_CursorControl_Dev; + +namespace pepper { + +// 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 pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_CURSOR_CONTROL_H_ + diff --git a/webkit/glue/plugins/pepper_error_util.cc b/webkit/glue/plugins/pepper_error_util.cc new file mode 100644 index 0000000..a1b5c06 --- /dev/null +++ b/webkit/glue/plugins/pepper_error_util.cc @@ -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. + +#include "webkit/glue/plugins/pepper_error_util.h" + +#include "third_party/ppapi/c/pp_errors.h" + +namespace pepper { + +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: + return PP_ERROR_FAILED; + default: + return PP_ERROR_FAILED; + } +} + +} // namespace pepper diff --git a/webkit/glue/plugins/pepper_error_util.h b/webkit/glue/plugins/pepper_error_util.h new file mode 100644 index 0000000..12e715c --- /dev/null +++ b/webkit/glue/plugins/pepper_error_util.h @@ -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. + +#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_ERROR_UTIL_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_ERROR_UTIL_H_ + +#include "base/platform_file.h" + +namespace pepper { + +int PlatformFileErrorToPepperError(base::PlatformFileError error_code); + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_ERROR_UTIL_H_ diff --git a/webkit/glue/plugins/pepper_fullscreen_container.h b/webkit/glue/plugins/pepper_fullscreen_container.h new file mode 100644 index 0000000..5f67538 --- /dev/null +++ b/webkit/glue/plugins/pepper_fullscreen_container.h @@ -0,0 +1,33 @@ +// 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_FULLSCREEN_CONTAINER_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_FULLSCREEN_CONTAINER_H_ + +namespace WebKit { +struct WebRect; +} // namespace WebKit + +namespace pepper { + +// This class is like a lightweight WebPluginContainer for fullscreen pepper +// 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; + + // Destroys the fullscreen window. This also destroys the FullscreenContainer + // instance. + virtual void Destroy() = 0; +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_FULLSCREEN_CONTAINER_H_ diff --git a/webkit/glue/plugins/pepper_graphics_2d.cc b/webkit/glue/plugins/pepper_graphics_2d.cc new file mode 100644 index 0000000..5011f87 --- /dev/null +++ b/webkit/glue/plugins/pepper_graphics_2d.cc @@ -0,0 +1,563 @@ +// 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/glue/plugins/pepper_graphics_2d.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 "third_party/ppapi/c/pp_errors.h" +#include "third_party/ppapi/c/pp_module.h" +#include "third_party/ppapi/c/pp_rect.h" +#include "third_party/ppapi/c/pp_resource.h" +#include "third_party/ppapi/c/ppb_graphics_2d.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "webkit/glue/plugins/pepper_image_data.h" +#include "webkit/glue/plugins/pepper_plugin_instance.h" +#include "webkit/glue/plugins/pepper_plugin_module.h" + +#if defined(OS_MACOSX) +#include "base/mac_util.h" +#include "base/scoped_cftyperef.h" +#endif + +namespace pepper { + +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; +} + +PP_Resource Create(PP_Module module_id, + const PP_Size* size, + bool is_always_opaque) { + PluginModule* module = PluginModule::FromPPModule(module_id); + if (!module) + return 0; + + scoped_refptr<Graphics2D> context(new Graphics2D(module)); + if (!context->Init(size->width, size->height, is_always_opaque)) + return 0; + return context->GetReference(); +} + +bool IsGraphics2D(PP_Resource resource) { + return !!Resource::GetAs<Graphics2D>(resource); +} + +bool Describe(PP_Resource device_context, + PP_Size* size, + bool* is_always_opaque) { + scoped_refptr<Graphics2D> context( + Resource::GetAs<Graphics2D>(device_context)); + if (!context) + return false; + return context->Describe(size, is_always_opaque); +} + +bool PaintImageData(PP_Resource device_context, + PP_Resource image, + const PP_Point* top_left, + const PP_Rect* src_rect) { + scoped_refptr<Graphics2D> context( + Resource::GetAs<Graphics2D>(device_context)); + if (!context) + return false; + return context->PaintImageData(image, top_left, src_rect); +} + +bool Scroll(PP_Resource device_context, + const PP_Rect* clip_rect, + const PP_Point* amount) { + scoped_refptr<Graphics2D> context( + Resource::GetAs<Graphics2D>(device_context)); + if (!context) + return false; + return context->Scroll(clip_rect, amount); +} + +bool ReplaceContents(PP_Resource device_context, PP_Resource image) { + scoped_refptr<Graphics2D> context( + Resource::GetAs<Graphics2D>(device_context)); + if (!context) + return false; + return context->ReplaceContents(image); +} + +int32_t Flush(PP_Resource device_context, + PP_CompletionCallback callback) { + scoped_refptr<Graphics2D> context( + Resource::GetAs<Graphics2D>(device_context)); + 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 Graphics2D::QueuedOperation { + enum Type { + PAINT, + SCROLL, + REPLACE + }; + + QueuedOperation(Type t) + : type(t), + paint_x(0), + paint_y(0), + scroll_dx(0), + scroll_dy(0) { + } + + Type type; + + // Valid when type == PAINT. + scoped_refptr<ImageData> paint_image; + int paint_x, paint_y; + gfx::Rect paint_src_rect; + + // Valid when type == SCROLL. + gfx::Rect scroll_clip_rect; + int scroll_dx, scroll_dy; + + // Valid when type == REPLACE. + scoped_refptr<ImageData> replace_image; +}; + +Graphics2D::Graphics2D(PluginModule* module) + : Resource(module), + bound_instance_(NULL), + flushed_any_data_(false), + offscreen_flush_pending_(false), + is_always_opaque_(false) { +} + +Graphics2D::~Graphics2D() { +} + +// static +const PPB_Graphics2D* Graphics2D::GetInterface() { + return &ppb_graphics_2d; +} + +bool Graphics2D::Init(int width, int height, bool is_always_opaque) { + // The underlying ImageData will validate the dimensions. + image_data_ = new ImageData(module()); + if (!image_data_->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width, height, true) || + !image_data_->Map()) { + image_data_ = NULL; + return false; + } + is_always_opaque_ = is_always_opaque; + return true; +} + +bool Graphics2D::Describe(PP_Size* size, bool* is_always_opaque) { + size->width = image_data_->width(); + size->height = image_data_->height(); + *is_always_opaque = false; // TODO(brettw) implement this. + return true; +} + +bool Graphics2D::PaintImageData(PP_Resource image, + const PP_Point* top_left, + const PP_Rect* src_rect) { + if (!top_left) + return false; + + scoped_refptr<ImageData> image_resource(Resource::GetAs<ImageData>(image)); + if (!image_resource) + return false; + + QueuedOperation operation(QueuedOperation::PAINT); + operation.paint_image = image_resource; + if (!ValidateAndConvertRect(src_rect, image_resource->width(), + image_resource->height(), + &operation.paint_src_rect)) + return false; + + // Validate the bitmap position using the previously-validated rect, 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 false; + if (y64 + static_cast<int64>(operation.paint_src_rect.y()) < 0 || + y64 + static_cast<int64>(operation.paint_src_rect.bottom()) > + image_data_->height()) + return false; + operation.paint_x = top_left->x; + operation.paint_y = top_left->y; + + queued_operations_.push_back(operation); + return true; +} + +bool Graphics2D::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 false; + + // 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() || + dx <= -image_data_->height() || dy >= image_data_->height()) + return true; + + operation.scroll_dx = dx; + operation.scroll_dy = dy; + + queued_operations_.push_back(operation); + return false; +} + +bool Graphics2D::ReplaceContents(PP_Resource image) { + scoped_refptr<ImageData> image_resource(Resource::GetAs<ImageData>(image)); + if (!image_resource) + return false; + if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL) + return false; + + if (image_resource->width() != image_data_->width() || + image_resource->height() != image_data_->height()) + return false; + + QueuedOperation operation(QueuedOperation::REPLACE); + operation.replace_image = image_resource; + queued_operations_.push_back(operation); + + return true; +} + +int32_t Graphics2D::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; + + gfx::Rect changed_rect; + 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; + } + changed_rect = changed_rect.Union(op_rect); + } + queued_operations_.clear(); + flushed_any_data_ = true; + + // 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_ && !changed_rect.IsEmpty()) + visible_changed_rect = bound_instance_->clip().Intersect(changed_rect); + + if (bound_instance_ && !visible_changed_rect.IsEmpty()) { + unpainted_flush_callback_.Set(callback); + bound_instance_->InvalidateRect(visible_changed_rect); + } else { + // There's nothing visible to invalidate so just schedule the callback to + // execute in the next round of the message loop. + ScheduleOffscreenCallback(FlushCallbackData(callback)); + } + return PP_ERROR_WOULDBLOCK; +} + +bool Graphics2D::ReadImageData(PP_Resource image, + const PP_Point* top_left) { + // Get and validate the image object to paint into. + scoped_refptr<ImageData> image_resource(Resource::GetAs<ImageData>(image)); + if (!image_resource) + return false; + if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL) + 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; + skia::PlatformCanvas* dest_canvas = image_resource->mapped_canvas(); + + SkIRect src_irect = { x, y, + x + image_resource->width(), + y + image_resource->height() }; + SkRect dest_rect = { SkIntToScalar(0), + SkIntToScalar(0), + SkIntToScalar(image_resource->width()), + SkIntToScalar(image_resource->height()) }; + + // We want to replace the contents of the bitmap rather than blend. + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + dest_canvas->drawBitmapRect(*image_data_->GetMappedBitmap(), + &src_irect, dest_rect, &paint); + return true; +} + +bool Graphics2D::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 Graphics2D::Paint(WebKit::WebCanvas* canvas, + const gfx::Rect& plugin_rect, + const gfx::Rect& paint_rect) { + // We're guaranteed to have a mapped canvas since we mapped it in Init(). + const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap(); + +#if defined(OS_MACOSX) + SkAutoLockPixels lock(backing_bitmap); + + scoped_cftyperef<CGDataProviderRef> data_provider( + CGDataProviderCreateWithData( + NULL, backing_bitmap.getAddr32(0, 0), + backing_bitmap.rowBytes() * backing_bitmap.height(), NULL)); + scoped_cftyperef<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 Graphics2D::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 Graphics2D::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 Graphics2D::ExecutePaintImageData(ImageData* 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()) }; + + // 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 Graphics2D::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 Graphics2D::ExecuteReplaceContents(ImageData* image, + gfx::Rect* invalidated_rect) { + image_data_->Swap(image); + *invalidated_rect = gfx::Rect(0, 0, + image_data_->width(), image_data_->height()); +} + +void Graphics2D::ScheduleOffscreenCallback(const FlushCallbackData& callback) { + DCHECK(!HasPendingFlush()); + offscreen_flush_pending_ = true; + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(this, + &Graphics2D::ExecuteOffscreenCallback, + callback)); +} + +void Graphics2D::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 Graphics2D::HasPendingFlush() const { + return !unpainted_flush_callback_.is_null() || + !painted_flush_callback_.is_null() || + offscreen_flush_pending_; +} + +} // namespace pepper diff --git a/webkit/glue/plugins/pepper_graphics_2d.h b/webkit/glue/plugins/pepper_graphics_2d.h new file mode 100644 index 0000000..3af84de --- /dev/null +++ b/webkit/glue/plugins/pepper_graphics_2d.h @@ -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. + +#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_2D_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_2D_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "third_party/ppapi/c/pp_completion_callback.h" +#include "third_party/ppapi/c/ppb_graphics_2d.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h" +#include "webkit/glue/plugins/pepper_resource.h" + +struct PPB_Graphics2D; + +namespace gfx { +class Rect; +} + +namespace pepper { + +class ImageData; +class PluginInstance; +class PluginModule; + +class Graphics2D : public Resource { + public: + Graphics2D(PluginModule* module); + virtual ~Graphics2D(); + + // 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 Graphics2D* AsGraphics2D() { return this; } + + // PPB_Graphics2D functions. + bool Describe(PP_Size* size, bool* is_always_opaque); + bool PaintImageData(PP_Resource image, + const PP_Point* top_left, + const PP_Rect* src_rect); + bool Scroll(const PP_Rect* clip_rect, const PP_Point* amount); + bool ReplaceContents(PP_Resource image); + 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(); + + ImageData* 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(ImageData* 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(ImageData* 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<ImageData> 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(Graphics2D); +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_2D_H_ diff --git a/webkit/glue/plugins/pepper_graphics_3d.cc b/webkit/glue/plugins/pepper_graphics_3d.cc new file mode 100644 index 0000000..18e5cd1 --- /dev/null +++ b/webkit/glue/plugins/pepper_graphics_3d.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/glue/plugins/pepper_graphics_3d.h" + +#include "gpu/command_buffer/common/command_buffer.h" +#include "base/singleton.h" +#include "base/thread_local.h" +#include "third_party/ppapi/c/dev/ppb_graphics_3d_dev.h" +#include "webkit/glue/plugins/pepper_plugin_instance.h" + +namespace pepper { + +namespace { + +struct CurrentContextTag {}; +typedef Singleton<base::ThreadLocalPointer<Graphics3D>, + DefaultSingletonTraits<base::ThreadLocalPointer<Graphics3D> >, + CurrentContextTag> CurrentContextKey; + +// Size of the transfer buffer. +enum { kTransferBufferSize = 512 * 1024 }; + +bool IsGraphics3D(PP_Resource resource) { + return !!Resource::GetAs<Graphics3D>(resource); +} + +bool GetConfigs(int32_t* configs, int32_t config_size, int32_t* num_config) { + // TODO(neb): Implement me! + return false; +} + +bool ChooseConfig(const int32_t* attrib_list, int32_t* configs, + int32_t config_size, int32_t* num_config) { + // TODO(neb): Implement me! + return false; +} + +bool GetConfigAttrib(int32_t config, int32_t attribute, int32_t* value) { + // TODO(neb): Implement me! + return 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 = PluginInstance::FromPPInstance(instance_id); + if (!instance) { + return 0; + } + + scoped_refptr<Graphics3D> context(new Graphics3D(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; +} + +bool MakeCurrent(PP_Resource graphics3d) { + if (!graphics3d) { + Graphics3D::ResetCurrent(); + return true; + } else { + scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d)); + return context.get() && context->MakeCurrent(); + } +} + +PP_Resource GetCurrentContext() { + Graphics3D* currentContext = Graphics3D::GetCurrent(); + return currentContext ? currentContext->GetReference() : 0; +} + +bool SwapBuffers(PP_Resource graphics3d) { + scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d)); + return context && context->SwapBuffers(); +} + +uint32_t GetError() { + // TODO(neb): Figure out error checking. + return PP_GRAPHICS_3D_ERROR_SUCCESS; +} + +const PPB_Graphics3D_Dev ppb_graphics3d = { + &IsGraphics3D, + &GetConfigs, + &ChooseConfig, + &GetConfigAttrib, + &QueryString, + &CreateContext, + &GetProcAddress, + &MakeCurrent, + &GetCurrentContext, + &SwapBuffers, + &GetError +}; + +} // namespace + +Graphics3D::Graphics3D(PluginModule* module) + : Resource(module), + command_buffer_(NULL), + transfer_buffer_id_(0), + method_factory3d_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +const PPB_Graphics3D_Dev* Graphics3D::GetInterface() { + return &ppb_graphics3d; +} + +Graphics3D* Graphics3D::GetCurrent() { + return CurrentContextKey::get()->Get(); +} + +void Graphics3D::ResetCurrent() { + CurrentContextKey::get()->Set(NULL); +} + +Graphics3D::~Graphics3D() { + Destroy(); +} + +bool Graphics3D::Init(PP_Instance instance_id, int32_t config, + const int32_t* attrib_list) { + PluginInstance* instance = PluginInstance::FromPPInstance(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()) + return false; + + if (!platform_context_->Init(instance->position(), + instance->clip())) { + platform_context_.reset(); + return false; + } + command_buffer_ = platform_context_->GetCommandBuffer(); + gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_)); + gpu::Buffer buffer = command_buffer_->GetRingBuffer(); + if (gles2_helper_->Initialize(buffer.size)) { + transfer_buffer_id_ = + command_buffer_->CreateTransferBuffer(kTransferBufferSize); + gpu::Buffer transfer_buffer = + command_buffer_->GetTransferBuffer(transfer_buffer_id_); + if (transfer_buffer.ptr) { + gles2_implementation_.reset(new gpu::gles2::GLES2Implementation( + gles2_helper_.get(), + transfer_buffer.size, + transfer_buffer.ptr, + transfer_buffer_id_, + false)); + platform_context_->SetNotifyRepaintTask( + method_factory3d_.NewRunnableMethod(&Graphics3D::HandleRepaint, + instance_id)); + return true; + } + } + + // Tear everything down if initialization failed. + Destroy(); + return false; +} + +bool Graphics3D::MakeCurrent() { + if (!command_buffer_) + return false; + + CurrentContextKey::get()->Set(this); + + // Don't request latest error status from service. Just use the locally + // cached information from the last flush. + // TODO(apatrick): I'm not sure if this should actually change the + // current context if it fails. For now it gets changed even if it fails + // becuase making GL calls with a NULL context crashes. + // TODO(neb): Figure out error checking. +// if (command_buffer_->GetCachedError() != gpu::error::kNoError) +// return false; + return true; +} + +bool Graphics3D::SwapBuffers() { + if (!command_buffer_) + return false; + + // Don't request latest error status from service. Just use the locally cached + // information from the last flush. + // TODO(neb): Figure out error checking. +// if (command_buffer_->GetCachedError() != gpu::error::kNoError) +// return false; + + gles2_implementation_->SwapBuffers(); + return true; +} + +void Graphics3D::Destroy() { + if (GetCurrent() == this) { + ResetCurrent(); + } + + method_factory3d_.RevokeAll(); + + gles2_implementation_.reset(); + + if (command_buffer_ && transfer_buffer_id_ != 0) { + command_buffer_->DestroyTransferBuffer(transfer_buffer_id_); + transfer_buffer_id_ = 0; + } + + gles2_helper_.reset(); + + // Platform context owns the command buffer. + platform_context_.reset(); + command_buffer_ = NULL; +} + +void Graphics3D::HandleRepaint(PP_Instance instance_id) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + if (instance) { + instance->Graphics3DContextLost(); + if (platform_context_.get()) { + platform_context_->SetNotifyRepaintTask( + method_factory3d_.NewRunnableMethod(&Graphics3D::HandleRepaint, + instance_id)); + } + } +} + +} // namespace pepper + diff --git a/webkit/glue/plugins/pepper_graphics_3d.h b/webkit/glue/plugins/pepper_graphics_3d.h new file mode 100644 index 0000000..16258ed --- /dev/null +++ b/webkit/glue/plugins/pepper_graphics_3d.h @@ -0,0 +1,85 @@ +// 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_GRAPHICS_3D_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_3D_H_ + +#include "base/scoped_ptr.h" +#include "gpu/command_buffer/client/gles2_cmd_helper.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "third_party/ppapi/c/pp_instance.h" +#include "webkit/glue/plugins/pepper_plugin_delegate.h" +#include "webkit/glue/plugins/pepper_resource.h" + +namespace gfx { +class Rect; +} // namespace gfx + +namespace gpu { +class CommandBuffer; +} // namespace gpu + +struct PPB_Graphics3D_Dev; +struct PPB_OpenGLES_Dev; + +namespace pepper { + +class Graphics3D : public Resource { + public: + explicit Graphics3D(PluginModule* module); + + virtual ~Graphics3D(); + + static const PPB_Graphics3D_Dev* GetInterface(); + static const PPB_OpenGLES_Dev* GetOpenGLESInterface(); + + static bool Shutdown(); + + static Graphics3D* GetCurrent(); + + static void ResetCurrent(); + + // Resource override. + virtual Graphics3D* AsGraphics3D() { + return this; + } + + bool Init(PP_Instance instance_id, int32_t config, + const int32_t* attrib_list); + + bool MakeCurrent(); + + bool SwapBuffers(); + + gpu::gles2::GLES2Implementation* impl() { + return gles2_implementation_.get(); + } + + private: + void HandleRepaint(PP_Instance instance_id); + void Destroy(); + + // PluginDelegate's 3D Context. Responsible for providing the command buffer. + scoped_ptr<PluginDelegate::PlatformContext3D> platform_context_; + + // Command buffer is owned by the platform context. + gpu::CommandBuffer* command_buffer_; + + // GLES2 Command Helper instance. + scoped_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_; + + // ID of the transfer buffer. + int32_t transfer_buffer_id_; + + // GLES2 Implementation instance. + scoped_ptr<gpu::gles2::GLES2Implementation> gles2_implementation_; + + // Runnable methods that must be cancelled when the 3D context is destroyed. + ScopedRunnableMethodFactory<Graphics3D> method_factory3d_; +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_3D_H_ + diff --git a/webkit/glue/plugins/pepper_graphics_3d_gl.cc b/webkit/glue/plugins/pepper_graphics_3d_gl.cc new file mode 100644 index 0000000..897e459 --- /dev/null +++ b/webkit/glue/plugins/pepper_graphics_3d_gl.cc @@ -0,0 +1,716 @@ +// 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/glue/plugins/pepper_graphics_3d.h" + +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "third_party/ppapi/c/dev/ppb_opengles_dev.h" + +namespace pepper { + +namespace { + +void ActiveTexture(GLenum texture) { + Graphics3D::GetCurrent()->impl()->ActiveTexture(texture); +} +void AttachShader(GLuint program, GLuint shader) { + Graphics3D::GetCurrent()->impl()->AttachShader(program, shader); +} +void BindAttribLocation(GLuint program, GLuint index, const char* name) { + Graphics3D::GetCurrent()->impl()->BindAttribLocation(program, index, name); +} +void BindBuffer(GLenum target, GLuint buffer) { + Graphics3D::GetCurrent()->impl()->BindBuffer(target, buffer); +} +void BindFramebuffer(GLenum target, GLuint framebuffer) { + Graphics3D::GetCurrent()->impl()->BindFramebuffer(target, framebuffer); +} +void BindRenderbuffer(GLenum target, GLuint renderbuffer) { + Graphics3D::GetCurrent()->impl()->BindRenderbuffer(target, renderbuffer); +} +void BindTexture(GLenum target, GLuint texture) { + Graphics3D::GetCurrent()->impl()->BindTexture(target, texture); +} +void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + Graphics3D::GetCurrent()->impl()->BlendColor(red, green, blue, alpha); +} +void BlendEquation(GLenum mode) { + Graphics3D::GetCurrent()->impl()->BlendEquation(mode); +} +void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { + Graphics3D::GetCurrent()->impl()->BlendEquationSeparate(modeRGB, modeAlpha); +} +void BlendFunc(GLenum sfactor, GLenum dfactor) { + Graphics3D::GetCurrent()->impl()->BlendFunc(sfactor, dfactor); +} +void BlendFuncSeparate( + GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { + Graphics3D::GetCurrent()->impl()->BlendFuncSeparate( + srcRGB, dstRGB, srcAlpha, dstAlpha); +} +void BufferData( + GLenum target, GLsizeiptr size, const void* data, GLenum usage) { + Graphics3D::GetCurrent()->impl()->BufferData(target, size, data, usage); +} +void BufferSubData( + GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { + Graphics3D::GetCurrent()->impl()->BufferSubData(target, offset, size, data); +} +GLenum CheckFramebufferStatus(GLenum target) { + return Graphics3D::GetCurrent()->impl()->CheckFramebufferStatus(target); +} +void Clear(GLbitfield mask) { + Graphics3D::GetCurrent()->impl()->Clear(mask); +} +void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + Graphics3D::GetCurrent()->impl()->ClearColor(red, green, blue, alpha); +} +void ClearDepthf(GLclampf depth) { + Graphics3D::GetCurrent()->impl()->ClearDepthf(depth); +} +void ClearStencil(GLint s) { + Graphics3D::GetCurrent()->impl()->ClearStencil(s); +} +void ColorMask( + GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { + Graphics3D::GetCurrent()->impl()->ColorMask(red, green, blue, alpha); +} +void CompileShader(GLuint shader) { + Graphics3D::GetCurrent()->impl()->CompileShader(shader); +} +void CompressedTexImage2D( + GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, const void* data) { + Graphics3D::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) { + Graphics3D::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) { + Graphics3D::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) { + Graphics3D::GetCurrent()->impl()->CopyTexSubImage2D( + target, level, xoffset, yoffset, x, y, width, height); +} +GLuint CreateProgram() { + return Graphics3D::GetCurrent()->impl()->CreateProgram(); +} +GLuint CreateShader(GLenum type) { + return Graphics3D::GetCurrent()->impl()->CreateShader(type); +} +void CullFace(GLenum mode) { + Graphics3D::GetCurrent()->impl()->CullFace(mode); +} +void DeleteBuffers(GLsizei n, const GLuint* buffers) { + Graphics3D::GetCurrent()->impl()->DeleteBuffers(n, buffers); +} +void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { + Graphics3D::GetCurrent()->impl()->DeleteFramebuffers(n, framebuffers); +} +void DeleteProgram(GLuint program) { + Graphics3D::GetCurrent()->impl()->DeleteProgram(program); +} +void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { + Graphics3D::GetCurrent()->impl()->DeleteRenderbuffers(n, renderbuffers); +} +void DeleteShader(GLuint shader) { + Graphics3D::GetCurrent()->impl()->DeleteShader(shader); +} +void DeleteTextures(GLsizei n, const GLuint* textures) { + Graphics3D::GetCurrent()->impl()->DeleteTextures(n, textures); +} +void DepthFunc(GLenum func) { + Graphics3D::GetCurrent()->impl()->DepthFunc(func); +} +void DepthMask(GLboolean flag) { + Graphics3D::GetCurrent()->impl()->DepthMask(flag); +} +void DepthRangef(GLclampf zNear, GLclampf zFar) { + Graphics3D::GetCurrent()->impl()->DepthRangef(zNear, zFar); +} +void DetachShader(GLuint program, GLuint shader) { + Graphics3D::GetCurrent()->impl()->DetachShader(program, shader); +} +void Disable(GLenum cap) { + Graphics3D::GetCurrent()->impl()->Disable(cap); +} +void DisableVertexAttribArray(GLuint index) { + Graphics3D::GetCurrent()->impl()->DisableVertexAttribArray(index); +} +void DrawArrays(GLenum mode, GLint first, GLsizei count) { + Graphics3D::GetCurrent()->impl()->DrawArrays(mode, first, count); +} +void DrawElements( + GLenum mode, GLsizei count, GLenum type, const void* indices) { + Graphics3D::GetCurrent()->impl()->DrawElements(mode, count, type, indices); +} +void Enable(GLenum cap) { + Graphics3D::GetCurrent()->impl()->Enable(cap); +} +void EnableVertexAttribArray(GLuint index) { + Graphics3D::GetCurrent()->impl()->EnableVertexAttribArray(index); +} +void Finish() { + Graphics3D::GetCurrent()->impl()->Finish(); +} +void Flush() { + Graphics3D::GetCurrent()->impl()->Flush(); +} +void FramebufferRenderbuffer( + GLenum target, GLenum attachment, GLenum renderbuffertarget, + GLuint renderbuffer) { + Graphics3D::GetCurrent()->impl()->FramebufferRenderbuffer( + target, attachment, renderbuffertarget, renderbuffer); +} +void FramebufferTexture2D( + GLenum target, GLenum attachment, GLenum textarget, GLuint texture, + GLint level) { + Graphics3D::GetCurrent()->impl()->FramebufferTexture2D( + target, attachment, textarget, texture, level); +} +void FrontFace(GLenum mode) { + Graphics3D::GetCurrent()->impl()->FrontFace(mode); +} +void GenBuffers(GLsizei n, GLuint* buffers) { + Graphics3D::GetCurrent()->impl()->GenBuffers(n, buffers); +} +void GenerateMipmap(GLenum target) { + Graphics3D::GetCurrent()->impl()->GenerateMipmap(target); +} +void GenFramebuffers(GLsizei n, GLuint* framebuffers) { + Graphics3D::GetCurrent()->impl()->GenFramebuffers(n, framebuffers); +} +void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) { + Graphics3D::GetCurrent()->impl()->GenRenderbuffers(n, renderbuffers); +} +void GenTextures(GLsizei n, GLuint* textures) { + Graphics3D::GetCurrent()->impl()->GenTextures(n, textures); +} +void GetActiveAttrib( + GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, + GLenum* type, char* name) { + Graphics3D::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) { + Graphics3D::GetCurrent()->impl()->GetActiveUniform( + program, index, bufsize, length, size, type, name); +} +void GetAttachedShaders( + GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) { + Graphics3D::GetCurrent()->impl()->GetAttachedShaders( + program, maxcount, count, shaders); +} +GLint GetAttribLocation(GLuint program, const char* name) { + return Graphics3D::GetCurrent()->impl()->GetAttribLocation(program, name); +} +void GetBooleanv(GLenum pname, GLboolean* params) { + Graphics3D::GetCurrent()->impl()->GetBooleanv(pname, params); +} +void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetBufferParameteriv( + target, pname, params); +} +GLenum GetError() { + return Graphics3D::GetCurrent()->impl()->GetError(); +} +void GetFloatv(GLenum pname, GLfloat* params) { + Graphics3D::GetCurrent()->impl()->GetFloatv(pname, params); +} +void GetFramebufferAttachmentParameteriv( + GLenum target, GLenum attachment, GLenum pname, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetFramebufferAttachmentParameteriv( + target, attachment, pname, params); +} +void GetIntegerv(GLenum pname, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetIntegerv(pname, params); +} +void GetProgramiv(GLuint program, GLenum pname, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetProgramiv(program, pname, params); +} +void GetProgramInfoLog( + GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) { + Graphics3D::GetCurrent()->impl()->GetProgramInfoLog( + program, bufsize, length, infolog); +} +void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetRenderbufferParameteriv( + target, pname, params); +} +void GetShaderiv(GLuint shader, GLenum pname, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetShaderiv(shader, pname, params); +} +void GetShaderInfoLog( + GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) { + Graphics3D::GetCurrent()->impl()->GetShaderInfoLog( + shader, bufsize, length, infolog); +} +void GetShaderPrecisionFormat( + GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { + Graphics3D::GetCurrent()->impl()->GetShaderPrecisionFormat( + shadertype, precisiontype, range, precision); +} +void GetShaderSource( + GLuint shader, GLsizei bufsize, GLsizei* length, char* source) { + Graphics3D::GetCurrent()->impl()->GetShaderSource( + shader, bufsize, length, source); +} +const GLubyte* GetString(GLenum name) { + return Graphics3D::GetCurrent()->impl()->GetString(name); +} +void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { + Graphics3D::GetCurrent()->impl()->GetTexParameterfv(target, pname, params); +} +void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetTexParameteriv(target, pname, params); +} +void GetUniformfv(GLuint program, GLint location, GLfloat* params) { + Graphics3D::GetCurrent()->impl()->GetUniformfv(program, location, params); +} +void GetUniformiv(GLuint program, GLint location, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetUniformiv(program, location, params); +} +GLint GetUniformLocation(GLuint program, const char* name) { + return Graphics3D::GetCurrent()->impl()->GetUniformLocation(program, name); +} +void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) { + Graphics3D::GetCurrent()->impl()->GetVertexAttribfv(index, pname, params); +} +void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) { + Graphics3D::GetCurrent()->impl()->GetVertexAttribiv(index, pname, params); +} +void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) { + Graphics3D::GetCurrent()->impl()->GetVertexAttribPointerv( + index, pname, pointer); +} +void Hint(GLenum target, GLenum mode) { + Graphics3D::GetCurrent()->impl()->Hint(target, mode); +} +GLboolean IsBuffer(GLuint buffer) { + return Graphics3D::GetCurrent()->impl()->IsBuffer(buffer); +} +GLboolean IsEnabled(GLenum cap) { + return Graphics3D::GetCurrent()->impl()->IsEnabled(cap); +} +GLboolean IsFramebuffer(GLuint framebuffer) { + return Graphics3D::GetCurrent()->impl()->IsFramebuffer(framebuffer); +} +GLboolean IsProgram(GLuint program) { + return Graphics3D::GetCurrent()->impl()->IsProgram(program); +} +GLboolean IsRenderbuffer(GLuint renderbuffer) { + return Graphics3D::GetCurrent()->impl()->IsRenderbuffer(renderbuffer); +} +GLboolean IsShader(GLuint shader) { + return Graphics3D::GetCurrent()->impl()->IsShader(shader); +} +GLboolean IsTexture(GLuint texture) { + return Graphics3D::GetCurrent()->impl()->IsTexture(texture); +} +void LineWidth(GLfloat width) { + Graphics3D::GetCurrent()->impl()->LineWidth(width); +} +void LinkProgram(GLuint program) { + Graphics3D::GetCurrent()->impl()->LinkProgram(program); +} +void PixelStorei(GLenum pname, GLint param) { + Graphics3D::GetCurrent()->impl()->PixelStorei(pname, param); +} +void PolygonOffset(GLfloat factor, GLfloat units) { + Graphics3D::GetCurrent()->impl()->PolygonOffset(factor, units); +} +void ReadPixels( + GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, + void* pixels) { + Graphics3D::GetCurrent()->impl()->ReadPixels( + x, y, width, height, format, type, pixels); +} +void ReleaseShaderCompiler() { + Graphics3D::GetCurrent()->impl()->ReleaseShaderCompiler(); +} +void RenderbufferStorage( + GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { + Graphics3D::GetCurrent()->impl()->RenderbufferStorage( + target, internalformat, width, height); +} +void SampleCoverage(GLclampf value, GLboolean invert) { + Graphics3D::GetCurrent()->impl()->SampleCoverage(value, invert); +} +void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) { + Graphics3D::GetCurrent()->impl()->Scissor(x, y, width, height); +} +void ShaderBinary( + GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, + GLsizei length) { + Graphics3D::GetCurrent()->impl()->ShaderBinary( + n, shaders, binaryformat, binary, length); +} +void ShaderSource( + GLuint shader, GLsizei count, const char** str, const GLint* length) { + Graphics3D::GetCurrent()->impl()->ShaderSource(shader, count, str, length); +} +void StencilFunc(GLenum func, GLint ref, GLuint mask) { + Graphics3D::GetCurrent()->impl()->StencilFunc(func, ref, mask); +} +void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) { + Graphics3D::GetCurrent()->impl()->StencilFuncSeparate(face, func, ref, mask); +} +void StencilMask(GLuint mask) { + Graphics3D::GetCurrent()->impl()->StencilMask(mask); +} +void StencilMaskSeparate(GLenum face, GLuint mask) { + Graphics3D::GetCurrent()->impl()->StencilMaskSeparate(face, mask); +} +void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) { + Graphics3D::GetCurrent()->impl()->StencilOp(fail, zfail, zpass); +} +void StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { + Graphics3D::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) { + Graphics3D::GetCurrent()->impl()->TexImage2D( + target, level, internalformat, width, height, border, format, type, + pixels); +} +void TexParameterf(GLenum target, GLenum pname, GLfloat param) { + Graphics3D::GetCurrent()->impl()->TexParameterf(target, pname, param); +} +void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params) { + Graphics3D::GetCurrent()->impl()->TexParameterfv(target, pname, params); +} +void TexParameteri(GLenum target, GLenum pname, GLint param) { + Graphics3D::GetCurrent()->impl()->TexParameteri(target, pname, param); +} +void TexParameteriv(GLenum target, GLenum pname, const GLint* params) { + Graphics3D::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) { + Graphics3D::GetCurrent()->impl()->TexSubImage2D( + target, level, xoffset, yoffset, width, height, format, type, pixels); +} +void Uniform1f(GLint location, GLfloat x) { + Graphics3D::GetCurrent()->impl()->Uniform1f(location, x); +} +void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) { + Graphics3D::GetCurrent()->impl()->Uniform1fv(location, count, v); +} +void Uniform1i(GLint location, GLint x) { + Graphics3D::GetCurrent()->impl()->Uniform1i(location, x); +} +void Uniform1iv(GLint location, GLsizei count, const GLint* v) { + Graphics3D::GetCurrent()->impl()->Uniform1iv(location, count, v); +} +void Uniform2f(GLint location, GLfloat x, GLfloat y) { + Graphics3D::GetCurrent()->impl()->Uniform2f(location, x, y); +} +void Uniform2fv(GLint location, GLsizei count, const GLfloat* v) { + Graphics3D::GetCurrent()->impl()->Uniform2fv(location, count, v); +} +void Uniform2i(GLint location, GLint x, GLint y) { + Graphics3D::GetCurrent()->impl()->Uniform2i(location, x, y); +} +void Uniform2iv(GLint location, GLsizei count, const GLint* v) { + Graphics3D::GetCurrent()->impl()->Uniform2iv(location, count, v); +} +void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) { + Graphics3D::GetCurrent()->impl()->Uniform3f(location, x, y, z); +} +void Uniform3fv(GLint location, GLsizei count, const GLfloat* v) { + Graphics3D::GetCurrent()->impl()->Uniform3fv(location, count, v); +} +void Uniform3i(GLint location, GLint x, GLint y, GLint z) { + Graphics3D::GetCurrent()->impl()->Uniform3i(location, x, y, z); +} +void Uniform3iv(GLint location, GLsizei count, const GLint* v) { + Graphics3D::GetCurrent()->impl()->Uniform3iv(location, count, v); +} +void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { + Graphics3D::GetCurrent()->impl()->Uniform4f(location, x, y, z, w); +} +void Uniform4fv(GLint location, GLsizei count, const GLfloat* v) { + Graphics3D::GetCurrent()->impl()->Uniform4fv(location, count, v); +} +void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) { + Graphics3D::GetCurrent()->impl()->Uniform4i(location, x, y, z, w); +} +void Uniform4iv(GLint location, GLsizei count, const GLint* v) { + Graphics3D::GetCurrent()->impl()->Uniform4iv(location, count, v); +} +void UniformMatrix2fv( + GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + Graphics3D::GetCurrent()->impl()->UniformMatrix2fv( + location, count, transpose, value); +} +void UniformMatrix3fv( + GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + Graphics3D::GetCurrent()->impl()->UniformMatrix3fv( + location, count, transpose, value); +} +void UniformMatrix4fv( + GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + Graphics3D::GetCurrent()->impl()->UniformMatrix4fv( + location, count, transpose, value); +} +void UseProgram(GLuint program) { + Graphics3D::GetCurrent()->impl()->UseProgram(program); +} +void ValidateProgram(GLuint program) { + Graphics3D::GetCurrent()->impl()->ValidateProgram(program); +} +void VertexAttrib1f(GLuint indx, GLfloat x) { + Graphics3D::GetCurrent()->impl()->VertexAttrib1f(indx, x); +} +void VertexAttrib1fv(GLuint indx, const GLfloat* values) { + Graphics3D::GetCurrent()->impl()->VertexAttrib1fv(indx, values); +} +void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) { + Graphics3D::GetCurrent()->impl()->VertexAttrib2f(indx, x, y); +} +void VertexAttrib2fv(GLuint indx, const GLfloat* values) { + Graphics3D::GetCurrent()->impl()->VertexAttrib2fv(indx, values); +} +void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) { + Graphics3D::GetCurrent()->impl()->VertexAttrib3f(indx, x, y, z); +} +void VertexAttrib3fv(GLuint indx, const GLfloat* values) { + Graphics3D::GetCurrent()->impl()->VertexAttrib3fv(indx, values); +} +void VertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { + Graphics3D::GetCurrent()->impl()->VertexAttrib4f(indx, x, y, z, w); +} +void VertexAttrib4fv(GLuint indx, const GLfloat* values) { + Graphics3D::GetCurrent()->impl()->VertexAttrib4fv(indx, values); +} +void VertexAttribPointer( + GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, + const void* ptr) { + Graphics3D::GetCurrent()->impl()->VertexAttribPointer( + indx, size, type, normalized, stride, ptr); +} +void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) { + Graphics3D::GetCurrent()->impl()->Viewport(x, y, width, height); +} +void SwapBuffers() { + Graphics3D::GetCurrent()->impl()->SwapBuffers(); +} +GLuint GetMaxValueInBuffer( + GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) { + return Graphics3D::GetCurrent()->impl()->GetMaxValueInBuffer( + buffer_id, count, type, offset); +} +void GenSharedIds( + GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) { + Graphics3D::GetCurrent()->impl()->GenSharedIds( + namespace_id, id_offset, n, ids); +} +void DeleteSharedIds(GLuint namespace_id, GLsizei n, const GLuint* ids) { + Graphics3D::GetCurrent()->impl()->DeleteSharedIds(namespace_id, n, ids); +} +void RegisterSharedIds(GLuint namespace_id, GLsizei n, const GLuint* ids) { + Graphics3D::GetCurrent()->impl()->RegisterSharedIds(namespace_id, n, ids); +} +GLboolean CommandBufferEnable(const char* feature) { + return Graphics3D::GetCurrent()->impl()->CommandBufferEnable(feature); +} +void* MapBufferSubData( + GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) { + return Graphics3D::GetCurrent()->impl()->MapBufferSubData( + target, offset, size, access); +} +void UnmapBufferSubData(const void* mem) { + Graphics3D::GetCurrent()->impl()->UnmapBufferSubData(mem); +} +void* MapTexSubImage2D( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLenum format, GLenum type, GLenum access) { + return Graphics3D::GetCurrent()->impl()->MapTexSubImage2D( + target, level, xoffset, yoffset, width, height, format, type, access); +} +void UnmapTexSubImage2D(const void* mem) { + Graphics3D::GetCurrent()->impl()->UnmapTexSubImage2D(mem); +} + +const 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, + &GetMaxValueInBuffer, + &GenSharedIds, + &DeleteSharedIds, + &RegisterSharedIds, + &CommandBufferEnable, + &MapBufferSubData, + &UnmapBufferSubData, + &MapTexSubImage2D, + &UnmapTexSubImage2D +}; + +} // namespace + +const PPB_OpenGLES_Dev* Graphics3D::GetOpenGLESInterface() { + return &ppb_opengles; +} + +} // namespace pepper + diff --git a/webkit/glue/plugins/pepper_plugin_object.cc b/webkit/glue/plugins/pepper_plugin_object.cc new file mode 100644 index 0000000..c0a7cd6 --- /dev/null +++ b/webkit/glue/plugins/pepper_plugin_object.cc @@ -0,0 +1,601 @@ +// 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/glue/plugins/pepper_plugin_object.h" + +#include "base/logging.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 "third_party/ppapi/c/pp_var.h" +#include "third_party/ppapi/c/ppb_var.h" +#include "third_party/ppapi/c/ppp_class.h" +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" +#include "webkit/glue/plugins/pepper_plugin_module.h" +#include "webkit/glue/plugins/pepper_string.h" +#include "webkit/glue/plugins/pepper_var.h" + +using WebKit::WebBindings; + +namespace pepper { + +namespace { + +const char kInvalidValueException[] = "Error: Invalid value"; +const char kInvalidPluginValue[] = "Error: Plugin returned invalid value."; + +// --------------------------------------------------------------------------- +// 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) { + switch (var.type) { + case PP_VARTYPE_VOID: + 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; +} + +// 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) + : 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() { + for (size_t i = 0; i < size_; i++) + Var::PluginReleasePPVar(array_[i]); + } + + PP_Var* array() { return array_.get(); } + + private: + size_t size_; + scoped_array<PP_Var> array_; + + DISALLOW_COPY_AND_ASSIGN(PPVarArrayFromNPVariantArray); +}; + +// 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. This class does not take a ref, so it must remain + // valid for the lifetime of this object. + // + // 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(PluginObject* object_var, + NPVariant* np_result) + : object_var_(object_var), + np_result_(np_result), + exception_(PP_MakeVoid()), + success_(false), + checked_exception_(false) { + } + + ~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_); + } + + // Returns true if an exception has been set. + bool has_exception() const { return exception_.type != PP_VARTYPE_VOID; } + + // 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 { + DCHECK(checked_exception_); + 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) { + 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_->GetNPObject(), + 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 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 IgnoreException() { + checked_exception_ = true; + } + + private: + // Throws the current exception to JS. The exception must be set. + void ThrowException() { + scoped_refptr<StringVar> string(StringVar::FromPPVar(exception_)); + if (string) { + WebBindings::setException(object_var_->GetNPObject(), + string->value().c_str()); + } + } + + PluginObject* 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); +}; + +// 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) + : object_(PluginObject::FromNPObject(object)), + identifier_(PP_MakeVoid()) { + if (object_) { + identifier_ = Var::NPIdentifierToPPVar(object_->module(), identifier); + if (identifier_.type == PP_VARTYPE_INT32 && !allow_integer_identifier) + identifier_.type = PP_VARTYPE_VOID; // Make the identifier invalid. + } + } + + ~NPObjectAccessorWithIdentifier() { + Var::PluginReleasePPVar(identifier_); + } + + // Returns true if both the object and identifier are valid. + bool is_valid() const { + return object_ && identifier_.type != PP_VARTYPE_VOID; + } + + PluginObject* object() { return object_; } + PP_Var identifier() const { return identifier_; } + + private: + PluginObject* object_; + PP_Var identifier_; + + DISALLOW_COPY_AND_ASSIGN(NPObjectAccessorWithIdentifier); +}; + +// NPObject implementation in terms of PPP_Class ------------------------------- + +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(), 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(), 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, result); + + result_converter.SetResult(obj->ppp_class()->Call( + obj->ppp_class_data(), PP_MakeVoid(), 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(), 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(), 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(), 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(), 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, 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, 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* 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* 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* 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 pepper diff --git a/webkit/glue/plugins/pepper_plugin_object.h b/webkit/glue/plugins/pepper_plugin_object.h new file mode 100644 index 0000000..7715a81 --- /dev/null +++ b/webkit/glue/plugins/pepper_plugin_object.h @@ -0,0 +1,89 @@ +// 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_PLUGIN_OBJECT_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_OBJECT_H_ + +#include <string> + +#include "base/basictypes.h" + +struct PP_Var; +struct PPP_Class; +typedef struct NPObject NPObject; +typedef struct _NPVariant NPVariant; + +namespace pepper { + +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* ppp_class, + void* ppp_class_data); + + PluginModule* module() const { return module_; } + + const PPP_Class* 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* 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* 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* ppp_class_; + void* ppp_class_data_; + + DISALLOW_COPY_AND_ASSIGN(PluginObject); +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_OBJECT_H_ diff --git a/webkit/glue/plugins/pepper_private2.cc b/webkit/glue/plugins/pepper_private2.cc new file mode 100644 index 0000000..9a740aa --- /dev/null +++ b/webkit/glue/plugins/pepper_private2.cc @@ -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. + +#include "webkit/glue/plugins/pepper_private2.h" + +#include "webkit/glue/plugins/pepper_plugin_instance.h" +#include "webkit/glue/plugins/ppb_private2.h" + +namespace pepper { + +namespace { + +void SetInstanceAlwaysOnTop(PP_Instance pp_instance, bool on_top) { + PluginInstance* instance = PluginInstance::FromPPInstance(pp_instance); + if (!instance) + return; + instance->set_always_on_top(on_top); +} + +const PPB_Private2 ppb_private2 = { + &SetInstanceAlwaysOnTop +}; + +} // namespace + +// static +const PPB_Private2* Private2::GetInterface() { + return &ppb_private2; +} + +} // namespace pepper diff --git a/webkit/glue/plugins/pepper_private2.h b/webkit/glue/plugins/pepper_private2.h new file mode 100644 index 0000000..492669a --- /dev/null +++ b/webkit/glue/plugins/pepper_private2.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_GLUE_PLUGINS_PEPPER_PRIVATE2_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_PRIVATE2_H_ + +#include "webkit/glue/plugins/pepper_resource.h" + +struct PPB_Private2; + +namespace pepper { + +class Private2 { + public: + // Returns a pointer to the interface implementing PPB_Private2 that is + // exposed to the plugin. + static const PPB_Private2* GetInterface(); +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PRIVATE2_H_ diff --git a/webkit/glue/plugins/pepper_transport.cc b/webkit/glue/plugins/pepper_transport.cc new file mode 100644 index 0000000..ed5e05f --- /dev/null +++ b/webkit/glue/plugins/pepper_transport.cc @@ -0,0 +1,139 @@ +// 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/glue/plugins/pepper_transport.h" + +#include "base/singleton.h" +#include "base/thread_local.h" +#include "third_party/ppapi/c/dev/ppb_transport_dev.h" +#include "webkit/glue/plugins/pepper_plugin_instance.h" +#include "webkit/glue/plugins/pepper_plugin_module.h" + +namespace pepper { + +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 Transport +bool IsTransport(PP_Resource resource) { + return !!Resource::GetAs<Transport>(resource); +} + +// Returns whether the transport is currently writable +// (i.e. can send data to the remote peer) +bool IsWritable(PP_Resource transport) { + // TODO(juberti): impelement me + return 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 + +Transport::Transport(PluginModule* module) + : Resource(module) { + // TODO(juberti): impl +} + +const PPB_Transport_Dev* Transport::GetInterface() { + return &ppb_transport; +} + +Transport::~Transport() { + // TODO(juberti): teardown +} + +bool Transport::Init(const char* name, + const char* proto) { + // TODO(juberti): impl + return false; +} + +} // namespace pepper + diff --git a/webkit/glue/plugins/pepper_transport.h b/webkit/glue/plugins/pepper_transport.h new file mode 100644 index 0000000..1e6e56f --- /dev/null +++ b/webkit/glue/plugins/pepper_transport.h @@ -0,0 +1,35 @@ +// 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_TRANSPORT_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_TRANSPORT_H_ + +#include "base/scoped_ptr.h" +#include "third_party/ppapi/c/pp_instance.h" +#include "webkit/glue/plugins/pepper_plugin_delegate.h" +#include "webkit/glue/plugins/pepper_resource.h" + +struct PPB_Transport_Dev; + +namespace pepper { + +class Transport : public Resource { + public: + explicit Transport(PluginModule* module); + virtual ~Transport(); + static const PPB_Transport_Dev* GetInterface(); + virtual Transport* AsTransport() { + return this; + } + bool Init(const char* name, + const char* proto); + private: + + DISALLOW_COPY_AND_ASSIGN(Transport); +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_TRANSPORT_H_ + diff --git a/webkit/glue/plugins/pepper_url_util.cc b/webkit/glue/plugins/pepper_url_util.cc new file mode 100644 index 0000000..3f9a54f --- /dev/null +++ b/webkit/glue/plugins/pepper_url_util.cc @@ -0,0 +1,176 @@ +// 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/glue/plugins/pepper_url_util.h" + +#include "googleurl/src/gurl.h" +#include "third_party/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/glue/plugins/pepper_plugin_instance.h" +#include "webkit/glue/plugins/pepper_string.h" +#include "webkit/glue/plugins/pepper_var.h" + +namespace pepper { + +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 = PluginInstance::FromPPInstance(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 = PluginInstance::FromPPInstance(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); +} + +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 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 false; + + return gurl_a.GetOrigin() == gurl_b.GetOrigin(); +} + +bool DocumentCanRequest(PP_Instance instance, PP_Var url) { + scoped_refptr<StringVar> url_string(StringVar::FromPPVar(url)); + if (!url_string) + return false; + + WebKit::WebSecurityOrigin security_origin; + if (!SecurityOriginForInstance(instance, &security_origin)) + return false; + + GURL gurl(url_string->value()); + if (!gurl.is_valid()) + return false; + + return security_origin.canRequest(gurl); +} + +bool DocumentCanAccessDocument(PP_Instance active, PP_Instance target) { + WebKit::WebSecurityOrigin active_origin; + if (!SecurityOriginForInstance(active, &active_origin)) + return false; + + WebKit::WebSecurityOrigin target_origin; + if (!SecurityOriginForInstance(active, &target_origin)) + return false; + + return active_origin.canAccess(target_origin); +} + +} // namespace + +const PPB_UrlUtil_Dev ppb_url_util = { + &Canonicalize, + &ResolveRelativeToUrl, + &ResolveRelativeToDocument, + &IsSameSecurityOrigin, + &DocumentCanRequest, + &DocumentCanAccessDocument +}; + +// static +const PPB_UrlUtil_Dev* UrlUtil::GetInterface() { + return &ppb_url_util; +} + +} // namespace pepper diff --git a/webkit/glue/plugins/pepper_url_util.h b/webkit/glue/plugins/pepper_url_util.h new file mode 100644 index 0000000..ffb7c76 --- /dev/null +++ b/webkit/glue/plugins/pepper_url_util.h @@ -0,0 +1,19 @@ +// 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_URL_UTIL_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_URL_UTIL_H_ + +struct PPB_UrlUtil_Dev; + +namespace pepper { + +class UrlUtil { + public: + static const PPB_UrlUtil_Dev* GetInterface(); +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_URL_UTIL_H_ diff --git a/webkit/glue/plugins/pepper_video_decoder.cc b/webkit/glue/plugins/pepper_video_decoder.cc new file mode 100644 index 0000000..ed572b3 --- /dev/null +++ b/webkit/glue/plugins/pepper_video_decoder.cc @@ -0,0 +1,140 @@ +// 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/glue/plugins/pepper_video_decoder.h" + +#include "base/logging.h" +#include "third_party/ppapi/c/dev/pp_video_dev.h" +#include "third_party/ppapi/c/dev/ppb_video_decoder_dev.h" +#include "third_party/ppapi/c/pp_completion_callback.h" +#include "third_party/ppapi/c/pp_errors.h" +#include "webkit/glue/plugins/pepper_file_ref.h" +#include "webkit/glue/plugins/pepper_plugin_instance.h" +#include "webkit/glue/plugins/pepper_resource_tracker.h" + +namespace pepper { + +namespace { + +bool GetConfig(PP_Instance instance_id, + PP_VideoCodecId_Dev codec, + PP_VideoConfig_Dev* configs, + int32_t config_size, + int32_t *num_config) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + *num_config = 0; + if (!instance) + return false; + + // Get configs based on codec. + + if (configs) { + // Fill in the array of configs. + } + + // Update *num_config. + + return true; +} + +PP_Resource Create(PP_Instance instance_id, + const PP_VideoDecoderConfig_Dev* decoder_config) { + PluginInstance* instance = PluginInstance::FromPPInstance(instance_id); + if (!instance) + return 0; + + scoped_refptr<VideoDecoder> decoder(new VideoDecoder(instance)); + + if (!decoder->Init(*decoder_config)) + return 0; + + return decoder->GetReference(); +} + +bool Decode(PP_Resource decoder_id, + PP_VideoCompressedDataBuffer_Dev* input_buffer) { + scoped_refptr<VideoDecoder> decoder( + Resource::GetAs<VideoDecoder>(decoder_id)); + if (!decoder) + return false; + + decoder->Decode(*input_buffer); + return true; +} + +int32_t Flush(PP_Resource decoder_id, PP_CompletionCallback callback) { + scoped_refptr<VideoDecoder> decoder( + Resource::GetAs<VideoDecoder>(decoder_id)); + if (!decoder) + return PP_ERROR_BADRESOURCE; + + return decoder->Flush(callback); +} + +bool ReturnUncompressedDataBuffer(PP_Resource decoder_id, + PP_VideoUncompressedDataBuffer_Dev* buffer) { + scoped_refptr<VideoDecoder> decoder( + Resource::GetAs<VideoDecoder>(decoder_id)); + if (!decoder) + return false; + + return decoder->ReturnUncompressedDataBuffer(*buffer); +} + +const PPB_VideoDecoder_Dev ppb_videodecoder = { + &GetConfig, + &Create, + &Decode, + &Flush, + &ReturnUncompressedDataBuffer +}; + +} // namespace + +VideoDecoder::VideoDecoder(PluginInstance* instance) + : Resource(instance->module()), + instance_(instance) { +} + +VideoDecoder::~VideoDecoder() { +} + +// static +const PPB_VideoDecoder_Dev* VideoDecoder::GetInterface() { + return &ppb_videodecoder; +} + +bool VideoDecoder::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 VideoDecoder::Decode(PP_VideoCompressedDataBuffer_Dev& input_buffer) { + if (!platform_video_decoder_.get()) + return false; + + return platform_video_decoder_->Decode(input_buffer); +} + +int32_t VideoDecoder::Flush(PP_CompletionCallback& callback) { + if (!platform_video_decoder_.get()) + return PP_ERROR_FAILED; + + return platform_video_decoder_->Flush(callback); +} + +bool VideoDecoder::ReturnUncompressedDataBuffer( + PP_VideoUncompressedDataBuffer_Dev& buffer) { + if (!platform_video_decoder_.get()) + return false; + + return platform_video_decoder_->ReturnUncompressedDataBuffer(buffer); +} + +} // namespace pepper diff --git a/webkit/glue/plugins/pepper_video_decoder.h b/webkit/glue/plugins/pepper_video_decoder.h new file mode 100644 index 0000000..c828709 --- /dev/null +++ b/webkit/glue/plugins/pepper_video_decoder.h @@ -0,0 +1,50 @@ +// 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_VIDEO_DECODER_H_ +#define WEBKIT_GLUE_PLUGINS_PEPPER_VIDEO_DECODER_H_ + +#include "base/scoped_ptr.h" +#include "webkit/glue/plugins/pepper_plugin_delegate.h" +#include "webkit/glue/plugins/pepper_resource.h" + +struct PP_VideoDecoderConfig_Dev; +struct PP_VideoCompressedDataBuffer_Dev; +struct PP_VideoUncompressedDataBuffer_Dev; +struct PPB_VideoDecoder_Dev; + +namespace pepper { + +class PluginInstance; + +class VideoDecoder : public Resource { + public: + VideoDecoder(PluginInstance* instance); + virtual ~VideoDecoder(); + + // Returns a pointer to the interface implementing PPB_VideoDecoder that is + // exposed to the plugin. + static const PPB_VideoDecoder_Dev* GetInterface(); + + // Resource overrides. + VideoDecoder* AsVideoDecoder() { return this; } + + 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 VideoDecoder is + // swapped with another. + scoped_ptr<PluginDelegate::PlatformVideoDecoder> platform_video_decoder_; + scoped_refptr<PluginInstance> instance_; +}; + +} // namespace pepper + +#endif // WEBKIT_GLUE_PLUGINS_PEPPER_VIDEO_DECODER_H_ diff --git a/webkit/glue/plugins/ppb_private2.h b/webkit/glue/plugins/ppb_private2.h new file mode 100644 index 0000000..ca45471 --- /dev/null +++ b/webkit/glue/plugins/ppb_private2.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_GLUE_PLUGINS_PPB_PRIVATE2_H_ +#define WEBKIT_GLUE_PLUGINS_PPB_PRIVATE2_H_ + +#include "third_party/ppapi/c/pp_instance.h" +#include "third_party/ppapi/c/pp_module.h" +#include "third_party/ppapi/c/pp_var.h" + +#define PPB_PRIVATE2_INTERFACE "PPB_Private2;1" + +struct PPB_Private2 { + // 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); +}; + +#endif // WEBKIT_GLUE_PLUGINS_PPB_PRIVATE2_H_ |