summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-13 22:18:58 +0000
committerevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-13 22:18:58 +0000
commita2d489b22f9e3f361adeaf7a09ae88510a2bb1e3 (patch)
treeff3dd61a3278c60286a820e9f07952e4571743e5
parent16ead307a2b27b7d02bae66792eaf3c2f904b9c0 (diff)
downloadchromium_src-a2d489b22f9e3f361adeaf7a09ae88510a2bb1e3.zip
chromium_src-a2d489b22f9e3f361adeaf7a09ae88510a2bb1e3.tar.gz
chromium_src-a2d489b22f9e3f361adeaf7a09ae88510a2bb1e3.tar.bz2
Basic windowless plugins, try 2.
In response to Dean's comment on http://codereview.chromium.org/39105, I redid that patch to put the X munging into the plugin implementation. This won't work for multiproc, but it's near the correct place and many things will need to be changed for multiproc. Review URL: http://codereview.chromium.org/42056 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11674 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/gfx/native_widget_types.h5
-rw-r--r--skia/ext/bitmap_platform_device_linux.h4
-rw-r--r--skia/ext/platform_canvas_linux.cc4
-rw-r--r--skia/ext/platform_canvas_linux.h7
-rw-r--r--skia/ext/platform_device_linux.h4
-rw-r--r--webkit/glue/plugins/plugin_host.cc7
-rw-r--r--webkit/glue/plugins/plugin_instance.cc11
-rw-r--r--webkit/glue/plugins/plugin_instance.h2
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h12
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_gtk.cc133
-rw-r--r--webkit/glue/webplugin_impl.cc9
11 files changed, 143 insertions, 55 deletions
diff --git a/base/gfx/native_widget_types.h b/base/gfx/native_widget_types.h
index c45b1a7..32d6012 100644
--- a/base/gfx/native_widget_types.h
+++ b/base/gfx/native_widget_types.h
@@ -49,6 +49,7 @@ class NSTextField;
#elif defined(OS_LINUX)
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
+typedef struct _cairo_surface cairo_surface_t;
#endif
namespace gfx {
@@ -67,9 +68,7 @@ typedef CGContext* NativeDrawingContext;
typedef GtkWidget* NativeView;
typedef GtkWindow* NativeWindow;
typedef GtkWidget* NativeEditView;
-typedef void *NativeDrawingContext; // TODO(port): update for Gtk
-#else // null port.
-#error No known OS defined
+typedef cairo_surface_t* NativeDrawingContext;
#endif
// Note: for test_shell we're packing a pointer into the NativeViewId. So, if
diff --git a/skia/ext/bitmap_platform_device_linux.h b/skia/ext/bitmap_platform_device_linux.h
index d26c50d..bb261bd 100644
--- a/skia/ext/bitmap_platform_device_linux.h
+++ b/skia/ext/bitmap_platform_device_linux.h
@@ -85,6 +85,10 @@ class BitmapPlatformDeviceLinux : public PlatformDeviceLinux {
// Bitmaps aren't vector graphics.
virtual bool IsVectorial() { return false; }
+ // If someone wants to paint on a Cairo surface version of our
+ // buffer, then give them the surface we're already using.
+ virtual cairo_surface_t* beginPlatformPaint() { return surface(); }
+
cairo_surface_t* surface() const;
private:
diff --git a/skia/ext/platform_canvas_linux.cc b/skia/ext/platform_canvas_linux.cc
index 422693c..a4e080f 100644
--- a/skia/ext/platform_canvas_linux.cc
+++ b/skia/ext/platform_canvas_linux.cc
@@ -53,6 +53,10 @@ bool PlatformCanvasLinux::initialize(int width, int height, bool is_opaque,
return true;
}
+cairo_surface_t* PlatformCanvasLinux::beginPlatformPaint() {
+ return getTopPlatformDevice().beginPlatformPaint();
+}
+
PlatformDeviceLinux& PlatformCanvasLinux::getTopPlatformDevice() const {
// All of our devices should be our special PlatformDevice.
SkCanvas::LayerIter iter(const_cast<PlatformCanvasLinux*>(this), false);
diff --git a/skia/ext/platform_canvas_linux.h b/skia/ext/platform_canvas_linux.h
index 1cf87a8..a1cd1ab 100644
--- a/skia/ext/platform_canvas_linux.h
+++ b/skia/ext/platform_canvas_linux.h
@@ -32,6 +32,13 @@ class PlatformCanvasLinux : public SkCanvas {
bool initialize(int width, int height, bool is_opaque);
bool initialize(int width, int height, bool is_opaque, uint8_t* data);
+ // These calls should surround calls to platform-specific drawing routines.
+ // The cairo_surface_t* returned by beginPlatformPaint represents the
+ // memory that can be used to draw into.
+ // endPlatformPaint is a no-op; it is used for symmetry with Windows.
+ cairo_surface_t* beginPlatformPaint();
+ void endPlatformPaint() {}
+
// Returns the platform device pointer of the topmost rect with a non-empty
// clip. Both the windows and mac versions have an equivalent of this method;
// a Linux version is added for compatibility.
diff --git a/skia/ext/platform_device_linux.h b/skia/ext/platform_device_linux.h
index 5c16c08..eae8965 100644
--- a/skia/ext/platform_device_linux.h
+++ b/skia/ext/platform_device_linux.h
@@ -7,6 +7,8 @@
#include "SkDevice.h"
+typedef struct _cairo_surface cairo_surface_t;
+
namespace skia {
// Blindly copying the mac hierarchy.
@@ -15,6 +17,8 @@ class PlatformDeviceLinux : public SkDevice {
// Returns if the preferred rendering engine is vectorial or bitmap based.
virtual bool IsVectorial() = 0;
+ virtual cairo_surface_t* beginPlatformPaint() = 0;
+
protected:
// Forwards |bitmap| to SkDevice's constructor.
PlatformDeviceLinux(const SkBitmap& bitmap);
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc
index b5acda2..2ecb48f 100644
--- a/webkit/glue/plugins/plugin_host.cc
+++ b/webkit/glue/plugins/plugin_host.cc
@@ -777,14 +777,7 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void *value) {
case NPNVSupportsWindowless:
{
NPBool* supports_windowless = reinterpret_cast<NPBool*>(value);
-#if defined(OS_LINUX)
- // TODO(deanm): Remove me once windowless plugins work on Linux. Right now
- // it's better to tell the plugin we don't support windowless, then have it
- // try and fail.
- *supports_windowless = FALSE;
-#else
*supports_windowless = TRUE;
-#endif
rv = NPERR_NO_ERROR;
break;
}
diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc
index 9d28592..6738435 100644
--- a/webkit/glue/plugins/plugin_instance.cc
+++ b/webkit/glue/plugins/plugin_instance.cc
@@ -4,6 +4,11 @@
#include "config.h"
+#include "build/build_config.h"
+#if defined(OS_LINUX)
+#define MOZ_X11 1
+#endif
+
#include "webkit/glue/plugins/plugin_instance.h"
#include "base/file_util.h"
@@ -130,6 +135,12 @@ bool PluginInstance::HandleEvent(UINT message, WPARAM wParam, LPARAM lParam) {
windowEvent.wParam = static_cast<uint32>(wParam);
return NPP_HandleEvent(&windowEvent) != 0;
}
+#elif defined(OS_LINUX)
+bool PluginInstance::HandleEvent(XEvent* event) {
+ if (!windowless_)
+ return false;
+ return NPP_HandleEvent(event);
+}
#endif
bool PluginInstance::Start(const GURL& url,
diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h
index 7e3ecd0..e973717 100644
--- a/webkit/glue/plugins/plugin_instance.h
+++ b/webkit/glue/plugins/plugin_instance.h
@@ -99,6 +99,8 @@ class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> {
// Handles a windows native message which this PluginInstance should deal
// with. Returns true if the event is handled, false otherwise.
bool HandleEvent(UINT message, WPARAM wParam, LPARAM lParam);
+#elif defined(OS_LINUX)
+ bool HandleEvent(union _XEvent* event);
#endif
// Creates a stream for sending an URL. If notify_needed
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
index 27e17cf..c45b8f3 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl.h
+++ b/webkit/glue/plugins/webplugin_delegate_impl.h
@@ -19,6 +19,10 @@
#include "webkit/glue/webplugin_delegate.h"
#include "webkit/glue/webcursor.h"
+#if defined(OS_LINUX)
+typedef struct _GdkDrawable GdkPixmap;
+#endif
+
namespace NPAPI {
class PluginInstance;
};
@@ -177,6 +181,14 @@ class WebPluginDelegateImpl : public WebPluginDelegate {
bool is_calling_wndproc;
#endif // OS_WIN
+#if defined(OS_LINUX)
+ // The pixmap we're drawing into, for a windowless plugin.
+ GdkPixmap* pixmap_;
+
+ // Ensure pixmap_ exists and is at least width by height pixels.
+ void EnsurePixmapAtLeastSize(int width, int height);
+#endif
+
gfx::NativeView parent_;
NPWindow window_;
#if defined(OS_MACOSX)
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
index 2e20581..c77b61b 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
+++ b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
@@ -64,6 +64,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
windowless_(false),
plugin_(NULL),
instance_(instance),
+ pixmap_(NULL),
parent_(containing_view),
quirks_(0)
{
@@ -76,6 +77,17 @@ WebPluginDelegateImpl::~WebPluginDelegateImpl() {
if (!windowless_)
WindowedDestroyWindow();
+
+ if (window_.ws_info) {
+ // We only ever use ws_info as an NPSetWindowCallbackStruct.
+ delete static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
+ }
+
+ if (pixmap_) {
+ g_object_unref(gdk_drawable_get_colormap(pixmap_));
+ g_object_unref(pixmap_);
+ pixmap_ = NULL;
+ }
}
void WebPluginDelegateImpl::PluginDestroyed() {
@@ -108,8 +120,6 @@ bool WebPluginDelegateImpl::Initialize(const GURL& url,
// a valid window handle causes subtle bugs with plugins which retreive
// the window handle and validate the same. The window handle can be
// retreived via NPN_GetValue of NPNVnetscapeWindow.
- NOTIMPLEMENTED() << "windowless not implemented";
- return false;
// instance_->set_window_handle(parent_);
// CreateDummyWindowForActivation();
// handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -159,14 +169,14 @@ void WebPluginDelegateImpl::UpdateGeometry(
}
}
-void WebPluginDelegateImpl::Paint(void* dc, const gfx::Rect& rect) {
+void WebPluginDelegateImpl::Paint(cairo_surface_t* context,
+ const gfx::Rect& rect) {
if (windowless_) {
- // TODO(port): windowless painting.
- // WindowlessPaint(dc, rect);
+ WindowlessPaint(context, rect);
}
}
-void WebPluginDelegateImpl::Print(void* dc) {
+void WebPluginDelegateImpl::Print(cairo_surface_t* context) {
NOTIMPLEMENTED();
}
@@ -321,13 +331,15 @@ bool WebPluginDelegateImpl::WindowedCreatePlugin() {
window_.window = GINT_TO_POINTER(
gtk_socket_get_id(GTK_SOCKET(windowed_handle_)));
- NPSetWindowCallbackStruct* extra = new NPSetWindowCallbackStruct;
+ if (!window_.ws_info)
+ window_.ws_info = new NPSetWindowCallbackStruct;
+ NPSetWindowCallbackStruct* extra =
+ static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
extra->display = GDK_WINDOW_XDISPLAY(windowed_handle_->window);
GdkVisual* visual = gdk_drawable_get_visual(windowed_handle_->window);
extra->visual = GDK_VISUAL_XVISUAL(visual);
extra->depth = visual->depth;
extra->colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(windowed_handle_->window));
- window_.ws_info = extra;
return true;
}
@@ -411,7 +423,7 @@ void WebPluginDelegateImpl::WindowlessUpdateGeometry(
// Only resend to the instance if the geometry has changed.
if (window_rect == window_rect_ && clip_rect == clip_rect_)
return;
- /*
+
// Set this flag before entering the instance in case of side-effects.
windowless_needs_set_window_ = true;
@@ -423,40 +435,45 @@ void WebPluginDelegateImpl::WindowlessUpdateGeometry(
window_rect_ = window_rect;
WindowlessSetWindow(true);
+ }
+}
- WINDOWPOS win_pos = {0};
- win_pos.x = window_rect_.x();
- win_pos.y = window_rect_.y();
- win_pos.cx = window_rect_.width();
- win_pos.cy = window_rect_.height();
-
- NPEvent pos_changed_event;
- pos_changed_event.event = WM_WINDOWPOSCHANGED;
- pos_changed_event.wParam = 0;
- pos_changed_event.lParam = PtrToUlong(&win_pos);
+void WebPluginDelegateImpl::EnsurePixmapAtLeastSize(int width, int height) {
+ if (pixmap_) {
+ gint cur_width, cur_height;
+ gdk_drawable_get_size(pixmap_, &cur_width, &cur_height);
+ if (cur_width >= width && cur_height >= height)
+ return; // We are already the appropriate size.
- instance()->NPP_HandleEvent(&pos_changed_event);
+ // Otherwise, we need to recreate ourselves.
+ g_object_unref(gdk_drawable_get_colormap(pixmap_));
+ g_object_unref(pixmap_);
+ pixmap_ = NULL;
}
- */
+
+ // |sys_visual| is owned by gdk; we shouldn't free it.
+ GdkVisual* sys_visual = gdk_visual_get_system();
+ pixmap_ = gdk_pixmap_new(NULL, // use width/height/depth params
+ width, height, sys_visual->depth);
+ GdkColormap* colormap = gdk_colormap_new(gdk_visual_get_system(),
+ FALSE);
+ gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap_), colormap);
}
-#if 0
-void WebPluginDelegateImpl::WindowlessPaint(HDC hdc,
+void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
const gfx::Rect& damage_rect) {
- DCHECK(hdc);
+ // Compare to:
+ // http://mxr.mozilla.org/firefox/source/layout/generic/nsObjectFrame.cpp:
+ // nsPluginInstanceOwner::Renderer::NativeDraw().
- RECT damage_rect_win;
- damage_rect_win.left = damage_rect.x(); // + window_rect_.x();
- damage_rect_win.top = damage_rect.y(); // + window_rect_.y();
- damage_rect_win.right = damage_rect_win.left + damage_rect.width();
- damage_rect_win.bottom = damage_rect_win.top + damage_rect.height();
+ DCHECK(context);
- // We need to pass the HDC to the plugin via NPP_SetWindow in the
+ // We need to pass the DC to the plugin via NPP_SetWindow in the
// first paint to ensure that it initiates rect invalidations.
- if (window_.window == NULL)
+ // TODO(evanm): for now, it appears we always need to do this.
+ if (true)
windowless_needs_set_window_ = true;
- window_.window = hdc;
// TODO(darin): we should avoid calling NPP_SetWindow here since it may
// cause page layout to be invalidated.
@@ -465,16 +482,37 @@ void WebPluginDelegateImpl::WindowlessPaint(HDC hdc,
if (windowless_needs_set_window_)
WindowlessSetWindow(false);
- NPEvent paint_event;
- paint_event.event = WM_PAINT;
- // NOTE: NPAPI is not 64bit safe. It puts pointers into 32bit values.
- paint_event.wParam = PtrToUlong(hdc);
- paint_event.lParam = PtrToUlong(&damage_rect_win);
+ EnsurePixmapAtLeastSize(damage_rect.width(), damage_rect.height());
+
+ // Copy the current image into the pixmap, so the plugin can draw over
+ // this background.
+ cairo_t* cairo = gdk_cairo_create(pixmap_);
+ cairo_set_source_surface(cairo, context, 0, 0);
+ cairo_paint(cairo);
+ cairo_destroy(cairo);
+
+ // Construct the paint message, targeting the pixmap.
+ XGraphicsExposeEvent event = {0};
+ event.type = GraphicsExpose;
+ event.display = GDK_DISPLAY();
+ event.drawable = GDK_PIXMAP_XID(pixmap_);
+ event.x = damage_rect.x();
+ event.y = damage_rect.y();
+ event.width = damage_rect.width();
+ event.height = damage_rect.height();
+
+ // Tell the plugin to paint into the pixmap.
static StatsRate plugin_paint("Plugin.Paint");
StatsScope<StatsRate> scope(plugin_paint);
- instance()->NPP_HandleEvent(&paint_event);
+ NPError err = instance()->NPP_HandleEvent(reinterpret_cast<XEvent*>(&event));
+ DCHECK_EQ(err, NPERR_NO_ERROR);
+
+ // Now copy the rendered image pixmap back into the drawing buffer.
+ cairo = cairo_create(context);
+ gdk_cairo_set_source_pixmap(cairo, pixmap_, 0, 0);
+ cairo_paint(cairo);
+ cairo_destroy(cairo);
}
-#endif
void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
if (!instance())
@@ -484,6 +522,9 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
return;
DCHECK(instance()->windowless());
+ // Mozilla docs say that this window param is not used for windowless
+ // plugins; rather, the window is passed during the GraphicsExpose event.
+ DCHECK(window_.window == 0);
window_.clipRect.top = clip_rect_.y();
window_.clipRect.left = clip_rect_.x();
@@ -495,6 +536,20 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
window_.y = window_rect_.y();
window_.type = NPWindowTypeDrawable;
+ if (!window_.ws_info)
+ window_.ws_info = new NPSetWindowCallbackStruct;
+ NPSetWindowCallbackStruct* extra =
+ static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
+ extra->display = GDK_DISPLAY();
+ GdkVisual* visual = gdk_visual_get_system();
+ extra->visual = GDK_VISUAL_XVISUAL(visual);
+ extra->depth = visual->depth;
+ GdkColormap* colormap = gdk_colormap_new(gdk_visual_get_system(), FALSE);
+ extra->colormap = GDK_COLORMAP_XCOLORMAP(colormap);
+
+ if (!force_set_window)
+ windowless_needs_set_window_ = false;
+
NPError err = instance()->NPP_SetWindow(&window_);
DCHECK(err == NPERR_NO_ERROR);
}
diff --git a/webkit/glue/webplugin_impl.cc b/webkit/glue/webplugin_impl.cc
index 09b6974..5027d5a 100644
--- a/webkit/glue/webplugin_impl.cc
+++ b/webkit/glue/webplugin_impl.cc
@@ -718,15 +718,12 @@ void WebPluginImpl::paint(WebCore::GraphicsContext* gc,
gc->translate(static_cast<float>(origin.x()),
static_cast<float>(origin.y()));
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_LINUX)
// Note that |context| is only used when in windowless mode.
gfx::NativeDrawingContext context =
gc->platformContext()->canvas()->beginPlatformPaint();
-#elif defined (OS_MACOSX)
+#elif defined(OS_MACOSX)
gfx::NativeDrawingContext context = gc->platformContext();
-#else
- // TODO(port): the equivalent of the above.
- void* context = NULL; // Temporary, to reduce ifdefs.
#endif
WebCore::IntRect window_rect =
@@ -735,7 +732,7 @@ void WebPluginImpl::paint(WebCore::GraphicsContext* gc,
delegate_->Paint(context, webkit_glue::FromIntRect(window_rect));
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_LINUX)
gc->platformContext()->canvas()->endPlatformPaint();
#endif
gc->restore();