summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-22 03:29:57 +0000
committerevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-22 03:29:57 +0000
commit597725dc3391c9728461a2f93e1420bc8d386923 (patch)
treef822b3fca46af93fac347ae053c0cc78724d4893
parenta2442489a87f1f64697558d3832b7b312e683f39 (diff)
downloadchromium_src-597725dc3391c9728461a2f93e1420bc8d386923.zip
chromium_src-597725dc3391c9728461a2f93e1420bc8d386923.tar.gz
chromium_src-597725dc3391c9728461a2f93e1420bc8d386923.tar.bz2
linux: add quirk for windowless flash drawing glitches
Review URL: http://codereview.chromium.org/115685 Patch from Antoine Labour <piman@google.com>. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16718 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_gtk.cc159
-rw-r--r--webkit/glue/webplugin_delegate.cc2
-rw-r--r--webkit/glue/webplugin_delegate.h25
3 files changed, 128 insertions, 58 deletions
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
index 45fe78c..9762ee2 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
+++ b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
@@ -67,6 +67,11 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
parent_(containing_view),
quirks_(0) {
memset(&window_, 0, sizeof(window_));
+ if (instance_->mime_type() == "application/x-shockwave-flash") {
+ // Flash is tied to Firefox's whacky behavior with windowless plugins. See
+ // comments in WindowlessPaint
+ quirks_ |= PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW;
+ }
}
WebPluginDelegateImpl::~WebPluginDelegateImpl() {
@@ -483,12 +488,6 @@ void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
DCHECK(context);
- // We need to pass the DC to the plugin via NPP_SetWindow in the
- // first paint to ensure that it initiates rect invalidations.
- // TODO(evanm): for now, it appears we always need to do this.
- if (true)
- windowless_needs_set_window_ = true;
-
// TODO(darin): we should avoid calling NPP_SetWindow here since it may
// cause page layout to be invalidated.
@@ -497,45 +496,119 @@ void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
if (windowless_needs_set_window_)
WindowlessSetWindow(false);
- // The actual dirty region is just the intersection of the plugin
- // window with the damage region. However, the plugin wants to draw
- // relative to the containing window's origin, so our pixmap must be
- // from the window's origin down to the bottom-right edge of the
- // dirty region.
+ // The actual dirty region is just the intersection of the plugin window and
+ // the clip window with the damage region. However, the plugin wants to draw
+ // relative to the containing window's origin, so our pixmap must be from the
+ // window's origin down to the bottom-right edge of the dirty region.
//
- // +-----------------------------+-----------------------------+
- // | | |
- // | pixmap +-------------+ |
- // | | damage | window |
- // | | | |
- // | +-------+-------------+----------+ |
- // | | | draw | | |
- // +-------+-------+-------------+ | |
- // | | | |
- // | | plugin | |
- // | +--------------------------------+ |
- // | |
- // | |
- // +-----------------------------------------------------------+
+ // Typical case:
+ // X-----------------------------------+-----------------------------+
+ // | | |
+ // | pixmap +-------------------+ |
+ // | | damage | window |
+ // | | | |
+ // | +---+-------------------+-------------+ |
+ // | | | | clip | |
+ // | +---+---+-------------------+----------+ | |
+ // | | | | | | | |
+ // | | | | draw | | | |
+ // | | | | | | | |
+ // +-------+---+---+-------------------+----------+--+ |
+ // | | | | | |
+ // | | +-------------------+ | |
+ // | | | |
+ // | | plugin | |
+ // | +--------------------------------------+ |
+ // | |
+ // | |
+ // +-----------------------------------------------------------------+
+ // X = origin
//
- // TOOD(evanm): on Windows, we instead just translate the origin of
- // the DC that we hand to the plugin. Does such a thing exist on X?
- // TODO(evanm): make use of the clip rect as well.
-
- gfx::Rect plugin_rect(window_.x, window_.y, window_.width, window_.height);
- gfx::Rect draw_rect = plugin_rect.Intersect(damage_rect);
+ // NPAPI doesn't properly define which coordinates each of
+ // - window.clipRect, window.x and window.y in the SetWindow call
+ // - x and y in GraphicsExpose HandleEvent call
+ // are relative to, nor does it define what the pixmap is relative to.
+ //
+ // Any sane values for them just don't work with the flash plugin. Firefox
+ // has some interesting behavior. Experiments showed that:
+ // - window.clipRect is always in the same space as window.x and window.y
+ // - in the first SetWindow call, or when scrolling, window.x and window.y are
+ // the coordinates of the plugin relative to the window.
+ // - whenever only a part of the plugin is drawn, Firefox issues a SetWindow
+ // call before each GraphicsExpose event, that sets the drawing origin to
+ // (0, 0) as if the plugin was scrolled to be partially out of the view. The
+ // GraphicsExpose event has coordinates relative to the "window" (assuming
+ // that virtual scroll). The pixmap is also relative to the window. It always
+ // sets the clip rect to the draw rect.
+ //
+ // Attempts to deviate from that makes Flash render at the wrong place in the
+ // pixmap, or render the wrong pixels.
+ //
+ // Flash plugin:
+ // X-----------------------------------------------------------------+
+ // | |
+ // | +-------------------+ "real" window |
+ // | | damage | |
+ // | | | |
+ // | +---+-------------------+-------------+ |
+ // | | | | "real" clip | |
+ // | +---+---O===================#==========#==#===============#
+ // | | | H draw | | | H
+ // | | | H = pixmap | | | H
+ // | | | H = "apparent" clip | | | H
+ // | + +---#-------------------+----------+--+ H
+ // | | H | | H
+ // | | H-------------------+ | H
+ // | | H | H
+ // | | H plugin | H
+ // | +-------#------------------------------+ H
+ // | H H
+ // | H "apparent" window H
+ // +---------------#=================================================#
+ // X = "real" origin
+ // O = "apparent" origin
+ // "real" means as seen by Chrome
+ // "apparent" means as seen by the plugin.
+
+ gfx::Rect draw_rect = window_rect_.Intersect(damage_rect);
+
+ // clip_rect_ is relative to the plugin
+ gfx::Rect clip_rect_window = clip_rect_;
+ clip_rect_window.Offset(window_rect_.x(), window_rect_.y());
+ draw_rect = draw_rect.Intersect(clip_rect_window);
+
+ // These offsets represent by how much the view is shifted to accomodate
+ // Flash (the coordinates of X relative to O in the diagram above).
+ int offset_x = 0;
+ int offset_y = 0;
+ if (quirks_ & PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW) {
+ offset_x = -draw_rect.x();
+ offset_y = -draw_rect.y();
+ window_.clipRect.top = 0;
+ window_.clipRect.left = 0;
+ window_.clipRect.bottom = draw_rect.height();
+ window_.clipRect.right = draw_rect.width();
+ window_.height = window_rect_.height();
+ window_.width = window_rect_.width();
+ window_.x = window_rect_.x() - draw_rect.x();
+ window_.y = window_rect_.y() - draw_rect.y();
+ window_.type = NPWindowTypeDrawable;
+ DCHECK(window_.ws_info);
+ NPError err = instance()->NPP_SetWindow(&window_);
+ DCHECK_EQ(err, NPERR_NO_ERROR);
+ }
gfx::Rect pixmap_rect(0, 0,
- draw_rect.x() + draw_rect.width(),
- draw_rect.y() + draw_rect.height());
+ draw_rect.x() + offset_x + draw_rect.width(),
+ draw_rect.y() + offset_y + draw_rect.height());
EnsurePixmapAtLeastSize(pixmap_rect.width(), pixmap_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_rectangle(cairo, draw_rect.x(), draw_rect.y(),
+ cairo_set_source_surface(cairo, context, offset_x, offset_y);
+ cairo_rectangle(cairo, draw_rect.x() + offset_x, draw_rect.y() + offset_y,
draw_rect.width(), draw_rect.height());
cairo_clip(cairo);
cairo_paint(cairo);
@@ -547,8 +620,8 @@ void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
event.type = GraphicsExpose;
event.display = GDK_DISPLAY();
event.drawable = GDK_PIXMAP_XID(pixmap_);
- event.x = draw_rect.x();
- event.y = draw_rect.y();
+ event.x = draw_rect.x() + offset_x;
+ event.y = draw_rect.y() + offset_y;
event.width = draw_rect.width();
event.height = draw_rect.height();
@@ -560,7 +633,7 @@ void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
// Now copy the rendered image pixmap back into the drawing buffer.
cairo = cairo_create(context);
- gdk_cairo_set_source_pixmap(cairo, pixmap_, 0, 0);
+ gdk_cairo_set_source_pixmap(cairo, pixmap_, -offset_x, -offset_y);
cairo_rectangle(cairo, draw_rect.x(), draw_rect.y(),
draw_rect.width(), draw_rect.height());
cairo_clip(cairo);
@@ -588,10 +661,12 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
// 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();
- window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
- window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
+ window_.clipRect.top = clip_rect_.y() + window_rect_.y();
+ window_.clipRect.left = clip_rect_.x() + window_rect_.x();
+ window_.clipRect.bottom =
+ clip_rect_.y() + clip_rect_.height() + window_rect_.y();
+ window_.clipRect.right =
+ clip_rect_.x() + clip_rect_.width() + window_rect_.x();
window_.height = window_rect_.height();
window_.width = window_rect_.width();
window_.x = window_rect_.x();
diff --git a/webkit/glue/webplugin_delegate.cc b/webkit/glue/webplugin_delegate.cc
index ea1f285..bc8f692 100644
--- a/webkit/glue/webplugin_delegate.cc
+++ b/webkit/glue/webplugin_delegate.cc
@@ -27,10 +27,8 @@ const gfx::Rect& WebPluginDelegate::GetClipRect() const {
return GetRect();
}
-#if defined(OS_WIN)
// Returns a combinaison of PluginQuirks.
int WebPluginDelegate::GetQuirks() const {
NOTREACHED();
return 0;
}
-#endif
diff --git a/webkit/glue/webplugin_delegate.h b/webkit/glue/webplugin_delegate.h
index 36f943b..3884c37 100644
--- a/webkit/glue/webplugin_delegate.h
+++ b/webkit/glue/webplugin_delegate.h
@@ -32,19 +32,18 @@ class Rect;
// This is the interface that a plugin implementation needs to provide.
class WebPluginDelegate {
public:
-#if defined(OS_WIN)
enum PluginQuirks {
- PLUGIN_QUIRK_SETWINDOW_TWICE = 1,
- PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE = 2,
- PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY = 4,
- PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY = 8,
- PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES = 16,
- PLUGIN_QUIRK_DIE_AFTER_UNLOAD = 32,
- PLUGIN_QUIRK_PATCH_TRACKPOPUP_MENU = 64,
- PLUGIN_QUIRK_PATCH_SETCURSOR = 128,
- PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS = 256,
+ PLUGIN_QUIRK_SETWINDOW_TWICE = 1, // Win32
+ PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE = 2, // Win32
+ PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY = 4, // Win32
+ PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY = 8, // Win32
+ PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES = 16, // Win32
+ PLUGIN_QUIRK_DIE_AFTER_UNLOAD = 32, // Win32
+ PLUGIN_QUIRK_PATCH_TRACKPOPUP_MENU = 64, // Win32
+ PLUGIN_QUIRK_PATCH_SETCURSOR = 128, // Win32
+ PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS = 256, // Win32
+ PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW = 512, // Linux
};
-#endif
WebPluginDelegate() {}
virtual ~WebPluginDelegate() {}
@@ -151,10 +150,8 @@ class WebPluginDelegate {
virtual const gfx::Rect& GetClipRect() const;
-#if defined(OS_WIN)
- // Returns a combinaison of PluginQuirks.
+ // Returns a combination of PluginQuirks.
virtual int GetQuirks() const;
-#endif
private:
DISALLOW_COPY_AND_ASSIGN(WebPluginDelegate);