diff options
author | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-13 22:18:58 +0000 |
---|---|---|
committer | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-13 22:18:58 +0000 |
commit | a2d489b22f9e3f361adeaf7a09ae88510a2bb1e3 (patch) | |
tree | ff3dd61a3278c60286a820e9f07952e4571743e5 | |
parent | 16ead307a2b27b7d02bae66792eaf3c2f904b9c0 (diff) | |
download | chromium_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.h | 5 | ||||
-rw-r--r-- | skia/ext/bitmap_platform_device_linux.h | 4 | ||||
-rw-r--r-- | skia/ext/platform_canvas_linux.cc | 4 | ||||
-rw-r--r-- | skia/ext/platform_canvas_linux.h | 7 | ||||
-rw-r--r-- | skia/ext/platform_device_linux.h | 4 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_host.cc | 7 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.cc | 11 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.h | 2 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 12 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_gtk.cc | 133 | ||||
-rw-r--r-- | webkit/glue/webplugin_impl.cc | 9 |
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(); |