diff options
author | stuartmorgan@google.com <stuartmorgan@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-07 22:03:17 +0000 |
---|---|---|
committer | stuartmorgan@google.com <stuartmorgan@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-07 22:03:17 +0000 |
commit | f3ef7b1c17b3f9a1db703a7b099e697e401d21a9 (patch) | |
tree | c6252141eeb6637bb2a4630d1735bbf965933a56 /webkit | |
parent | 1ef7ccfa171759ab86cdf6b98cf5145b9db688b0 (diff) | |
download | chromium_src-f3ef7b1c17b3f9a1db703a7b099e697e401d21a9.zip chromium_src-f3ef7b1c17b3f9a1db703a7b099e697e401d21a9.tar.gz chromium_src-f3ef7b1c17b3f9a1db703a7b099e697e401d21a9.tar.bz2 |
Set up a interposing library for Carbon calls made by plugins.
This gives us a library that's inserted into plugin process via DYLD_INSERT_LIBRARIES to intercept Carbon calls, and moves the window/process activation handling into that library (based on Carbon window activation/deactivation calls, rather than polling the front window). Over time we'll interpose more, but this gives us the foundation.
This fixes both the "window loses focus when loading a page with plugins" and "can't click on YouTube controls" bugs.
BUG=18203,18553
TEST=Clicking on Flash plugins should work much more reliably, opening a page with a plugin shouldn't cause the window to lose focus.
Review URL: http://codereview.chromium.org/164100
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22799 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/plugins/fake_plugin_window_tracker_mac.cc | 49 | ||||
-rw-r--r-- | webkit/glue/plugins/fake_plugin_window_tracker_mac.h | 42 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 98 | ||||
-rw-r--r-- | webkit/webkit.gyp | 2 |
4 files changed, 116 insertions, 75 deletions
diff --git a/webkit/glue/plugins/fake_plugin_window_tracker_mac.cc b/webkit/glue/plugins/fake_plugin_window_tracker_mac.cc new file mode 100644 index 0000000..9f809a5 --- /dev/null +++ b/webkit/glue/plugins/fake_plugin_window_tracker_mac.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2009 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/logging.h" +#include "webkit/glue/plugins/fake_plugin_window_tracker_mac.h" + +FakePluginWindowTracker::FakePluginWindowTracker() + : window_to_delegate_map_(CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, NULL, NULL)) { +} + +FakePluginWindowTracker* FakePluginWindowTracker::SharedInstance() { + static FakePluginWindowTracker* tracker = new FakePluginWindowTracker(); + return tracker; +} + +WindowRef FakePluginWindowTracker::GenerateFakeWindowForDelegate( + WebPluginDelegateImpl* delegate) { + // TODO(stuartmorgan): Eventually we will be interposing enough that we don't + // even need a window, and can just use made-up identifiers, but for now we + // create one so that things that we don't interpose won't crash trying to use + // a bad WindowRef. + + // The real size will be set by the plugin instance, once that size is known. + Rect window_bounds = { 0, 0, 100, 100 }; + WindowRef new_ref = NULL; + if (CreateNewWindow(kDocumentWindowClass, + kWindowStandardDocumentAttributes, + &window_bounds, + &new_ref) == noErr) { + CFDictionaryAddValue(window_to_delegate_map_, new_ref, delegate); + } + return new_ref; +} + +const WebPluginDelegateImpl* FakePluginWindowTracker::GetDelegateForFakeWindow( + WindowRef window) const { + return static_cast<const WebPluginDelegateImpl*>( + CFDictionaryGetValue(window_to_delegate_map_, window)); +} + +void FakePluginWindowTracker::RemoveFakeWindowForDelegate( + WebPluginDelegateImpl* delegate, WindowRef window) { + DCHECK(GetDelegateForFakeWindow(window) == delegate); + CFDictionaryRemoveValue(window_to_delegate_map_, delegate); + if (window) // Check just in case the initial window creation failed. + DisposeWindow(window); +} diff --git a/webkit/glue/plugins/fake_plugin_window_tracker_mac.h b/webkit/glue/plugins/fake_plugin_window_tracker_mac.h new file mode 100644 index 0000000..d2e7bee --- /dev/null +++ b/webkit/glue/plugins/fake_plugin_window_tracker_mac.h @@ -0,0 +1,42 @@ +// Copyright (c) 2009 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_FAKE_PLUGIN_WINDOW_TRACKER_MAC_H_ +#define WEBKIT_GLUE_PLUGINS_FAKE_PLUGIN_WINDOW_TRACKER_MAC_H_ + +#include <Carbon/Carbon.h> + +#include "base/basictypes.h" +#include "base/scoped_cftyperef.h" + +class WebPluginDelegateImpl; + +// Serves as a bridge between password delegate instances and the Carbon +// interposing library. The Carbon functions we interpose work in terms of +// WindowRefs, and we need to be able to map from those back to the plugin +// delegates that know what we should claim about the state of the world. +class __attribute__((visibility("default"))) FakePluginWindowTracker { + public: + FakePluginWindowTracker(); + + // Returns the shared window tracker instance. + static FakePluginWindowTracker* SharedInstance(); + + // Creates a new fake window ref associated with |delegate|. + WindowRef GenerateFakeWindowForDelegate(WebPluginDelegateImpl* delegate); + + // Returns the WebPluginDelegate associated with the given fake window ref. + const WebPluginDelegateImpl* GetDelegateForFakeWindow(WindowRef window) const; + + // Removes the fake window ref entry for |delegate|. + void RemoveFakeWindowForDelegate(WebPluginDelegateImpl* delegate, + WindowRef window); + + private: + scoped_cftyperef<CFMutableDictionaryRef> window_to_delegate_map_; + + DISALLOW_COPY_AND_ASSIGN(FakePluginWindowTracker); +}; + +#endif // WEBKIT_GLUE_PLUGINS_FAKE_PLUGIN_WINDOW_TRACKER_MAC_H_ diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index e5da9eb..4fda86d 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -18,6 +18,7 @@ #include "webkit/default_plugin/plugin_impl.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webplugin.h" +#include "webkit/glue/plugins/fake_plugin_window_tracker_mac.h" #include "webkit/glue/plugins/plugin_constants_win.h" #include "webkit/glue/plugins/plugin_instance.h" #include "webkit/glue/plugins/plugin_lib.h" @@ -58,9 +59,6 @@ const int kPluginIdleThrottleDelayMs = 20; // 20ms (50Hz) 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( @@ -101,10 +99,9 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( } WebPluginDelegateImpl::~WebPluginDelegateImpl() { + FakePluginWindowTracker::SharedInstance()->RemoveFakeWindowForDelegate( + this, cg_context_.window); DestroyInstance(); - - if (cg_context_.window) - DisposeWindow(cg_context_.window); } void WebPluginDelegateImpl::PluginDestroyed() { @@ -131,7 +128,11 @@ bool WebPluginDelegateImpl::Initialize(const GURL& url, if (!start_result) return false; - cg_context_.window = NULL; + FakePluginWindowTracker* window_tracker = + FakePluginWindowTracker::SharedInstance(); + cg_context_.window = window_tracker->GenerateFakeWindowForDelegate(this); + Rect window_bounds = { 0, 0, window_rect_.height(), window_rect_.width() }; + SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds); window_.window = &cg_context_; window_.type = NPWindowTypeWindow; @@ -161,7 +162,6 @@ void WebPluginDelegateImpl::DestroyInstance() { void WebPluginDelegateImpl::UpdateGeometry( const gfx::Rect& window_rect, const gfx::Rect& clip_rect) { - DCHECK(windowless_); WindowlessUpdateGeometry(window_rect, clip_rect); } @@ -284,16 +284,22 @@ void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, // 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) { +// If new_width or new_height is non-zero, the window size (content region) +// will be updated accordingly; if they are zero, the existing size will be +// preserved. +static void UpdateDummyWindowBoundsWithOffset(WindowRef window, + int x_offset, int y_offset, + int new_width, int new_height) { 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; + int height = new_height ? new_height + : window_bounds.bottom - window_bounds.top; + int width = new_width ? new_width + : window_bounds.right - window_bounds.left; window_bounds.left = target_x; window_bounds.top = target_y; window_bounds.right = window_bounds.left + width; @@ -323,26 +329,9 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool 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()); + UpdateDummyWindowBoundsWithOffset(cg_context_.window, window_rect_.x(), + window_rect_.y(), window_rect_.width(), + window_rect_.height()); if (!force_set_window) windowless_needs_set_window_ = false; @@ -484,8 +473,8 @@ static void UpdateWindowLocation(WindowRef window, const WebMouseEvent& event) { 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); + UpdateDummyWindowBoundsWithOffset(window, event.windowX - event.x, + event.windowY - event.y, 0, 0); } bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, @@ -561,47 +550,6 @@ void WebPluginDelegateImpl::OnNullEvent() { 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), diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 9204703..033acf8 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -1274,6 +1274,8 @@ 'glue/plugins/mozilla_extensions.cc', 'glue/plugins/mozilla_extensions.h', 'glue/plugins/nphostapi.h', + 'glue/plugins/fake_plugin_window_tracker_mac.h', + 'glue/plugins/fake_plugin_window_tracker_mac.cc', 'glue/plugins/gtk_plugin_container.h', 'glue/plugins/gtk_plugin_container.cc', 'glue/plugins/gtk_plugin_container_manager.h', |