summaryrefslogtreecommitdiffstats
path: root/content/plugin/webplugin_proxy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/plugin/webplugin_proxy.cc')
-rw-r--r--content/plugin/webplugin_proxy.cc340
1 files changed, 206 insertions, 134 deletions
diff --git a/content/plugin/webplugin_proxy.cc b/content/plugin/webplugin_proxy.cc
index 84d6d0d..a54f73a 100644
--- a/content/plugin/webplugin_proxy.cc
+++ b/content/plugin/webplugin_proxy.cc
@@ -60,33 +60,37 @@ WebPluginProxy::WebPluginProxy(
containing_window_(containing_window),
page_url_(page_url),
transparent_(false),
+ windowless_buffer_index_(0),
host_render_view_routing_id_(host_render_view_routing_id),
ALLOW_THIS_IN_INITIALIZER_LIST(runnable_method_factory_(this)) {
#if defined(USE_X11)
- windowless_shm_pixmap_ = None;
- use_shm_pixmap_ = false;
-
- // If the X server supports SHM pixmaps
- // and the color depth and masks match,
- // then consider using SHM pixmaps for windowless plugin painting.
- Display* display = ui::GetXDisplay();
- if (ui::QuerySharedMemorySupport(display) == ui::SHARED_MEMORY_PIXMAP &&
- ui::BitsPerPixelForPixmapDepth(
- display, DefaultDepth(display, 0)) == 32) {
- Visual* vis = DefaultVisual(display, 0);
-
- if (vis->red_mask == 0xff0000 &&
- vis->green_mask == 0xff00 &&
- vis->blue_mask == 0xff)
- use_shm_pixmap_ = true;
- }
+ windowless_shm_pixmaps_[0] = None;
+ windowless_shm_pixmaps_[1] = None;
+ use_shm_pixmap_ = false;
+
+ // If the X server supports SHM pixmaps
+ // and the color depth and masks match,
+ // then consider using SHM pixmaps for windowless plugin painting.
+ Display* display = ui::GetXDisplay();
+ if (ui::QuerySharedMemorySupport(display) == ui::SHARED_MEMORY_PIXMAP &&
+ ui::BitsPerPixelForPixmapDepth(
+ display, DefaultDepth(display, 0)) == 32) {
+ Visual* vis = DefaultVisual(display, 0);
+
+ if (vis->red_mask == 0xff0000 &&
+ vis->green_mask == 0xff00 &&
+ vis->blue_mask == 0xff)
+ use_shm_pixmap_ = true;
+ }
#endif
}
WebPluginProxy::~WebPluginProxy() {
#if defined(USE_X11)
- if (windowless_shm_pixmap_ != None)
- XFreePixmap(ui::GetXDisplay(), windowless_shm_pixmap_);
+ if (windowless_shm_pixmaps_[0] != None)
+ XFreePixmap(ui::GetXDisplay(), windowless_shm_pixmaps_[0]);
+ if (windowless_shm_pixmaps_[1] != None)
+ XFreePixmap(ui::GetXDisplay(), windowless_shm_pixmaps_[1]);
#endif
#if defined(OS_MACOSX)
@@ -159,7 +163,7 @@ void WebPluginProxy::InvalidateRect(const gfx::Rect& rect) {
#if defined(OS_MACOSX)
// If this is a Core Animation plugin, all we need to do is inform the
// delegate.
- if (!windowless_context_.get()) {
+ if (!windowless_context()) {
delegate_->PluginDidInvalidate();
return;
}
@@ -328,10 +332,10 @@ void WebPluginProxy::HandleURLRequest(const char* url,
void WebPluginProxy::Paint(const gfx::Rect& rect) {
#if defined(OS_MACOSX)
- if (!windowless_context_.get())
+ if (!windowless_context())
return;
#else
- if (!windowless_canvas_.get())
+ if (!windowless_canvas())
return;
#endif
@@ -340,13 +344,17 @@ void WebPluginProxy::Paint(const gfx::Rect& rect) {
gfx::Rect offset_rect = rect;
offset_rect.Offset(delegate_->GetRect().origin());
#if defined(OS_MACOSX)
- CGContextSaveGState(windowless_context_);
- // It is possible for windowless_context_ to change during plugin painting
+ CGContextSaveGState(windowless_context());
+ // It is possible for windowless_contexts_ to change during plugin painting
// (since the plugin can make a synchronous call during paint event handling),
- // in which case we don't want to try to restore it later. Not an owning ref
+ // in which case we don't want to try to restore later. Not an owning ref
// since owning the ref without owning the shared backing memory doesn't make
// sense, so this should only be used for pointer comparisons.
- CGContextRef saved_context_weak = windowless_context_.get();
+ CGContextRef saved_context_weak = windowless_context();
+ // We also save the buffer index for the comparison because if we flip buffers
+ // but haven't reallocated them then we do need to restore the context because
+ // it is going to continue to be used.
+ int saved_index = windowless_buffer_index_;
if (background_context_.get()) {
base::mac::ScopedCFTypeRef<CGImageRef> image(
@@ -356,69 +364,66 @@ void WebPluginProxy::Paint(const gfx::Rect& rect) {
source_rect.origin.y = CGImageGetHeight(image) - rect.y() - rect.height();
base::mac::ScopedCFTypeRef<CGImageRef> sub_image(
CGImageCreateWithImageInRect(image, source_rect));
- CGContextDrawImage(windowless_context_, rect.ToCGRect(), sub_image);
+ CGContextDrawImage(windowless_context(), rect.ToCGRect(), sub_image);
} else if (transparent_) {
- CGContextClearRect(windowless_context_, rect.ToCGRect());
+ CGContextClearRect(windowless_context(), rect.ToCGRect());
}
- CGContextClipToRect(windowless_context_, rect.ToCGRect());
+ CGContextClipToRect(windowless_context(), rect.ToCGRect());
// TODO(caryclark): This is a temporary workaround to allow the Darwin / Skia
// port to share code with the Darwin / CG port. All ports will eventually use
// the common code below.
- delegate_->CGPaint(windowless_context_, rect);
- if (windowless_context_.get() == saved_context_weak)
- CGContextRestoreGState(windowless_context_);
+ delegate_->CGPaint(windowless_context(), rect);
+ if (windowless_contexts_[saved_index].get() == saved_context_weak)
+ CGContextRestoreGState(windowless_contexts_[saved_index]);
#else
- windowless_canvas_->save();
+ windowless_canvas()->save();
// The given clip rect is relative to the plugin coordinate system.
SkRect sk_rect = { SkIntToScalar(rect.x()),
SkIntToScalar(rect.y()),
SkIntToScalar(rect.right()),
SkIntToScalar(rect.bottom()) };
- windowless_canvas_->clipRect(sk_rect);
+ windowless_canvas()->clipRect(sk_rect);
// Setup the background.
if (background_canvas_.get()) {
// When a background canvas is given, we're in transparent mode. This means
// the plugin wants to have the image of the page in the canvas it's drawing
- // into (which is windowless_canvas_) so it can do blending. So we copy the
- // background bitmap into the windowless_canvas_.
+ // into (which is windowless_canvases_) so it can do blending. So we copy
+ // the background bitmap into the windowless canvas.
const SkBitmap& background_bitmap =
skia::GetTopDevice(*background_canvas_)->accessBitmap(false);
- windowless_canvas_->drawBitmap(background_bitmap, 0, 0);
+ windowless_canvas()->drawBitmap(background_bitmap, 0, 0);
} else {
// In non-transparent mode, the plugin doesn't care what's underneath, so we
// can just give it black.
SkPaint black_fill_paint;
black_fill_paint.setARGB(0xFF, 0x00, 0x00, 0x00);
- windowless_canvas_->drawPaint(black_fill_paint);
+ windowless_canvas()->drawPaint(black_fill_paint);
}
- // Bring the windowless_canvas_ into the window coordinate system, which is
+ // Bring the windowless canvas into the window coordinate system, which is
// how the plugin expects to draw (since the windowless API was originally
// designed just for scribbling over the web page).
- windowless_canvas_->translate(SkIntToScalar(-delegate_->GetRect().x()),
- SkIntToScalar(-delegate_->GetRect().y()));
+ windowless_canvas()->translate(SkIntToScalar(-delegate_->GetRect().x()),
+ SkIntToScalar(-delegate_->GetRect().y()));
// Before we send the invalidate, paint so that renderer uses the updated
// bitmap.
- delegate_->Paint(windowless_canvas_.get(), offset_rect);
+ delegate_->Paint(windowless_canvas(), offset_rect);
- windowless_canvas_->restore();
+ windowless_canvas()->restore();
#endif
}
void WebPluginProxy::UpdateGeometry(
const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
- const TransportDIB::Handle& windowless_buffer,
+ const TransportDIB::Handle& windowless_buffer0,
+ const TransportDIB::Handle& windowless_buffer1,
+ int windowless_buffer_index,
const TransportDIB::Handle& background_buffer,
- bool transparent
-#if defined(OS_MACOSX)
- ,
- int ack_key
-#endif
- ) {
+ bool transparent) {
gfx::Rect old = delegate_->GetRect();
gfx::Rect old_clip_rect = delegate_->GetClipRect();
transparent_ = transparent;
@@ -426,14 +431,23 @@ void WebPluginProxy::UpdateGeometry(
// Update the buffers before doing anything that could call into plugin code,
// so that we don't process buffer changes out of order if plugins make
// synchronous calls that lead to nested UpdateGeometry calls.
- if (TransportDIB::is_valid_handle(windowless_buffer)) {
- // The plugin's rect changed, so now we have a new buffer to draw into.
- SetWindowlessBuffer(windowless_buffer, background_buffer, window_rect);
+ if (TransportDIB::is_valid_handle(windowless_buffer0)) {
+ // The plugin's rect changed, so now we have new buffers to draw into.
+ SetWindowlessBuffers(windowless_buffer0,
+ windowless_buffer1,
+ background_buffer,
+ window_rect);
}
+ DCHECK(0 <= windowless_buffer_index && windowless_buffer_index <= 1);
+ windowless_buffer_index_ = windowless_buffer_index;
+#if defined(USE_X11)
+ delegate_->SetWindowlessShmPixmap(windowless_shm_pixmap());
+#endif
+
#if defined(OS_MACOSX)
- delegate_->UpdateGeometryAndContext(window_rect, clip_rect,
- windowless_context_);
+ delegate_->UpdateGeometryAndContext(
+ window_rect, clip_rect, windowless_context());
#else
delegate_->UpdateGeometry(window_rect, clip_rect);
#endif
@@ -444,45 +458,58 @@ void WebPluginProxy::UpdateGeometry(
!damaged_rect_.IsEmpty()) {
InvalidateRect(damaged_rect_);
}
-
-#if defined(OS_MACOSX)
- // The renderer is expecting an ACK message if ack_key is not -1.
- if (ack_key != -1) {
- Send(new PluginHostMsg_UpdateGeometry_ACK(route_id_, ack_key));
- }
-#endif
}
#if defined(OS_WIN)
-void WebPluginProxy::SetWindowlessBuffer(
- const TransportDIB::Handle& windowless_buffer,
- const TransportDIB::Handle& background_buffer,
- const gfx::Rect& window_rect) {
+
+void WebPluginProxy::CreateCanvasFromHandle(
+ const TransportDIB::Handle& dib_handle,
+ const gfx::Rect& window_rect,
+ scoped_ptr<skia::PlatformCanvas>* canvas_out) {
// Create a canvas that will reference the shared bits. We have to handle
// errors here since we're mapping a large amount of memory that may not fit
// in our address space, or go wrong in some other way.
- windowless_canvas_.reset(new skia::PlatformCanvas);
- if (!windowless_canvas_->initialize(
+ scoped_ptr<skia::PlatformCanvas> canvas(new skia::PlatformCanvas);
+ if (!canvas->initialize(
window_rect.width(),
window_rect.height(),
true,
- chrome::GetSectionFromProcess(windowless_buffer,
+ chrome::GetSectionFromProcess(dib_handle,
channel_->renderer_handle(), false))) {
- windowless_canvas_.reset();
+ canvas.reset();
+ }
+ canvas_out->reset(canvas.release());
+}
+
+void WebPluginProxy::SetWindowlessBuffers(
+ const TransportDIB::Handle& windowless_buffer0,
+ const TransportDIB::Handle& windowless_buffer1,
+ const TransportDIB::Handle& background_buffer,
+ const gfx::Rect& window_rect) {
+ CreateCanvasFromHandle(windowless_buffer0,
+ window_rect,
+ &windowless_canvases_[0]);
+ if (!windowless_canvases_[0].get()) {
+ windowless_canvases_[1].reset();
+ background_canvas_.reset();
+ return;
+ }
+ CreateCanvasFromHandle(windowless_buffer1,
+ window_rect,
+ &windowless_canvases_[1]);
+ if (!windowless_canvases_[1].get()) {
+ windowless_canvases_[0].reset();
background_canvas_.reset();
return;
}
if (background_buffer) {
- background_canvas_.reset(new skia::PlatformCanvas);
- if (!background_canvas_->initialize(
- window_rect.width(),
- window_rect.height(),
- true,
- chrome::GetSectionFromProcess(background_buffer,
- channel_->renderer_handle(), false))) {
- windowless_canvas_.reset();
- background_canvas_.reset();
+ CreateCanvasFromHandle(background_buffer,
+ window_rect,
+ &background_canvas_);
+ if (!background_canvas_.get()) {
+ windowless_canvases_[0].reset();
+ windowless_canvases_[1].reset();
return;
}
}
@@ -490,79 +517,116 @@ void WebPluginProxy::SetWindowlessBuffer(
#elif defined(OS_MACOSX)
-void WebPluginProxy::SetWindowlessBuffer(
- const TransportDIB::Handle& windowless_buffer,
- const TransportDIB::Handle& background_buffer,
- const gfx::Rect& window_rect) {
+void WebPluginProxy::CreateDIBAndCGContextFromHandle(
+ const TransportDIB::Handle& dib_handle,
+ const gfx::Rect& window_rect,
+ scoped_ptr<TransportDIB>* dib_out,
+ base::mac::ScopedCFTypeRef<CGContextRef>* cg_context_out) {
// Convert the shared memory handle to a handle that works in our process,
// and then use that to create a CGContextRef.
- windowless_dib_.reset(TransportDIB::Map(windowless_buffer));
- background_dib_.reset(TransportDIB::Map(background_buffer));
- windowless_context_.reset(CGBitmapContextCreate(
- windowless_dib_->memory(),
- window_rect.width(),
- window_rect.height(),
- 8, 4 * window_rect.width(),
- base::mac::GetSystemColorSpace(),
- kCGImageAlphaPremultipliedFirst |
- kCGBitmapByteOrder32Host));
- CGContextTranslateCTM(windowless_context_, 0, window_rect.height());
- CGContextScaleCTM(windowless_context_, 1, -1);
- if (background_dib_.get()) {
- background_context_.reset(CGBitmapContextCreate(
- background_dib_->memory(),
+ TransportDIB* dib = TransportDIB::Map(dib_handle);
+ CGContextRef cg_context = NULL;
+ if (dib) {
+ cg_context = CGBitmapContextCreate(
+ dib->memory(),
window_rect.width(),
window_rect.height(),
- 8, 4 * window_rect.width(),
+ 8,
+ 4 * window_rect.width(),
base::mac::GetSystemColorSpace(),
- kCGImageAlphaPremultipliedFirst |
- kCGBitmapByteOrder32Host));
- CGContextTranslateCTM(background_context_, 0, window_rect.height());
- CGContextScaleCTM(background_context_, 1, -1);
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
+ CGContextTranslateCTM(cg_context, 0, window_rect.height());
+ CGContextScaleCTM(cg_context, 1, -1);
}
+ dib_out->reset(dib);
+ cg_context_out->reset(cg_context);
}
-#elif defined(USE_X11)
-
-void WebPluginProxy::SetWindowlessBuffer(
- const TransportDIB::Handle& windowless_buffer,
+void WebPluginProxy::SetWindowlessBuffers(
+ const TransportDIB::Handle& windowless_buffer0,
+ const TransportDIB::Handle& windowless_buffer1,
const TransportDIB::Handle& background_buffer,
const gfx::Rect& window_rect) {
- int width = window_rect.width();
- int height = window_rect.height();
- windowless_dib_.reset(TransportDIB::Map(windowless_buffer));
- if (windowless_dib_.get()) {
- windowless_canvas_.reset(windowless_dib_->GetPlatformCanvas(width, height));
- } else {
- // This can happen if the renderer has already destroyed the TransportDIB
- // by the time we receive the handle, e.g. in case of multiple resizes.
- windowless_canvas_.reset();
- }
- background_dib_.reset(TransportDIB::Map(background_buffer));
- if (background_dib_.get()) {
- background_canvas_.reset(background_dib_->GetPlatformCanvas(width, height));
- } else {
- background_canvas_.reset();
+ CreateDIBAndCGContextFromHandle(windowless_buffer0,
+ window_rect,
+ &windowless_dibs_[0],
+ &windowless_contexts_[0]);
+ CreateDIBAndCGContextFromHandle(windowless_buffer1,
+ window_rect,
+ &windowless_dibs_[1],
+ &windowless_contexts_[1]);
+ CreateDIBAndCGContextFromHandle(background_buffer,
+ window_rect,
+ &background_dib_,
+ &background_context_);
+}
+
+#elif defined(USE_X11)
+
+void WebPluginProxy::CreateDIBAndCanvasFromHandle(
+ const TransportDIB::Handle& dib_handle,
+ const gfx::Rect& window_rect,
+ scoped_ptr<TransportDIB>* dib_out,
+ scoped_ptr<skia::PlatformCanvas>* canvas_out) {
+ TransportDIB* dib = TransportDIB::Map(dib_handle);
+ skia::PlatformCanvas* canvas = NULL;
+ // dib may be NULL if the renderer has already destroyed the TransportDIB by
+ // the time we receive the handle, e.g. in case of multiple resizes.
+ if (dib) {
+ canvas = dib->GetPlatformCanvas(window_rect.width(), window_rect.height());
}
+ dib_out->reset(dib);
+ canvas_out->reset(canvas);
+}
- // If SHM pixmaps support is available, create a SHM pixmap and
- // pass it to the delegate for windowless plugin painting.
- if (delegate_->IsWindowless() && use_shm_pixmap_ && windowless_dib_.get()) {
+void WebPluginProxy::CreateShmPixmapFromDIB(
+ TransportDIB* dib,
+ const gfx::Rect& window_rect,
+ XID* pixmap_out) {
+ if (dib) {
Display* display = ui::GetXDisplay();
XID root_window = ui::GetX11RootWindow();
XShmSegmentInfo shminfo = {0};
- if (windowless_shm_pixmap_ != None)
- XFreePixmap(display, windowless_shm_pixmap_);
+ if (*pixmap_out != None)
+ XFreePixmap(display, *pixmap_out);
- shminfo.shmseg = windowless_dib_->MapToX(display);
+ shminfo.shmseg = dib->MapToX(display);
// Create a shared memory pixmap based on the image buffer.
- windowless_shm_pixmap_ = XShmCreatePixmap(display, root_window,
- NULL, &shminfo,
- width, height,
- DefaultDepth(display, 0));
+ *pixmap_out = XShmCreatePixmap(display, root_window,
+ NULL, &shminfo,
+ window_rect.width(), window_rect.height(),
+ DefaultDepth(display, 0));
+ }
+}
- delegate_->SetWindowlessShmPixmap(windowless_shm_pixmap_);
+void WebPluginProxy::SetWindowlessBuffers(
+ const TransportDIB::Handle& windowless_buffer0,
+ const TransportDIB::Handle& windowless_buffer1,
+ const TransportDIB::Handle& background_buffer,
+ const gfx::Rect& window_rect) {
+ CreateDIBAndCanvasFromHandle(windowless_buffer0,
+ window_rect,
+ &windowless_dibs_[0],
+ &windowless_canvases_[0]);
+ CreateDIBAndCanvasFromHandle(windowless_buffer1,
+ window_rect,
+ &windowless_dibs_[1],
+ &windowless_canvases_[1]);
+ CreateDIBAndCanvasFromHandle(background_buffer,
+ window_rect,
+ &background_dib_,
+ &background_canvas_);
+
+ // If SHM pixmaps support is available, create SHM pixmaps to pass to the
+ // delegate for windowless plugin painting.
+ if (delegate_->IsWindowless() && use_shm_pixmap_) {
+ CreateShmPixmapFromDIB(windowless_dibs_[0].get(),
+ window_rect,
+ &windowless_shm_pixmaps_[0]);
+ CreateShmPixmapFromDIB(windowless_dibs_[1].get(),
+ window_rect,
+ &windowless_shm_pixmaps_[1]);
}
}
@@ -644,7 +708,15 @@ void WebPluginProxy::OnPaint(const gfx::Rect& damaged_rect) {
content::GetContentClient()->SetActiveURL(page_url_);
Paint(damaged_rect);
- Send(new PluginHostMsg_InvalidateRect(route_id_, damaged_rect));
+ bool allow_buffer_flipping;
+#if defined(OS_MACOSX)
+ allow_buffer_flipping = delegate_->AllowBufferFlipping();
+#else
+ allow_buffer_flipping = true;
+#endif
+ Send(new PluginHostMsg_InvalidateRect(route_id_,
+ damaged_rect,
+ allow_buffer_flipping));
}
bool WebPluginProxy::IsOffTheRecord() {