diff options
author | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-21 19:57:44 +0000 |
---|---|---|
committer | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-21 19:57:44 +0000 |
commit | 979cb0e4846b5420ca417dc05f2642c5f79f795f (patch) | |
tree | 74167ea5e2841a66c0739e2d1a3cdfcbd8dd0b11 /webkit | |
parent | 22927adeb7d392dfee17a90657f51bf12d8a5766 (diff) | |
download | chromium_src-979cb0e4846b5420ca417dc05f2642c5f79f795f.zip chromium_src-979cb0e4846b5420ca417dc05f2642c5f79f795f.tar.gz chromium_src-979cb0e4846b5420ca417dc05f2642c5f79f795f.tar.bz2 |
Remove the temporary Mac plugin whitelist.
Support Mac NPAPI drawing and event model negotiation. Implement a fallback
Quickdraw drawing model implementation so that old plugins don't crash.
This change does not address keyboard input issues (see issue 19194), just
display issues.
BUG=12030
TEST=Quickdraw based plugins (such as the QuickTime plugin) should not crash
when invoked, and may even display properly.
Review URL: http://codereview.chromium.org/211031
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26724 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/plugins/plugin_host.cc | 36 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.cc | 4 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.h | 11 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_list_mac.mm | 13 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 4 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 177 |
6 files changed, 203 insertions, 42 deletions
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc index 27445a5..a6f0205 100644 --- a/webkit/glue/plugins/plugin_host.cc +++ b/webkit/glue/plugins/plugin_host.cc @@ -784,6 +784,14 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void *value) { break; } #if defined(OS_MACOSX) + case NPNVpluginDrawingModel: + { + // return the drawing model that was negotiated when we initialized + scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id); + *reinterpret_cast<int*>(value) = plugin->drawing_model(); + rv = NPERR_NO_ERROR; + break; + } case NPNVsupportsQuickDrawBool: { // we do not support the QuickDraw drawing model @@ -851,15 +859,35 @@ NPError NPN_SetValue(NPP id, NPPVariable variable, void *value) { DLOG(INFO) << "NPN_SetValue(NPPVpluginKeepLibraryInMemory) is not implemented."; return NPERR_GENERIC_ERROR; #if defined(OS_MACOSX) - case NPNVpluginDrawingModel: - // we only support the CoreGraphics drawing model - if (reinterpret_cast<int>(value) == NPDrawingModelCoreGraphics) + 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; + } return NPERR_GENERIC_ERROR; + } + case NPPVpluginEventModel: + { + // we only support the Carbon event model + int model = reinterpret_cast<int>(value); + switch (model) { + case NPNVsupportsCarbonBool: + plugin->set_event_model(model); + return NPERR_NO_ERROR; + break; + } + return NPERR_GENERIC_ERROR; + } #endif default: // TODO: implement me - DLOG(INFO) << "NPN_SetValue(" << variable << ") is not implemented."; + LOG(WARNING) << "NPN_SetValue(" << variable << ") is not implemented."; break; } diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc index ad8c9bf..42abdc5 100644 --- a/webkit/glue/plugins/plugin_instance.cc +++ b/webkit/glue/plugins/plugin_instance.cc @@ -42,6 +42,10 @@ PluginInstance::PluginInstance(PluginLib *plugin, const std::string &mime_type) webplugin_(0), mime_type_(mime_type), use_mozilla_user_agent_(false), +#if defined (OS_MACOSX) + drawing_model_(0), + event_model_(0), +#endif message_loop_(MessageLoop::current()), load_manually_(false), in_close_streams_(false) { diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h index 352dab5..a724957 100644 --- a/webkit/glue/plugins/plugin_instance.h +++ b/webkit/glue/plugins/plugin_instance.h @@ -101,6 +101,13 @@ class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> { NPAPI::PluginLib* plugin_lib() { return plugin_; } +#if defined(OS_MACOSX) + int drawing_model() { return drawing_model_; } + void set_drawing_model(int value) { drawing_model_ = value; } + int event_model() { return event_model_; } + void set_event_model(int value) { event_model_ = value; } +#endif + #if defined(OS_WIN) // Handles a windows native message which this PluginInstance should deal // with. Returns true if the event is handled, false otherwise. @@ -238,6 +245,10 @@ class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> { #if defined(OS_WIN) scoped_refptr<MozillaExtensionApi> mozilla_extenstions_; #endif +#if defined(OS_MACOSX) + int drawing_model_; + int event_model_; +#endif MessageLoop* message_loop_; scoped_refptr<PluginStreamUrl> plugin_data_stream_; diff --git a/webkit/glue/plugins/plugin_list_mac.mm b/webkit/glue/plugins/plugin_list_mac.mm index c470c5a..518d37f 100644 --- a/webkit/glue/plugins/plugin_list_mac.mm +++ b/webkit/glue/plugins/plugin_list_mac.mm @@ -76,19 +76,6 @@ bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info, return false; } - // For now, only load plugins that we know are working reasonably well. - // Anything using QuickDraw-based drawing, for example, would crash - // immediately. - - std::string plugin_name = WideToUTF8(info.name); - if (!(plugin_name == "WebKit Test PlugIn" || - plugin_name == "Shockwave Flash" || - plugin_name == "Picasa" || - plugin_name == "Google Talk Browser Plugin" || - plugin_name == "Google Talk NPAPI Plugin")) { - return false; - } - // Hierarchy check // (we're loading plugins hierarchically from Library folders, so plugins we // encounter earlier must override plugins we encounter later) diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index 6d53339..56f6264 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -237,6 +237,10 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { NPWindow window_; #if defined(OS_MACOSX) NP_CGContext cg_context_; +#ifndef NP_NO_QUICKDRAW + NP_Port qd_port_; + GWorldPtr qd_world_; +#endif #endif gfx::Rect window_rect_; gfx::Rect clip_rect_; diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index ecb2c6f..e40546c 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -27,6 +27,14 @@ #include "webkit/glue/plugins/plugin_stream_url.h" #include "webkit/glue/webkit_glue.h" +// If we're compiling support for the QuickDraw drawing model, turn off GCC +// warnings about deprecated functions (since QuickDraw is a deprecated API). +// According to the GCC documentation, this can only be done per file, not +// pushed and popped like some options can be. +#ifndef NP_NO_QUICKDRAW +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + using webkit_glue::WebPlugin; using webkit_glue::WebPluginDelegate; using webkit_glue::WebPluginResourceClient; @@ -98,11 +106,21 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( user_gesture_msg_factory_(this), null_event_factory_(this), last_mouse_x_(0), - last_mouse_y_(0) { + last_mouse_y_(0), + qd_world_(0) { memset(&window_, 0, sizeof(window_)); +#ifndef NP_NO_QUICKDRAW + memset(&qd_port_, 0, sizeof(qd_port_)); +#endif } WebPluginDelegateImpl::~WebPluginDelegateImpl() { +#ifndef NP_NO_QUICKDRAW + if (qd_port_.port) { + DisposeGWorld(qd_port_.port); + DisposeGWorld(qd_world_); + } +#endif FakePluginWindowTracker::SharedInstance()->RemoveFakeWindowForDelegate( this, reinterpret_cast<WindowRef>(cg_context_.window)); DestroyInstance(); @@ -151,8 +169,22 @@ bool WebPluginDelegateImpl::Initialize(const GURL& url, Rect window_bounds = { 0, 0, window_rect_.height(), window_rect_.width() }; SetWindowBounds(reinterpret_cast<WindowRef>(cg_context_.window), kWindowContentRgn, &window_bounds); - window_.window = &cg_context_; - window_.type = NPWindowTypeWindow; + + switch (instance_->drawing_model()) { +#ifndef NP_NO_QUICKDRAW + case NPDrawingModelQuickDraw: + window_.window = &qd_port_; + window_.type = NPWindowTypeDrawable; + break; +#endif + case NPDrawingModelCoreGraphics: + window_.window = &cg_context_; + window_.type = NPWindowTypeDrawable; + break; + default: + NOTREACHED(); + break; + } plugin->SetWindow(NULL); plugin_url_ = url.spec(); @@ -199,6 +231,32 @@ void WebPluginDelegateImpl::UpdateContext(CGContextRef context) { // changes. if (context != cg_context_.context) { cg_context_.context = context; +#ifndef NP_NO_QUICKDRAW + if (instance()->drawing_model() == NPDrawingModelQuickDraw) { + if (qd_port_.port) { + DisposeGWorld(qd_port_.port); + DisposeGWorld(qd_world_); + qd_port_.port = NULL; + qd_world_ = NULL; + } + Rect window_bounds = { + 0, 0, window_rect_.height(), window_rect_.width() + }; + // Create a GWorld pointing at the same bits as our CGContextRef + NewGWorldFromPtr(&qd_world_, k32BGRAPixelFormat, &window_bounds, + NULL, NULL, 0, + static_cast<Ptr>(CGBitmapContextGetData(context)), + static_cast<SInt32>(CGBitmapContextGetBytesPerRow(context))); + // Create a GWorld for the plugin to paint into whenever it wants + NewGWorld(&qd_port_.port, k32ARGBPixelFormat, &window_bounds, + NULL, NULL, kNativeEndianPixMap); + SetGWorld(qd_port_.port, NULL); + // Fill with black + ForeColor(blackColor); + BackColor(whiteColor); + PaintRect(&window_bounds); + } +#endif WindowlessSetWindow(true); } } @@ -296,25 +354,62 @@ void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, static StatsRate plugin_paint("Plugin.Paint"); StatsScope<StatsRate> scope(plugin_paint); - // We save and restore the NSGraphicsContext state in case the plugin uses - // Cocoa drawing. - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext - graphicsContextWithGraphicsPort:context - flipped:YES]]; - CGContextSaveGState(context); - - NPEvent paint_event; - paint_event.what = updateEvt; - paint_event.message = reinterpret_cast<uint32>(cg_context_.window); - paint_event.when = TickCount(); - paint_event.where.h = 0; - paint_event.where.v = 0; - paint_event.modifiers = 0; - instance()->NPP_HandleEvent(&paint_event); - - CGContextRestoreGState(context); - [NSGraphicsContext restoreGraphicsState]; + switch (instance()->drawing_model()) { +#ifndef NP_NO_QUICKDRAW + case NPDrawingModelQuickDraw: + { + // Plugins using the QuickDraw drawing model do not restrict their + // drawing to update events the way that CoreGraphics-based plugins + // do. When we are asked to paint, we therefore just copy from the + // plugin's persistent offscreen GWorld into our shared memory bitmap + // context. + Rect window_bounds = { + 0, 0, window_rect_.height(), window_rect_.width() + }; + PixMapHandle plugin_pixmap = GetGWorldPixMap(qd_port_.port); + if (LockPixels(plugin_pixmap)) { + PixMapHandle shared_pixmap = GetGWorldPixMap(qd_world_); + if (LockPixels(shared_pixmap)) { + SetGWorld(qd_world_, NULL); + // Set foreground and background colors to avoid "colorizing" the + // image. + ForeColor(blackColor); + BackColor(whiteColor); + CopyBits(reinterpret_cast<BitMap*>(*plugin_pixmap), + reinterpret_cast<BitMap*>(*shared_pixmap), + &window_bounds, &window_bounds, srcCopy, NULL); + UnlockPixels(shared_pixmap); + } + UnlockPixels(plugin_pixmap); + } + break; + } +#endif + case NPDrawingModelCoreGraphics: + { + NPEvent paint_event; + + // Save and restore the NSGraphicsContext state in case the plugin uses + // Cocoa drawing. + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext: + [NSGraphicsContext graphicsContextWithGraphicsPort:context + flipped:YES]]; + CGContextSaveGState(context); + + paint_event.what = updateEvt; + paint_event.message = reinterpret_cast<uint32>(cg_context_.window); + paint_event.when = TickCount(); + paint_event.where.h = 0; + paint_event.where.v = 0; + paint_event.modifiers = 0; + instance()->NPP_HandleEvent(&paint_event); + + CGContextRestoreGState(context); + [NSGraphicsContext restoreGraphicsState]; + break; + } + } } // Moves our dummy window to the given offset relative to the last known @@ -364,6 +459,7 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { window_rect_.y(), window_rect_.width(), window_rect_.height()); NPError err = instance()->NPP_SetWindow(&window_); + DCHECK(err == NPERR_NO_ERROR); } @@ -515,6 +611,7 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, NPEvent np_event = {0}; if (!NPEventFromWebInputEvent(event, &np_event)) { + LOG(WARNING) << "NPEventFromWebInputEvent failed"; return false; } np_event.when = TickCount(); @@ -533,9 +630,20 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, UpdateWindowLocation(reinterpret_cast<WindowRef>(cg_context_.window), *mouse_event); } - CGContextSaveGState(cg_context_.context); - bool ret = instance()->NPP_HandleEvent(&np_event) != 0; - CGContextRestoreGState(cg_context_.context); + bool ret = false; + switch (instance()->drawing_model()) { +#ifndef NP_NO_QUICKDRAW + case NPDrawingModelQuickDraw: + SetGWorld(qd_port_.port, NULL); + ret = instance()->NPP_HandleEvent(&np_event) != 0; + break; +#endif + case NPDrawingModelCoreGraphics: + CGContextSaveGState(cg_context_.context); + ret = instance()->NPP_HandleEvent(&np_event) != 0; + CGContextRestoreGState(cg_context_.context); + break; + } return ret; } @@ -561,6 +669,16 @@ WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( } void WebPluginDelegateImpl::OnNullEvent() { + // Dispatch any pending Carbon events so that the plugin's event handlers + // will get called on any windows it has created. + EventRef event; + while (ReceiveNextEvent( + 0, NULL, kEventDurationNoWait, kEventRemoveFromQueue, &event) == noErr) { + SendEventToEventTarget(event, GetEventDispatcherTarget()); + ReleaseEvent(event); + } + + // Send an idle event so that the plugin can do background work NPEvent np_event = {0}; np_event.what = nullEvent; np_event.when = TickCount(); @@ -571,6 +689,15 @@ void WebPluginDelegateImpl::OnNullEvent() { np_event.where.v = last_mouse_y_; instance()->NPP_HandleEvent(&np_event); +#ifndef NP_NO_QUICKDRAW + // Quickdraw-based plugins can draw at any time, so tell the renderer to + // repaint. + // TODO: only do this if the contents of the offscreen GWorld has changed, + // so as not to spam the renderer with an unchanging image. + if (instance_->drawing_model() == NPDrawingModelQuickDraw) + instance()->webplugin()->Invalidate(); +#endif + MessageLoop::current()->PostDelayedTask(FROM_HERE, null_event_factory_.NewRunnableMethod( &WebPluginDelegateImpl::OnNullEvent), |