summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorstuartmorgan@google.com <stuartmorgan@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-07 22:03:17 +0000
committerstuartmorgan@google.com <stuartmorgan@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-07 22:03:17 +0000
commitf3ef7b1c17b3f9a1db703a7b099e697e401d21a9 (patch)
treec6252141eeb6637bb2a4630d1735bbf965933a56 /webkit
parent1ef7ccfa171759ab86cdf6b98cf5145b9db688b0 (diff)
downloadchromium_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.cc49
-rw-r--r--webkit/glue/plugins/fake_plugin_window_tracker_mac.h42
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_mac.mm98
-rw-r--r--webkit/webkit.gyp2
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',