diff options
author | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-11 01:57:28 +0000 |
---|---|---|
committer | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-11 01:57:28 +0000 |
commit | 6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef (patch) | |
tree | 7bedf19228a20b83189ab96e617e72210991c7c4 /chrome/plugin | |
parent | 7e05f6c4baad4f81e06835b83febe2784568ebe1 (diff) | |
download | chromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.zip chromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.tar.gz chromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.tar.bz2 |
Wire up windowless plugins. Mostly Mac related, some cross
platform aspects.
BUG=10809
TEST=none
Review URL: http://codereview.chromium.org/113637
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20453 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/plugin')
-rw-r--r-- | chrome/plugin/plugin_main.cc | 63 | ||||
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.cc | 6 | ||||
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.h | 4 | ||||
-rw-r--r-- | chrome/plugin/webplugin_proxy.cc | 95 | ||||
-rw-r--r-- | chrome/plugin/webplugin_proxy.h | 20 |
5 files changed, 159 insertions, 29 deletions
diff --git a/chrome/plugin/plugin_main.cc b/chrome/plugin/plugin_main.cc index fb8880f..4cc7911 100644 --- a/chrome/plugin/plugin_main.cc +++ b/chrome/plugin/plugin_main.cc @@ -27,6 +27,47 @@ #include "base/global_descriptors_posix.h" #endif +#if defined(OS_MACOSX) + +// To support Mac NPAPI plugins that use the Carbon event model (i.e., most +// shipping plugins for MacOS X 10.5 and earlier), we need some way for the +// Carbon event dispatcher to run, even though the plugin host process itself +// does not use Carbon events. Rather than give control to the standard +// Carbon event loop, we schedule a periodic task on the main thread which +// empties the Carbon event queue every 20ms (chosen to match how often Safari +// does the equivalent operation). This allows plugins to receive idle events +// and schedule Carbon timers without swamping the CPU. If, in the future, +// we remove support for the Carbon event model and only support the Cocoa +// event model, this can be removed. Note that this approach does not install +// standard application event handlers for the menubar, AppleEvents, and so on. +// This is intentional, since the plugin process is not actually an application +// with its own UI elements--all rendering and event handling happens via IPC +// to the renderer process which invoked it. + +namespace { + +const int kPluginUpdateIntervalMs = 20; // 20ms = 50Hz + +void PluginCarbonEventTask() { + EventRef theEvent; + EventTargetRef theTarget; + + theTarget = GetEventDispatcherTarget(); + + // Dispatch any pending events. but do not block if there are no events. + while (ReceiveNextEvent(0, NULL, kEventDurationNoWait, + true, &theEvent) == noErr) { + SendEventToEventTarget (theEvent, theTarget); + ReleaseEvent(theEvent); + } + + MessageLoop::current()->PostDelayedTask(FROM_HERE, + NewRunnableFunction(PluginCarbonEventTask), kPluginUpdateIntervalMs); +} + +} +#endif + // main() routine for running as the plugin process. int PluginMain(const MainFunctionParams& parameters) { // The main thread of the plugin services IO. @@ -37,9 +78,9 @@ int PluginMain(const MainFunctionParams& parameters) { // Initialize the SystemMonitor base::SystemMonitor::Start(); -#if defined(OS_WIN) const CommandLine& parsed_command_line = parameters.command_line_; +#if defined(OS_WIN) sandbox::TargetServices* target_services = parameters.sandbox_info_.TargetServices(); @@ -59,16 +100,32 @@ int PluginMain(const MainFunctionParams& parameters) { DCHECK(sandbox_test_module); } } - +#endif if (parsed_command_line.HasSwitch(switches::kPluginStartupDialog)) { +#if defined(OS_WIN) std::wstring title = chrome::kBrowserAppName; title += L" plugin"; // makes attaching to process easier win_util::MessageBox(NULL, L"plugin starting...", title, MB_OK | MB_SETFOREGROUND); - } +#elif defined(OS_MACOSX) + // TODO(playmobil): In the long term, overriding this flag doesn't seem + // right, either use our own flag or open a dialog we can use. + // This is just to ease debugging in the interim. + LOG(WARNING) << "Plugin (" + << getpid() + << ") paused waiting for debugger to attach @ pid"; + pause(); #else NOTIMPLEMENTED() << " non-windows startup, plugin startup dialog etc."; #endif + } + +#if defined(OS_MACOSX) + // Spin off a consumer for the native (Carbon) event stream so + // that plugin timers, event handlers, etc. will work properly. + MessageLoop::current()->PostDelayedTask(FROM_HERE, + NewRunnableFunction(PluginCarbonEventTask), kPluginUpdateIntervalMs); +#endif { ChildProcess plugin_process(new PluginThread()); diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index 542f0a3..a8a42b0 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -272,11 +272,11 @@ void WebPluginDelegateStub::OnPrint(base::SharedMemoryHandle* shared_memory, void WebPluginDelegateStub::OnUpdateGeometry( const gfx::Rect& window_rect, const gfx::Rect& clip_rect, - const TransportDIB::Id& windowless_buffer_id, - const TransportDIB::Id& background_buffer_id) { + const TransportDIB::Handle& windowless_buffer, + const TransportDIB::Handle& background_buffer) { webplugin_->UpdateGeometry( window_rect, clip_rect, - windowless_buffer_id, background_buffer_id); + windowless_buffer, background_buffer); } void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id, diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h index 10ac7a4..15b88a8 100644 --- a/chrome/plugin/webplugin_delegate_stub.h +++ b/chrome/plugin/webplugin_delegate_stub.h @@ -71,8 +71,8 @@ class WebPluginDelegateStub : public IPC::Channel::Listener, void OnUpdateGeometry(const gfx::Rect& window_rect, const gfx::Rect& clip_rect, - const TransportDIB::Id& windowless_buffer, - const TransportDIB::Id& background_buffer); + const TransportDIB::Handle& windowless_buffer, + const TransportDIB::Handle& background_buffer); void OnGetPluginScriptableObject(int* route_id, intptr_t* npobject_ptr); void OnSendJavaScriptStream(const std::string& url, const std::wstring& result, diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc index b2fe778..94f2b2f 100644 --- a/chrome/plugin/webplugin_proxy.cc +++ b/chrome/plugin/webplugin_proxy.cc @@ -369,11 +369,16 @@ void WebPluginProxy::Paint(const gfx::Rect& rect) { #if defined(OS_WIN) if (!windowless_hdc_) return; +#elif defined(OS_MACOSX) + if (!windowless_context_.get()) + return; +#endif // Clear the damaged area so that if the plugin doesn't paint there we won't // end up with the old values. gfx::Rect offset_rect = rect; offset_rect.Offset(delegate_->GetRect().origin()); +#if defined(OS_WIN) if (!background_hdc_) { FillRect(windowless_hdc_, &offset_rect.ToRECT(), static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); @@ -393,6 +398,22 @@ void WebPluginProxy::Paint(const gfx::Rect& rect) { SelectClipRgn(windowless_hdc_, NULL); DeleteObject(clip_region); +#elif defined(OS_MACOSX) + CGContextSaveGState(windowless_context_); + if (!background_context_.get()) { + CGContextSetFillColorWithColor(windowless_context_, + CGColorGetConstantColor(kCGColorWhite)); + CGContextFillRect(windowless_context_, rect.ToCGRect()); + } else { + scoped_cftyperef<CGImageRef> image( + CGBitmapContextCreateImage(background_context_)); + scoped_cftyperef<CGImageRef> sub_image( + CGImageCreateWithImageInRect(image, rect.ToCGRect())); + CGContextDrawImage(background_context_, rect.ToCGRect(), sub_image); + } + CGContextClipToRect(windowless_context_, rect.ToCGRect()); + delegate_->Paint(windowless_context_, rect); + CGContextRestoreGState(windowless_context_); #else // TODO(port): windowless painting. NOTIMPLEMENTED(); @@ -402,22 +423,21 @@ void WebPluginProxy::Paint(const gfx::Rect& rect) { void WebPluginProxy::UpdateGeometry( const gfx::Rect& window_rect, const gfx::Rect& clip_rect, - const TransportDIB::Id& windowless_buffer_id, - const TransportDIB::Id& background_buffer_id) { - // TODO(port): this isn't correct usage of a TransportDIB; for now, - // the caller temporarly just stuffs the handle into the HANDLE - // field of the TransportDIB::Id so it should behave like the older - // code. + const TransportDIB::Handle& windowless_buffer, + const TransportDIB::Handle& background_buffer) { gfx::Rect old = delegate_->GetRect(); gfx::Rect old_clip_rect = delegate_->GetClipRect(); delegate_->UpdateGeometry(window_rect, clip_rect); -#if defined(OS_WIN) bool moved = old.x() != window_rect.x() || old.y() != window_rect.y(); - if (windowless_buffer_id.handle) { +#if defined(OS_MACOSX) + if (windowless_buffer.fd > 0) { +#else + if (windowless_buffer) { +#endif // The plugin's rect changed, so now we have a new buffer to draw into. - SetWindowlessBuffer(windowless_buffer_id.handle, - background_buffer_id.handle); + SetWindowlessBuffer(windowless_buffer, + background_buffer); } else if (moved) { // The plugin moved, so update our world transform. UpdateTransform(); @@ -428,15 +448,12 @@ void WebPluginProxy::UpdateGeometry( old_clip_rect.IsEmpty() && !damaged_rect_.IsEmpty()) { InvalidateRect(damaged_rect_); } -#else - NOTIMPLEMENTED(); -#endif } #if defined(OS_WIN) void WebPluginProxy::SetWindowlessBuffer( - const base::SharedMemoryHandle& windowless_buffer, - const base::SharedMemoryHandle& background_buffer) { + const TransportDIB::Handle& windowless_buffer, + const TransportDIB::Handle& background_buffer) { // Convert the shared memory handle to a handle that works in our process, // and then use that to create an HDC. ConvertBuffer(windowless_buffer, @@ -501,6 +518,54 @@ void WebPluginProxy::UpdateTransform() { xf.eM22 = 1; SetWorldTransform(windowless_hdc_, &xf); } +#elif defined(OS_MACOSX) +void WebPluginProxy::UpdateTransform() { + NOTIMPLEMENTED(); +} + +void WebPluginProxy::SetWindowlessBuffer( + const TransportDIB::Handle& windowless_buffer, + const TransportDIB::Handle& background_buffer) { + // Convert the shared memory handle to a handle that works in our process, + // and then use that to create a CGContextRef. + windowless_dib_.reset(TransportDIB::Map(windowless_buffer)); + background_dib_.reset(TransportDIB::Map(background_buffer)); + scoped_cftyperef<CGColorSpaceRef> rgb_colorspace( + CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)); + windowless_context_.reset(CGBitmapContextCreate( + windowless_dib_->memory(), + delegate_->GetRect().width(), + delegate_->GetRect().height(), + 8, 4 * delegate_->GetRect().width(), + rgb_colorspace, + kCGImageAlphaPremultipliedFirst | + kCGBitmapByteOrder32Host)); + CGContextTranslateCTM(windowless_context_, 0, delegate_->GetRect().height()); + CGContextScaleCTM(windowless_context_, 1, -1); + if (background_dib_.get()) { + background_context_.reset(CGBitmapContextCreate( + background_dib_->memory(), + delegate_->GetRect().width(), + delegate_->GetRect().height(), + 8, 4 * delegate_->GetRect().width(), + rgb_colorspace, + kCGImageAlphaPremultipliedFirst | + kCGBitmapByteOrder32Host)); + CGContextTranslateCTM(background_context_, 0, + delegate_->GetRect().height()); + CGContextScaleCTM(background_context_, 1, -1); + } +} +#elif defined (OS_LINUX) +void WebPluginProxy::UpdateTransform() { + NOTIMPLEMENTED(); +} + +void WebPluginProxy::SetWindowlessBuffer( + const TransportDIB::Handle& windowless_buffer, + const TransportDIB::Handle& background_buffer) { + NOTIMPLEMENTED(); +} #endif void WebPluginProxy::CancelDocumentLoad() { diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h index 103be5c..a55a3da2 100644 --- a/chrome/plugin/webplugin_proxy.h +++ b/chrome/plugin/webplugin_proxy.h @@ -9,6 +9,9 @@ #include "base/hash_tables.h" #include "base/ref_counted.h" +#if defined(OS_MACOSX) +#include "base/scoped_cftyperef.h" +#endif #include "base/scoped_handle.h" #include "base/scoped_ptr.h" #include "base/shared_memory.h" @@ -104,8 +107,8 @@ class WebPluginProxy : public WebPlugin { void UpdateGeometry(const gfx::Rect& window_rect, const gfx::Rect& clip_rect, - const TransportDIB::Id& windowless_buffer, - const TransportDIB::Id& background_buffer); + const TransportDIB::Handle& windowless_buffer, + const TransportDIB::Handle& background_buffer); void CancelDocumentLoad(); @@ -129,22 +132,22 @@ class WebPluginProxy : public WebPlugin { // Handler for sending over the paint event to the plugin. void OnPaint(const gfx::Rect& damaged_rect); -#if defined(OS_WIN) // Updates the shared memory section where windowless plugins paint. - void SetWindowlessBuffer(const base::SharedMemoryHandle& windowless_buffer, - const base::SharedMemoryHandle& background_buffer); + void SetWindowlessBuffer(const TransportDIB::Handle& windowless_buffer, + const TransportDIB::Handle& background_buffer); +#if defined(OS_WIN) // Converts a shared memory section handle from the renderer process into a // bitmap and hdc that are mapped to this process. void ConvertBuffer(const base::SharedMemoryHandle& buffer, ScopedHandle* shared_section, ScopedBitmap* bitmap, ScopedHDC* hdc); +#endif // Called when a plugin's origin moves, so that we can update the world // transform of the local HDC. void UpdateTransform(); -#endif typedef base::hash_map<int, WebPluginResourceClient*> ResourceClientMap; ResourceClientMap resource_clients_; @@ -174,6 +177,11 @@ class WebPluginProxy : public WebPlugin { ScopedHandle background_shared_section_; ScopedBitmap background_bitmap_; ScopedHDC background_hdc_; +#elif defined(OS_MACOSX) + scoped_ptr<TransportDIB> windowless_dib_; + scoped_ptr<TransportDIB> background_dib_; + scoped_cftyperef<CGContextRef> windowless_context_; + scoped_cftyperef<CGContextRef> background_context_; #endif ScopedRunnableMethodFactory<WebPluginProxy> runnable_method_factory_; |