Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Unified Diff: webkit/glue/plugins/webplugin_delegate_impl_mac.mm

Issue 165250: Merge 22799 - Set up a interposing library for Carbon calls made by plugins.... (Closed) Base URL: svn://chrome-svn/chrome/branches/197/src/
Patch Set: Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webkit/glue/plugins/fake_plugin_window_tracker_mac.cc ('k') | webkit/webkit.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webkit/glue/plugins/webplugin_delegate_impl_mac.mm
===================================================================
--- webkit/glue/plugins/webplugin_delegate_impl_mac.mm (revision 22935)
+++ webkit/glue/plugins/webplugin_delegate_impl_mac.mm (working copy)
@@ -1,609 +0,0 @@
-// Copyright (c) 2006-2008 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.
-
-#import <Cocoa/Cocoa.h>
-
-#include "webkit/glue/plugins/webplugin_delegate_impl.h"
-
-#include <string>
-#include <vector>
-
-#include "base/file_util.h"
-#include "base/lazy_instance.h"
-#include "base/message_loop.h"
-#include "base/stats_counters.h"
-#include "base/string_util.h"
-#include "webkit/api/public/WebInputEvent.h"
-#include "webkit/default_plugin/plugin_impl.h"
-#include "webkit/glue/glue_util.h"
-#include "webkit/glue/webplugin.h"
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/plugin_stream_url.h"
-#include "webkit/glue/webkit_glue.h"
-
-using WebKit::WebCursorInfo;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebInputEvent;
-using WebKit::WebMouseEvent;
-
-// 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
-// accomodated by the WebPluginDelegate class.
-
-namespace {
-
-// The fastest we are willing to process idle events for plugins.
-// Some can easily exceed the limits of our CPU if we don't throttle them.
-// The throttle has been chosen by using the same value as Apple's WebKit port.
-//
-// We'd like to make the throttle delay variable, based on the amount of
-// time currently required to paint plugins. There isn't a good
-// way to count the time spent in aggregate plugin painting, however, so
-// this seems to work well enough.
-const int kPluginIdleThrottleDelayMs = 20; // 20ms (50Hz)
-
-// The most recently seen offset between global and local coordinates. We use
-// this to keep the placeholder Carbon WindowRef's origin in sync with the
-// actual browser window, without having to pass that geometry over IPC. If we
-// end up needing to interpose on Carbon APIs in the plugin process (in order
-// to simulate window activation, for example), this could be replaced by
-// interposing on GlobalToLocal and/or LocalToGlobal (see related TODO comments
-// below in WebPluginDelegateImpl::OnNullEvent()).
-
-int g_current_x_offset = 0;
-int g_current_y_offset = 0;
-
-WindowRef g_last_front_window = NULL;
-ProcessSerialNumber g_saved_front_process;
-
-} // namespace
-
-WebPluginDelegate* WebPluginDelegate::Create(
- const FilePath& filename,
- const std::string& mime_type,
- gfx::PluginWindowHandle containing_view) {
- scoped_refptr<NPAPI::PluginLib> plugin =
- NPAPI::PluginLib::CreatePluginLib(filename);
- if (plugin.get() == NULL)
- return NULL;
-
- NPError err = plugin->NP_Initialize();
- if (err != NPERR_NO_ERROR)
- return NULL;
-
- scoped_refptr<NPAPI::PluginInstance> instance =
- plugin->CreateInstance(mime_type);
- return new WebPluginDelegateImpl(containing_view, instance.get());
-}
-
-WebPluginDelegateImpl::WebPluginDelegateImpl(
- gfx::PluginWindowHandle containing_view,
- NPAPI::PluginInstance *instance)
- : parent_(containing_view),
- instance_(instance),
- quirks_(0),
- plugin_(NULL),
- // all Mac plugins are "windowless" in the Windows/X11 sense
- windowless_(true),
- windowless_needs_set_window_(true),
- handle_event_depth_(0),
- user_gesture_message_posted_(this),
- user_gesture_msg_factory_(this),
- null_event_factory_(this),
- last_mouse_x_(0),
- last_mouse_y_(0) {
- memset(&window_, 0, sizeof(window_));
-}
-
-WebPluginDelegateImpl::~WebPluginDelegateImpl() {
- DestroyInstance();
-
- if (cg_context_.window)
- DisposeWindow(cg_context_.window);
-}
-
-void WebPluginDelegateImpl::PluginDestroyed() {
- delete this;
-}
-
-bool WebPluginDelegateImpl::Initialize(const GURL& url,
- char** argn,
- char** argv,
- int argc,
- WebPlugin* plugin,
- bool load_manually) {
- plugin_ = plugin;
-
- instance_->set_web_plugin(plugin);
- NPAPI::PluginInstance* old_instance =
- NPAPI::PluginInstance::SetInitializingInstance(instance_);
-
-
- bool start_result = instance_->Start(url, argn, argv, argc, load_manually);
-
- NPAPI::PluginInstance::SetInitializingInstance(old_instance);
-
- if (!start_result)
- return false;
-
- cg_context_.window = NULL;
- window_.window = &cg_context_;
- window_.type = NPWindowTypeWindow;
-
- plugin->SetWindow(NULL);
- plugin_url_ = url.spec();
-
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- null_event_factory_.NewRunnableMethod(
- &WebPluginDelegateImpl::OnNullEvent),
- kPluginIdleThrottleDelayMs);
- return true;
-}
-
-void WebPluginDelegateImpl::DestroyInstance() {
- if (instance_ && (instance_->npp()->ndata != NULL)) {
- // Shutdown all streams before destroying so that
- // no streams are left "in progress". Need to do
- // this before calling set_web_plugin(NULL) because the
- // instance uses the helper to do the download.
- instance_->CloseStreams();
- instance_->NPP_Destroy();
- instance_->set_web_plugin(NULL);
- instance_ = 0;
- }
-}
-
-void WebPluginDelegateImpl::UpdateGeometry(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
-
- DCHECK(windowless_);
- WindowlessUpdateGeometry(window_rect, clip_rect);
-}
-
-void WebPluginDelegateImpl::Paint(CGContextRef context, const gfx::Rect& rect) {
- DCHECK(windowless_);
- WindowlessPaint(context, rect);
-}
-
-void WebPluginDelegateImpl::Print(CGContextRef context) {
- // Disabling the call to NPP_Print as it causes a crash in
- // flash in some cases. In any case this does not work as expected
- // as the EMF meta file dc passed in needs to be created with the
- // the plugin window dc as its sibling dc and the window rect
- // in .01 mm units.
-}
-
-NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
- return instance_->GetPluginScriptableObject();
-}
-
-void WebPluginDelegateImpl::DidFinishLoadWithReason(NPReason reason) {
- instance()->DidFinishLoadWithReason(reason);
-}
-
-int WebPluginDelegateImpl::GetProcessId() {
- // We are in process, so the plugin pid is this current process pid.
- return getpid();
-}
-
-void WebPluginDelegateImpl::SendJavaScriptStream(const std::string& url,
- const std::wstring& result,
- bool success,
- bool notify_needed,
- intptr_t notify_data) {
- instance()->SendJavaScriptStream(url, result, success, notify_needed,
- notify_data);
-}
-
-void WebPluginDelegateImpl::DidReceiveManualResponse(
- const std::string& url, const std::string& mime_type,
- const std::string& headers, uint32 expected_length, uint32 last_modified) {
- instance()->DidReceiveManualResponse(url, mime_type, headers,
- expected_length, last_modified);
-}
-
-void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
- int length) {
- instance()->DidReceiveManualData(buffer, length);
-}
-
-void WebPluginDelegateImpl::DidFinishManualLoading() {
- instance()->DidFinishManualLoading();
-}
-
-void WebPluginDelegateImpl::DidManualLoadFail() {
- instance()->DidManualLoadFail();
-}
-
-FilePath WebPluginDelegateImpl::GetPluginPath() {
- return instance()->plugin_lib()->plugin_info().path;
-}
-
-void WebPluginDelegateImpl::InstallMissingPlugin() {
- NPEvent evt;
- instance()->NPP_HandleEvent(&evt);
-}
-
-void WebPluginDelegateImpl::WindowlessUpdateGeometry(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- // Only resend to the instance if the geometry has changed.
- if (window_rect == window_rect_ && clip_rect == clip_rect_)
- return;
-
- // We will inform the instance of this change when we call NPP_SetWindow.
- clip_rect_ = clip_rect;
-
- if (window_rect_ != window_rect) {
- window_rect_ = window_rect;
-
- WindowlessSetWindow(true);
- }
-}
-
-void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context,
- const gfx::Rect& damage_rect) {
- 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);
-
- cg_context_.context = context;
- if (window_.window == NULL)
- windowless_needs_set_window_ = true;
-
- window_.window = &cg_context_;
-
- if (windowless_needs_set_window_)
- WindowlessSetWindow(false);
-
- 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];
-}
-
-// Moves our dummy window to the given offset relative to the last known
-// location of the real renderer window's content view.
-static void UpdateDummyWindowLocationWithOffset(WindowRef window,
- int x_offset, int y_offset) {
- int target_x = g_current_x_offset + x_offset;
- int target_y = g_current_y_offset + y_offset;
- Rect window_bounds;
- GetWindowBounds(window, kWindowContentRgn, &window_bounds);
- if ((window_bounds.left != target_x) ||
- (window_bounds.top != target_y)) {
- int height = window_bounds.bottom - window_bounds.top;
- int width = window_bounds.right - window_bounds.left;
- window_bounds.left = target_x;
- window_bounds.top = target_y;
- window_bounds.right = window_bounds.left + width;
- window_bounds.bottom = window_bounds.top + height;
- SetWindowBounds(window, kWindowContentRgn, &window_bounds);
- }
-}
-
-void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
- if (!instance())
- return;
-
- if (window_rect_.IsEmpty()) // wait for geometry to be set.
- return;
-
- window_.clipRect.top = 0;
- window_.clipRect.left = 0;
- window_.clipRect.bottom = window_rect_.height();
- window_.clipRect.right = window_rect_.width();
- window_.height = window_rect_.height();
- window_.width = window_rect_.width();
- window_.x = 0;
- window_.y = 0;
- window_.type = NPWindowTypeWindow;
-
- if (!force_set_window)
- // Reset this flag before entering the instance in case of side-effects.
- windowless_needs_set_window_ = false;
-
- if (!cg_context_.window) {
- // For all plugins we create a placeholder offscreen window for the use
- // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the
- // "browser window", even if we're not using the Quickdraw drawing model.
- // Not having a valid window reference causes subtle bugs with plugins
- // which retreive the NPWindow and validate the same. The NPWindow
- // can be retreived via NPN_GetValue of NPNVnetscapeWindow.
- Rect window_bounds = { 0, 0, window_rect_.height(), window_rect_.width() };
- WindowRef window_ref;
- if (CreateNewWindow(kDocumentWindowClass,
- kWindowStandardDocumentAttributes,
- &window_bounds,
- &window_ref) == noErr) {
- cg_context_.window = window_ref;
- SelectWindow(window_ref);
- g_last_front_window = window_ref;
- }
- }
- UpdateDummyWindowLocationWithOffset(cg_context_.window, window_rect_.x(),
- window_rect_.y());
-
- if (!force_set_window)
- windowless_needs_set_window_ = false;
- NPError err = instance()->NPP_SetWindow(&window_);
- DCHECK(err == NPERR_NO_ERROR);
-}
-
-void WebPluginDelegateImpl::SetFocus() {
- NPEvent focus_event = { 0 };
- focus_event.what = NPEventType_GetFocusEvent;
- focus_event.when = TickCount();
- instance()->NPP_HandleEvent(&focus_event);
-}
-
-static bool WebInputEventIsWebMouseEvent(const WebInputEvent& event) {
- switch (event.type) {
- case WebInputEvent::MouseMove:
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseEnter:
- case WebInputEvent::MouseDown:
- case WebInputEvent::MouseUp:
- if (event.size < sizeof(WebMouseEvent)) {
- NOTREACHED();
- return false;
- }
- return true;
- default:
- return false;
- }
-}
-
-static bool WebInputEventIsWebKeyboardEvent(const WebInputEvent& event) {
- switch (event.type) {
- case WebInputEvent::KeyDown:
- case WebInputEvent::KeyUp:
- if (event.size < sizeof(WebKeyboardEvent)) {
- NOTREACHED();
- return false;
- }
- return true;
- default:
- return false;
- }
-}
-
-static bool NPEventFromWebMouseEvent(const WebMouseEvent& event,
- NPEvent *np_event) {
- np_event->where.h = event.globalX;
- np_event->where.v = event.globalY;
-
- if (event.modifiers & WebInputEvent::ControlKey)
- np_event->modifiers |= controlKey;
- if (event.modifiers & WebInputEvent::ShiftKey)
- np_event->modifiers |= shiftKey;
-
- // default to "button up"; override this for mouse down events below.
- np_event->modifiers |= btnState;
-
- switch (event.button) {
- case WebMouseEvent::ButtonLeft:
- break;
- case WebMouseEvent::ButtonMiddle:
- np_event->modifiers |= cmdKey;
- break;
- case WebMouseEvent::ButtonRight:
- np_event->modifiers |= controlKey;
- break;
- }
- switch (event.type) {
- case WebInputEvent::MouseMove:
- np_event->what = nullEvent;
- return true;
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseEnter:
- np_event->what = NPEventType_AdjustCursorEvent;
- return true;
- case WebInputEvent::MouseDown:
- np_event->modifiers &= ~btnState;
- np_event->what = mouseDown;
- return true;
- case WebInputEvent::MouseUp:
- np_event->what = mouseUp;
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event,
- NPEvent *np_event) {
- // TODO: figure out how to handle Unicode input to plugins, if that's
- // even possible in the NPAPI Carbon event model.
- np_event->message = (event.nativeKeyCode << 8) & keyCodeMask;
- np_event->message |= event.text[0] & charCodeMask;
- np_event->modifiers |= btnState;
- if (event.modifiers & WebInputEvent::ControlKey)
- np_event->modifiers |= controlKey;
- if (event.modifiers & WebInputEvent::ShiftKey)
- np_event->modifiers |= shiftKey;
- if (event.modifiers & WebInputEvent::AltKey)
- np_event->modifiers |= cmdKey;
- if (event.modifiers & WebInputEvent::MetaKey)
- np_event->modifiers |= optionKey;
-
- switch (event.type) {
- case WebInputEvent::KeyDown:
- if (event.modifiers & WebInputEvent::IsAutoRepeat)
- np_event->what = autoKey;
- else
- np_event->what = keyDown;
- return true;
- case WebInputEvent::KeyUp:
- np_event->what = keyUp;
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-static bool NPEventFromWebInputEvent(const WebInputEvent& event,
- NPEvent* np_event) {
- if (WebInputEventIsWebMouseEvent(event)) {
- return NPEventFromWebMouseEvent(*static_cast<const WebMouseEvent*>(&event),
- np_event);
- } else if (WebInputEventIsWebKeyboardEvent(event)) {
- return NPEventFromWebKeyboardEvent(
- *static_cast<const WebKeyboardEvent*>(&event), np_event);
- }
- DLOG(WARNING) << "unknown event type" << event.type;
- return false;
-}
-
-static void UpdateWindowLocation(WindowRef window, const WebMouseEvent& event) {
- // TODO: figure out where the vertical offset of 22 comes from (and if 22 is
- // exactly right) and replace with an appropriate calculation. It feels like
- // window structure or the menu bar, but neither should be involved here.
- g_current_x_offset = event.globalX - event.windowX;
- g_current_y_offset = event.globalY - event.windowY + 22;
-
- UpdateDummyWindowLocationWithOffset(window, event.windowX - event.x,
- event.windowY - event.y);
-}
-
-bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event,
- WebCursorInfo* cursor) {
- DCHECK(windowless_) << "events should only be received in windowless mode";
- DCHECK(cursor != NULL);
-
- NPEvent np_event = {0};
- if (!NPEventFromWebInputEvent(event, &np_event)) {
- return false;
- }
- np_event.when = TickCount();
- if (np_event.what == nullEvent) {
- last_mouse_x_ = np_event.where.h;
- last_mouse_y_ = np_event.where.v;
- return true; // Let the recurring task actually send the event.
- }
-
- // If this is a mouse event, we need to make sure our dummy window has the
- // correct location before we send the event to the plugin, so that any
- // coordinate conversion the plugin does will work out.
- if (WebInputEventIsWebMouseEvent(event)) {
- const WebMouseEvent* mouse_event =
- static_cast<const WebMouseEvent*>(&event);
- UpdateWindowLocation(cg_context_.window, *mouse_event);
- }
- CGContextSaveGState(cg_context_.context);
- bool ret = instance()->NPP_HandleEvent(&np_event) != 0;
- CGContextRestoreGState(cg_context_.context);
- return ret;
-}
-
-WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
- int resource_id, const std::string &url, bool notify_needed,
- intptr_t notify_data, intptr_t existing_stream) {
- // Stream already exists. This typically happens for range requests
- // initiated via NPN_RequestRead.
- if (existing_stream) {
- NPAPI::PluginStream* plugin_stream =
- reinterpret_cast<NPAPI::PluginStream*>(existing_stream);
-
- plugin_stream->CancelRequest();
-
- return plugin_stream->AsResourceClient();
- }
-
- if (notify_needed) {
- instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
- }
- std::string mime_type;
- NPAPI::PluginStreamUrl *stream = instance()->CreateStream(
- resource_id, url, mime_type, notify_needed,
- reinterpret_cast<void*>(notify_data));
- return stream;
-}
-
-void WebPluginDelegateImpl::URLRequestRouted(const std::string&url,
- bool notify_needed,
- intptr_t notify_data) {
- if (notify_needed) {
- instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
- }
-}
-
-void WebPluginDelegateImpl::OnNullEvent() {
- NPEvent np_event = {0};
- np_event.what = nullEvent;
- np_event.when = TickCount();
- np_event.modifiers = GetCurrentKeyModifiers();
- if (!Button())
- np_event.modifiers |= btnState;
- np_event.where.h = last_mouse_x_;
- np_event.where.v = last_mouse_y_;
- instance()->NPP_HandleEvent(&np_event);
-
- WindowRef front_window = FrontWindow();
- if (front_window == cg_context_.window) {
- if (front_window != g_last_front_window) {
- // If our dummy window is now the front window, but was not previously,
- // it means that a plugin window has been destroyed. Make sure our fake
- // browser window is selected.
- // TODO: Use DYLD_INSERT_LIBRARIES to interpose on Carbon window
- // APIs within the plugin process. This will allow us to (a) get rid of
- // the dummy window, and (b) explicitly track the creation and
- // destruction of windows by the plugin.
- g_last_front_window = front_window;
- SelectWindow(cg_context_.window);
-
- // If the plugin process is still the front process, bring the prior
- // front process (normally this will be the browser process) back to
- // the front.
- // TODO: make this an IPC message so that the browser can properly
- // reactivate the window.
- ProcessSerialNumber this_process, front_process;
- GetCurrentProcess(&this_process);
- GetFrontProcess(&front_process);
- Boolean matched = false;
- SameProcess(&this_process, &front_process, &matched);
- if (matched)
- SetFrontProcess(&g_saved_front_process);
- g_last_front_window = FrontWindow();
- }
- } else if (front_window != g_last_front_window) {
- // The plugin has just created a new window and brought it to the front.
- // bring the plugin process to the front so that the user can see it (for
- // example, an alert or file selection dialog).
- // TODO: make this an IPC to order the plugin process above the browser
- // process but not necessarily the frontmost.
- ProcessSerialNumber this_process;
- GetCurrentProcess(&this_process);
- GetFrontProcess(&g_saved_front_process);
- SetFrontProcess(&this_process);
- g_last_front_window = front_window;
- SelectWindow(front_window);
- }
-
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- null_event_factory_.NewRunnableMethod(
- &WebPluginDelegateImpl::OnNullEvent),
- kPluginIdleThrottleDelayMs);
-}
Property changes on: webkit/glue/plugins/webplugin_delegate_impl_mac.mm
___________________________________________________________________
Added: svn:mergeinfo
Merged /branches/chrome_webkit_merge_branch/src/webkit/glue/plugins/webplugin_delegate_impl_mac.mm:r3734-4217,4606-5108,5177-5263
Merged /trunk/src/webkit/glue/plugins/webplugin_delegate_impl_mac.mm:r22799
« no previous file with comments | « webkit/glue/plugins/fake_plugin_window_tracker_mac.cc ('k') | webkit/webkit.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698