diff options
author | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-10 20:01:35 +0000 |
---|---|---|
committer | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-10 20:01:35 +0000 |
commit | 3d1e89df95d421bcedec406019b3a9dbbf94b8c1 (patch) | |
tree | 2ed165930ca9f7520e94d49911a8245d54502478 /webkit | |
parent | cb0ce1e02b7d16ab9024da9335ab7c70c493aa4e (diff) | |
download | chromium_src-3d1e89df95d421bcedec406019b3a9dbbf94b8c1.zip chromium_src-3d1e89df95d421bcedec406019b3a9dbbf94b8c1.tar.gz chromium_src-3d1e89df95d421bcedec406019b3a9dbbf94b8c1.tar.bz2 |
Implement the CoreAnimation drawing model for plug-ins, sharing IPC and some rendering code with the GPU Plug-in. The drawing model negotiation is currently disabled so this should have no visible impact to plug-ins.
BUG=32012
TEST=make sure the pepper GPU plug-ins still work.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41194 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/plugins/plugin_host.cc | 42 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 39 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 99 | ||||
-rw-r--r-- | webkit/glue/webplugin.h | 20 | ||||
-rw-r--r-- | webkit/tools/test_shell/mac/accelerated_surface_stub.cc | 49 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.gypi | 1 | ||||
-rw-r--r-- | webkit/webkit.gyp | 5 |
7 files changed, 240 insertions, 15 deletions
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc index 0db965c..4cd5b3b 100644 --- a/webkit/glue/plugins/plugin_host.cc +++ b/webkit/glue/plugins/plugin_host.cc @@ -9,6 +9,9 @@ #include "base/scoped_ptr.h" #include "base/string_piece.h" #include "base/string_util.h" +#if defined(OS_MACOSX) +#include "base/sys_info.h" +#endif #include "base/sys_string_conversions.h" #include "net/base/net_util.h" #include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" @@ -36,6 +39,21 @@ static NPAPI::PluginInstance* FindInstance(NPP id) { return reinterpret_cast<NPAPI::PluginInstance*>(id->ndata); } +#if defined(OS_MACOSX) +// Returns true if the OS supports shared accelerated surfaces via IOSurface. +// This is true on Snow Leopard and higher. +static bool SupportsSharingAcceleratedSurfaces() { + int32 major, minor, bugfix; + base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); +#if PINK_USE_COREANIMATION + // TODO(pinkerton): enable this, http://crbug.com/32012 + return major > 10 || (major == 10 && minor > 5); +#else + return false; +#endif +} +#endif + namespace NPAPI { scoped_refptr<PluginHost> PluginHost::singleton_; @@ -757,7 +775,10 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) { } #ifndef NP_NO_QUICKDRAW case NPNVsupportsQuickDrawBool: { - // we do not admit to supporting the QuickDraw drawing model. + // We do not admit to supporting the QuickDraw drawing model. The logic + // here is that our QuickDraw plugin support is so rudimentary that we + // only want to use it as a fallback to keep plugins from crashing: if a + // plugin knows enough to ask, we want them to use CoreGraphics. NPBool* supports_qd = reinterpret_cast<NPBool*>(value); *supports_qd = FALSE; rv = NPERR_NO_ERROR; @@ -775,9 +796,16 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) { rv = NPERR_NO_ERROR; break; } - case NPNVsupportsOpenGLBool: case NPNVsupportsCoreAnimationBool: { - // we do not support these drawing and event models. + // We only support the Core Animation model on 10.6 and higher + NPBool* supports_model = reinterpret_cast<NPBool*>(value); + *supports_model = SupportsSharingAcceleratedSurfaces() ? TRUE : FALSE; + rv = NPERR_NO_ERROR; + break; + } + case NPNVsupportsOpenGLBool: { + // This drawing model was never widely supported, and we don't plan to + // support it. NPBool* supports_model = reinterpret_cast<NPBool*>(value); *supports_model = FALSE; rv = NPERR_NO_ERROR; @@ -838,14 +866,14 @@ NPError NPN_SetValue(NPP id, NPPVariable variable, void* value) { return NPERR_GENERIC_ERROR; #if defined(OS_MACOSX) case NPPVpluginDrawingModel: { - // We only admit to supporting the CoreGraphics drawing model. The logic - // here is that our QuickDraw plugin support is so rudimentary that we - // only want to use it as a fallback to keep plugins from crashing: if - // a plugin knows enough to ask, we want them to use CoreGraphics. int model = reinterpret_cast<int>(value); if (model == NPDrawingModelCoreGraphics) { plugin->set_drawing_model(model); return NPERR_NO_ERROR; + } else if (model == NPDrawingModelCoreAnimation && + SupportsSharingAcceleratedSurfaces()) { + plugin->set_drawing_model(model); + return NPERR_NO_ERROR; } return NPERR_GENERIC_ERROR; } diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index 1327464..d8bb88c 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -16,10 +16,15 @@ #include "base/gfx/rect.h" #include "base/ref_counted.h" #include "base/task.h" +#include "base/timer.h" #include "third_party/npapi/bindings/npapi.h" #include "webkit/glue/webcursor.h" #include "webkit/glue/webplugin_delegate.h" +#if defined(OS_MACOSX) +#include "chrome/common/accelerated_surface_mac.h" +#endif + #if defined(USE_X11) typedef struct _GdkDrawable GdkPixmap; #endif @@ -32,8 +37,19 @@ namespace WebKit { class WebMouseEvent; } -// An implementation of WebPluginDelegate that proxies all calls to -// the plugin process. +#if defined(OS_MACOSX) +class CoreAnimationRedrawTimerSource; +#ifdef __OBJC__ +@class CALayer; +@class CARenderer; +#else +class CALayer; +class CARenderer; +#endif +#endif + +// An implementation of WebPluginDelegate that runs in the plugin process, +// proxied from the renderer by WebPluginDelegateProxy. class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { public: enum PluginQuirks { @@ -146,6 +162,12 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { // Informs the delegate that the plugin set a Cocoa NSCursor. void SetNSCursor(NSCursor* cursor); + // Informs the browser about the updated accelerated drawing surface. + void UpdateAcceleratedSurface(); + + // Uses a CARenderer to draw the plug-in's layer in our OpenGL surface. + void DrawLayerInSurface(); + #ifndef NP_NO_CARBON // Indicates that it's time to send the plugin a null event. void FireIdleEvent(); @@ -157,10 +179,11 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { } #if defined(OS_MACOSX) - // On Mac OS X and for the GPU plugin only, this handle is a fake - // one and comes in from the outside world. + // Allow setting a "fake" window handle to associate this plug-in with + // an IOSurface in the browser. Used for accelerated drawing surfaces. void set_windowed_handle(gfx::PluginWindowHandle handle) { windowed_handle_ = handle; + UpdateAcceleratedSurface(); } #endif @@ -244,7 +267,7 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { // used for windowed plugins // Note: on Mac OS X, the only time the windowed handle is non-zero - // is the case of the GPU plugin, which uses a fake window handle to + // is the case of accelerated rendering, which uses a fake window handle to // identify itself back to the browser. It still performs all of its // work offscreen. gfx::PluginWindowHandle windowed_handle_; @@ -301,6 +324,10 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { #ifndef NP_NO_QUICKDRAW NP_Port qd_port_; #endif + CALayer* layer_; // Used for CA drawing mode. Weak, retained by plug-in. + AcceleratedSurface* surface_; + CARenderer* renderer_; // Renders layer_ to surface_. + scoped_ptr<base::RepeatingTimer<WebPluginDelegateImpl> > redraw_timer_; #endif gfx::Rect window_rect_; gfx::Rect clip_rect_; @@ -356,7 +383,7 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { #ifndef NP_NO_CARBON // Moves our dummy window to match the current screen location of the plugin. void UpdateDummyWindowBounds(const gfx::Point& plugin_origin); - + #ifndef NP_NO_QUICKDRAW // Scrapes the contents of our dummy window into the given context. void ScrapeDummyWindowIntoContext(CGContextRef context); diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index 0a1e84e..0a2f963 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -3,6 +3,7 @@ // found in the LICENSE file. #import <Cocoa/Cocoa.h> +#import <QuartzCore/QuartzCore.h> #include "webkit/glue/plugins/webplugin_delegate_impl.h" @@ -16,7 +17,6 @@ #include "base/scoped_ptr.h" #include "base/stats_counters.h" #include "base/string_util.h" -#include "base/timer.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" #include "webkit/default_plugin/plugin_impl.h" #include "webkit/glue/webplugin.h" @@ -49,6 +49,8 @@ using WebKit::WebInputEvent; using WebKit::WebMouseEvent; using WebKit::WebMouseWheelEvent; +const int kCoreAnimationRedrawPeriodMs = 20; // 50fps + // Important implementation notes: The Mac definition of NPAPI, particularly // the distinction between windowed and windowless modes, differs from the // Windows and Linux definitions. Most of those differences are @@ -169,16 +171,22 @@ class CarbonIdleEventSource { } // namespace +#pragma mark - + WebPluginDelegateImpl::WebPluginDelegateImpl( gfx::PluginWindowHandle containing_view, NPAPI::PluginInstance *instance) - : windowless_needs_set_window_(true), + : windowed_handle_(NULL), + windowless_needs_set_window_(true), // all Mac plugins are "windowless" in the Windows/X11 sense windowless_(true), plugin_(NULL), instance_(instance), parent_(containing_view), buffer_context_(NULL), + layer_(nil), + surface_(NULL), + renderer_(nil), quirks_(0), have_focus_(false), focus_notifier_(NULL), @@ -256,6 +264,32 @@ void WebPluginDelegateImpl::PlatformInitialize() { #endif window_.type = NPWindowTypeDrawable; break; + case NPDrawingModelCoreAnimation: { // Assumes Cocoa event model. + window_.type = NPWindowTypeDrawable; + // Ask the plug-in for the CALayer it created for rendering content. Have + // the renderer tell the browser to create a "windowed plugin" to host + // the IOSurface. The surface itself will be created when the plug-in + // is sized. + CALayer* layer = nil; + NPError err = instance()->NPP_GetValue(NPPVpluginCoreAnimationLayer, + reinterpret_cast<void*>(&layer)); + if (!err) { + layer_ = layer; + plugin_->BindFakePluginWindowHandle(); + surface_ = new AcceleratedSurface; + surface_->Initialize(); + UpdateAcceleratedSurface(); + renderer_ = [[CARenderer rendererWithCGLContext:surface_->context() + options:NULL] retain]; + [renderer_ setLayer:layer_]; + redraw_timer_.reset(new base::RepeatingTimer<WebPluginDelegateImpl>); + redraw_timer_->Start( + base::TimeDelta::FromMilliseconds(kCoreAnimationRedrawPeriodMs), + this, + &WebPluginDelegateImpl::DrawLayerInSurface); + } + break; + } default: NOTREACHED(); break; @@ -286,6 +320,16 @@ void WebPluginDelegateImpl::PlatformDestroyInstance() { if (instance()->event_model() == NPEventModelCarbon) CarbonIdleEventSource::SharedInstance()->UnregisterDelegate(this); #endif + if (redraw_timer_.get()) + redraw_timer_->Stop(); + [renderer_ release]; + renderer_ = nil; + layer_ = nil; + if (surface_) { + surface_->Destroy(); + delete surface_; + surface_ = NULL; + } } void WebPluginDelegateImpl::UpdateGeometryAndContext( @@ -379,8 +423,32 @@ void WebPluginDelegateImpl::WindowlessUpdateGeometry( WindowlessSetWindow(true); } +void WebPluginDelegateImpl::DrawLayerInSurface() { + surface_->MakeCurrent(); + + surface_->Clear(window_rect_); + + // Ensure all changes are made before rendering. Not sure where the |-begin| + // comes from, but not doing this causes nothing to render. + [CATransaction commit]; + [renderer_ beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL]; + CGRect layerRect = [layer_ bounds]; + [renderer_ addUpdateRect:layerRect]; + [renderer_ render]; + [renderer_ endFrame]; + + surface_->SwapBuffers(); + plugin_->AcceleratedFrameBuffersDidSwap(windowed_handle()); +} + void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, const gfx::Rect& damage_rect) { + // There is currently nothing to do for the Core Animation drawing model, + // but there have been discussions on the plugin-futures mailing list that + // might require future work. + if (instance()->drawing_model() == NPDrawingModelCoreAnimation) + return; + // If we somehow get a paint before we've set up the plugin buffer, bail. if (!buffer_context_) return; @@ -458,6 +526,8 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { SetWindowHasFocus(initial_window_focus_); } + UpdateAcceleratedSurface(); + DCHECK(err == NPERR_NO_ERROR); } @@ -580,6 +650,30 @@ void WebPluginDelegateImpl::SetContainerVisibility(bool is_visible) { } } +// Generate an IOSurface for accelerated drawing (but only in the case where a +// window handle has been set). Once the surface has been updated for the +// current size of the plug-in, tell the browser host view so it can adjust its +// bookkeeping and CALayer appropriately. +void WebPluginDelegateImpl::UpdateAcceleratedSurface() { + // Will only have a window handle when using the CoreAnimation drawing model. + if (!windowed_handle() || + instance()->drawing_model() != NPDrawingModelCoreAnimation) + return; + + [layer_ setFrame:CGRectMake(0, 0, + window_rect_.width(), window_rect_.height())]; + [renderer_ setBounds:[layer_ bounds]]; + + uint64 io_surface_id = surface_->SetSurfaceSize(window_rect_.width(), + window_rect_.height()); + if (io_surface_id) { + plugin_->SetAcceleratedSurface(windowed_handle(), + window_rect_.width(), + window_rect_.height(), + io_surface_id); + } +} + void WebPluginDelegateImpl::WindowFrameChanged(gfx::Rect window_frame, gfx::Rect view_frame) { instance()->set_window_frame(window_frame); @@ -600,6 +694,7 @@ void WebPluginDelegateImpl::SetNSCursor(NSCursor* cursor) { void WebPluginDelegateImpl::SetPluginRect(const gfx::Rect& rect) { window_rect_ = rect; + UpdateAcceleratedSurface(); PluginScreenLocationChanged(); } diff --git a/webkit/glue/webplugin.h b/webkit/glue/webplugin.h index d83601a..3f9c7e5 100644 --- a/webkit/glue/webplugin.h +++ b/webkit/glue/webplugin.h @@ -144,6 +144,26 @@ class WebPlugin { virtual void SetDeferResourceLoading(unsigned long resource_id, bool defer) = 0; +#if defined(OS_MACOSX) + // Synthesize a fake window handle for the plug-in to identify the instance + // to the browser, allowing mapping to a surface for hardware accelleration + // of plug-in content. The browser generates the handle which is then set on + // the plug-in. + virtual void BindFakePluginWindowHandle() {} + + // Tell the browser (via the renderer) to invalidate because the + // accelerated buffers have changed. + virtual void AcceleratedFrameBuffersDidSwap(gfx::PluginWindowHandle window) {} + + // Tell the renderer and browser to associate the given plugin handle with + // |accelerated_surface_identifier|. The geometry is used to resize any + // native "window" (which on the Mac is a CALayer). + virtual void SetAcceleratedSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 accelerated_surface_identifier) {} +#endif + // Gets the WebPluginDelegate that implements the interface. // This API is only for use with Pepper, and is only overridden // by in-renderer implementations. diff --git a/webkit/tools/test_shell/mac/accelerated_surface_stub.cc b/webkit/tools/test_shell/mac/accelerated_surface_stub.cc new file mode 100644 index 0000000..f331a41 --- /dev/null +++ b/webkit/tools/test_shell/mac/accelerated_surface_stub.cc @@ -0,0 +1,49 @@ +// 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 a complete and total hack intended to stub out some classes +// used by WebPluginDelegateImpl on Mac. Unfortunately, they live in +// chrome/common, so we can't compile them into TestShell. Instead, provide +// some stubs. It will need to be updated if new methods are added to +// AcceleratedSurface that get called from WebPluginDelegateImpl. It's not +// like plug-ins work in TestShell anyway. + +#include <CoreFoundation/CoreFoundation.h> +#include <OpenGL/OpenGL.h> + +#include "base/basictypes.h" +#include "base/gfx/rect.h" +#include "base/scoped_ptr.h" + +class TransportDIB { + public: + TransportDIB() { } + ~TransportDIB() { } +}; + +class AcceleratedSurface { + public: + AcceleratedSurface(); + virtual ~AcceleratedSurface(); + + bool Initialize(); + void Destroy(); + uint64 SetSurfaceSize(int32 width, int32 height); + bool MakeCurrent(); + void Clear(const gfx::Rect& rect); + void SwapBuffers(); + CGLContextObj context() { return NULL; } + private: + scoped_ptr<TransportDIB> ignore_; +}; + +AcceleratedSurface::AcceleratedSurface() { } +AcceleratedSurface::~AcceleratedSurface() { } +bool AcceleratedSurface::Initialize() { return false; } +void AcceleratedSurface::Destroy() { } +uint64 AcceleratedSurface::SetSurfaceSize(int32 width, int32 height) + { return 0; } +bool AcceleratedSurface::MakeCurrent() { return false; } +void AcceleratedSurface::Clear(const gfx::Rect& rect) { } +void AcceleratedSurface::SwapBuffers() { } diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi index a28daf2..a1bd3cb 100644 --- a/webkit/tools/test_shell/test_shell.gypi +++ b/webkit/tools/test_shell/test_shell.gypi @@ -48,6 +48,7 @@ ], 'msvs_guid': '77C32787-1B96-CB84-B905-7F170629F0AC', 'sources': [ + 'mac/accelerated_surface_stub.cc', 'mac/DumpRenderTreePasteboard.h', 'mac/DumpRenderTreePasteboard.m', 'mac/test_shell_webview.h', diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 282bb3b..0754c9f 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -408,6 +408,11 @@ ['exclude', r'/mac_']], }, { # else: OS=="mac" 'sources/': [['exclude', 'plugin_(lib|list)_posix\\.cc$']], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/QuartzCore.framework', + ], + }, }], ['enable_gpu==1', { 'dependencies': [ |