| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/plugin/webplugin_proxy.h" | |
| 6 | |
| 7 #include "build/build_config.h" | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/lazy_instance.h" | |
| 11 #include "content/child/npapi/webplugin_delegate_impl.h" | |
| 12 #include "content/child/plugin_messages.h" | |
| 13 #include "content/plugin/plugin_channel.h" | |
| 14 #include "content/plugin/plugin_thread.h" | |
| 15 #include "content/public/common/content_client.h" | |
| 16 #include "skia/ext/platform_canvas.h" | |
| 17 #include "ui/gfx/canvas.h" | |
| 18 #include "url/url_constants.h" | |
| 19 | |
| 20 #if defined(OS_MACOSX) | |
| 21 #include "base/mac/mac_util.h" | |
| 22 #include "base/mac/scoped_cftyperef.h" | |
| 23 #include "content/plugin/webplugin_accelerated_surface_proxy_mac.h" | |
| 24 #endif | |
| 25 | |
| 26 #if defined(OS_WIN) | |
| 27 #include "content/common/plugin_process_messages.h" | |
| 28 #include "content/public/common/sandbox_init.h" | |
| 29 #endif | |
| 30 | |
| 31 namespace content { | |
| 32 | |
| 33 WebPluginProxy::SharedTransportDIB::SharedTransportDIB(TransportDIB* dib) | |
| 34 : dib_(dib) { | |
| 35 } | |
| 36 | |
| 37 WebPluginProxy::SharedTransportDIB::~SharedTransportDIB() { | |
| 38 } | |
| 39 | |
| 40 WebPluginProxy::WebPluginProxy( | |
| 41 PluginChannel* channel, | |
| 42 int route_id, | |
| 43 const GURL& page_url, | |
| 44 int host_render_view_routing_id) | |
| 45 : channel_(channel), | |
| 46 route_id_(route_id), | |
| 47 delegate_(NULL), | |
| 48 waiting_for_paint_(false), | |
| 49 page_url_(page_url), | |
| 50 windowless_buffer_index_(0), | |
| 51 host_render_view_routing_id_(host_render_view_routing_id), | |
| 52 weak_factory_(this) { | |
| 53 } | |
| 54 | |
| 55 WebPluginProxy::~WebPluginProxy() { | |
| 56 #if defined(OS_MACOSX) | |
| 57 // Destroy the surface early, since it may send messages during cleanup. | |
| 58 if (accelerated_surface_) | |
| 59 accelerated_surface_.reset(); | |
| 60 #endif | |
| 61 } | |
| 62 | |
| 63 bool WebPluginProxy::Send(IPC::Message* msg) { | |
| 64 return channel_->Send(msg); | |
| 65 } | |
| 66 | |
| 67 void WebPluginProxy::Invalidate() { | |
| 68 gfx::Rect rect(0, 0, | |
| 69 delegate_->GetRect().width(), | |
| 70 delegate_->GetRect().height()); | |
| 71 InvalidateRect(rect); | |
| 72 } | |
| 73 | |
| 74 void WebPluginProxy::InvalidateRect(const gfx::Rect& rect) { | |
| 75 #if defined(OS_MACOSX) | |
| 76 // If this is a Core Animation plugin, all we need to do is inform the | |
| 77 // delegate. | |
| 78 if (!windowless_context()) { | |
| 79 delegate_->PluginDidInvalidate(); | |
| 80 return; | |
| 81 } | |
| 82 | |
| 83 // Some plugins will send invalidates larger than their own rect when | |
| 84 // offscreen, so constrain invalidates to the plugin rect. | |
| 85 gfx::Rect plugin_rect = delegate_->GetRect(); | |
| 86 plugin_rect.set_origin(gfx::Point(0, 0)); | |
| 87 plugin_rect.Intersect(rect); | |
| 88 const gfx::Rect invalidate_rect(plugin_rect); | |
| 89 #else | |
| 90 const gfx::Rect invalidate_rect(rect); | |
| 91 #endif | |
| 92 damaged_rect_.Union(invalidate_rect); | |
| 93 // Ignore NPN_InvalidateRect calls with empty rects. Also don't send an | |
| 94 // invalidate if it's outside the clipping region, since if we did it won't | |
| 95 // lead to a paint and we'll be stuck waiting forever for a DidPaint response. | |
| 96 // | |
| 97 // TODO(piman): There is a race condition here, because this test assumes | |
| 98 // that when the paint actually occurs, the clip rect will not have changed. | |
| 99 // This is not true because scrolling (or window resize) could occur and be | |
| 100 // handled by the renderer before it receives the InvalidateRect message, | |
| 101 // changing the clip rect and then not painting. | |
| 102 if (damaged_rect_.IsEmpty() || | |
| 103 !delegate_->GetClipRect().Intersects(damaged_rect_)) | |
| 104 return; | |
| 105 | |
| 106 // Only send a single InvalidateRect message at a time. From DidPaint we | |
| 107 // will dispatch an additional InvalidateRect message if necessary. | |
| 108 if (!waiting_for_paint_) { | |
| 109 waiting_for_paint_ = true; | |
| 110 // Invalidates caused by calls to NPN_InvalidateRect/NPN_InvalidateRgn | |
| 111 // need to be painted asynchronously as per the NPAPI spec. | |
| 112 base::MessageLoop::current()->PostTask( | |
| 113 FROM_HERE, | |
| 114 base::Bind(&WebPluginProxy::OnPaint, | |
| 115 weak_factory_.GetWeakPtr(), | |
| 116 damaged_rect_)); | |
| 117 damaged_rect_ = gfx::Rect(); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 bool WebPluginProxy::FindProxyForUrl(const GURL& url, std::string* proxy_list) { | |
| 122 bool result = false; | |
| 123 Send(new PluginHostMsg_ResolveProxy(route_id_, url, &result, proxy_list)); | |
| 124 return result; | |
| 125 } | |
| 126 | |
| 127 void WebPluginProxy::SetCookie(const GURL& url, | |
| 128 const GURL& first_party_for_cookies, | |
| 129 const std::string& cookie) { | |
| 130 Send(new PluginHostMsg_SetCookie(route_id_, url, | |
| 131 first_party_for_cookies, cookie)); | |
| 132 } | |
| 133 | |
| 134 std::string WebPluginProxy::GetCookies(const GURL& url, | |
| 135 const GURL& first_party_for_cookies) { | |
| 136 std::string cookies; | |
| 137 Send(new PluginHostMsg_GetCookies(route_id_, url, | |
| 138 first_party_for_cookies, &cookies)); | |
| 139 | |
| 140 return cookies; | |
| 141 } | |
| 142 | |
| 143 int WebPluginProxy::GetRendererId() { | |
| 144 if (channel_.get()) | |
| 145 return channel_->renderer_id(); | |
| 146 return -1; | |
| 147 } | |
| 148 | |
| 149 void WebPluginProxy::DidPaint() { | |
| 150 // If we have an accumulated damaged rect, then check to see if we need to | |
| 151 // send out another InvalidateRect message. | |
| 152 waiting_for_paint_ = false; | |
| 153 if (!damaged_rect_.IsEmpty()) | |
| 154 InvalidateRect(damaged_rect_); | |
| 155 } | |
| 156 | |
| 157 void WebPluginProxy::Paint(const gfx::Rect& rect) { | |
| 158 #if defined(OS_MACOSX) | |
| 159 if (!windowless_context()) | |
| 160 return; | |
| 161 #else | |
| 162 if (!windowless_canvas() || !windowless_canvas()->getDevice()) | |
| 163 return; | |
| 164 #endif | |
| 165 | |
| 166 // Clear the damaged area so that if the plugin doesn't paint there we won't | |
| 167 // end up with the old values. | |
| 168 gfx::Rect offset_rect = rect; | |
| 169 offset_rect.Offset(delegate_->GetRect().OffsetFromOrigin()); | |
| 170 #if defined(OS_MACOSX) | |
| 171 CGContextSaveGState(windowless_context()); | |
| 172 // It is possible for windowless_contexts_ to change during plugin painting | |
| 173 // (since the plugin can make a synchronous call during paint event handling), | |
| 174 // in which case we don't want to try to restore later. Not an owning ref | |
| 175 // since owning the ref without owning the shared backing memory doesn't make | |
| 176 // sense, so this should only be used for pointer comparisons. | |
| 177 CGContextRef saved_context_weak = windowless_context(); | |
| 178 // We also save the buffer index for the comparison because if we flip buffers | |
| 179 // but haven't reallocated them then we do need to restore the context because | |
| 180 // it is going to continue to be used. | |
| 181 int saved_index = windowless_buffer_index_; | |
| 182 | |
| 183 CGContextClipToRect(windowless_context(), rect.ToCGRect()); | |
| 184 // TODO(caryclark): This is a temporary workaround to allow the Darwin / Skia | |
| 185 // port to share code with the Darwin / CG port. All ports will eventually use | |
| 186 // the common code below. | |
| 187 delegate_->CGPaint(windowless_context(), rect); | |
| 188 if (windowless_contexts_[saved_index].get() == saved_context_weak) | |
| 189 CGContextRestoreGState(windowless_contexts_[saved_index]); | |
| 190 #else | |
| 191 // See above comment about windowless_context_ changing. | |
| 192 // http::/crbug.com/139462 | |
| 193 skia::RefPtr<SkCanvas> saved_canvas = windowless_canvas(); | |
| 194 | |
| 195 saved_canvas->save(); | |
| 196 | |
| 197 // The given clip rect is relative to the plugin coordinate system. | |
| 198 SkRect sk_rect = { SkIntToScalar(rect.x()), | |
| 199 SkIntToScalar(rect.y()), | |
| 200 SkIntToScalar(rect.right()), | |
| 201 SkIntToScalar(rect.bottom()) }; | |
| 202 saved_canvas->clipRect(sk_rect); | |
| 203 | |
| 204 // Fill a transparent value so that if the plugin supports transparency that | |
| 205 // will work. | |
| 206 saved_canvas->drawColor(SkColorSetARGB(0, 0, 0, 0), SkXfermode::kSrc_Mode); | |
| 207 | |
| 208 // Bring the windowless canvas into the window coordinate system, which is | |
| 209 // how the plugin expects to draw (since the windowless API was originally | |
| 210 // designed just for scribbling over the web page). | |
| 211 saved_canvas->translate(SkIntToScalar(-delegate_->GetRect().x()), | |
| 212 SkIntToScalar(-delegate_->GetRect().y())); | |
| 213 | |
| 214 // Before we send the invalidate, paint so that renderer uses the updated | |
| 215 // bitmap. | |
| 216 delegate_->Paint(saved_canvas.get(), offset_rect); | |
| 217 | |
| 218 saved_canvas->restore(); | |
| 219 #endif | |
| 220 } | |
| 221 | |
| 222 void WebPluginProxy::UpdateGeometry( | |
| 223 const gfx::Rect& window_rect, | |
| 224 const gfx::Rect& clip_rect, | |
| 225 const TransportDIB::Handle& windowless_buffer0, | |
| 226 const TransportDIB::Handle& windowless_buffer1, | |
| 227 int windowless_buffer_index) { | |
| 228 gfx::Rect old = delegate_->GetRect(); | |
| 229 gfx::Rect old_clip_rect = delegate_->GetClipRect(); | |
| 230 | |
| 231 // Update the buffers before doing anything that could call into plugin code, | |
| 232 // so that we don't process buffer changes out of order if plugins make | |
| 233 // synchronous calls that lead to nested UpdateGeometry calls. | |
| 234 if (TransportDIB::is_valid_handle(windowless_buffer0)) { | |
| 235 // The plugin's rect changed, so now we have new buffers to draw into. | |
| 236 SetWindowlessBuffers(windowless_buffer0, | |
| 237 windowless_buffer1, | |
| 238 window_rect); | |
| 239 } | |
| 240 | |
| 241 DCHECK(0 <= windowless_buffer_index && windowless_buffer_index <= 1); | |
| 242 windowless_buffer_index_ = windowless_buffer_index; | |
| 243 | |
| 244 #if defined(OS_MACOSX) | |
| 245 delegate_->UpdateGeometryAndContext( | |
| 246 window_rect, clip_rect, windowless_context()); | |
| 247 #else | |
| 248 delegate_->UpdateGeometry(window_rect, clip_rect); | |
| 249 #endif | |
| 250 | |
| 251 // Send over any pending invalidates which occured when the plugin was | |
| 252 // off screen. | |
| 253 if (!clip_rect.IsEmpty() && !damaged_rect_.IsEmpty()) { | |
| 254 InvalidateRect(damaged_rect_); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 #if defined(OS_WIN) | |
| 259 | |
| 260 void WebPluginProxy::CreateCanvasFromHandle( | |
| 261 const TransportDIB::Handle& dib_handle, | |
| 262 const gfx::Rect& window_rect, | |
| 263 skia::RefPtr<SkCanvas>* canvas) { | |
| 264 *canvas = skia::AdoptRef(skia::CreatePlatformCanvas( | |
| 265 window_rect.width(), window_rect.height(), true, dib_handle.GetHandle(), | |
| 266 skia::RETURN_NULL_ON_FAILURE)); | |
| 267 // The canvas does not own the section so we need to close it now. | |
| 268 dib_handle.Close(); | |
| 269 } | |
| 270 | |
| 271 void WebPluginProxy::SetWindowlessBuffers( | |
| 272 const TransportDIB::Handle& windowless_buffer0, | |
| 273 const TransportDIB::Handle& windowless_buffer1, | |
| 274 const gfx::Rect& window_rect) { | |
| 275 CreateCanvasFromHandle(windowless_buffer0, | |
| 276 window_rect, | |
| 277 &windowless_canvases_[0]); | |
| 278 if (!windowless_canvases_[0]) { | |
| 279 windowless_canvases_[1].clear(); | |
| 280 return; | |
| 281 } | |
| 282 CreateCanvasFromHandle(windowless_buffer1, | |
| 283 window_rect, | |
| 284 &windowless_canvases_[1]); | |
| 285 if (!windowless_canvases_[1]) { | |
| 286 windowless_canvases_[0].clear(); | |
| 287 return; | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 #elif defined(OS_MACOSX) | |
| 292 | |
| 293 void WebPluginProxy::CreateDIBAndCGContextFromHandle( | |
| 294 const TransportDIB::Handle& dib_handle, | |
| 295 const gfx::Rect& window_rect, | |
| 296 scoped_ptr<TransportDIB>* dib_out, | |
| 297 base::ScopedCFTypeRef<CGContextRef>* cg_context_out) { | |
| 298 // Convert the shared memory handle to a handle that works in our process, | |
| 299 // and then use that to create a CGContextRef. | |
| 300 TransportDIB* dib = TransportDIB::Map(dib_handle); | |
| 301 CGContextRef cg_context = NULL; | |
| 302 if (dib) { | |
| 303 cg_context = CGBitmapContextCreate( | |
| 304 dib->memory(), | |
| 305 window_rect.width(), | |
| 306 window_rect.height(), | |
| 307 8, | |
| 308 4 * window_rect.width(), | |
| 309 base::mac::GetSystemColorSpace(), | |
| 310 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); | |
| 311 CGContextTranslateCTM(cg_context, 0, window_rect.height()); | |
| 312 CGContextScaleCTM(cg_context, 1, -1); | |
| 313 } | |
| 314 dib_out->reset(dib); | |
| 315 cg_context_out->reset(cg_context); | |
| 316 } | |
| 317 | |
| 318 void WebPluginProxy::SetWindowlessBuffers( | |
| 319 const TransportDIB::Handle& windowless_buffer0, | |
| 320 const TransportDIB::Handle& windowless_buffer1, | |
| 321 const gfx::Rect& window_rect) { | |
| 322 CreateDIBAndCGContextFromHandle(windowless_buffer0, | |
| 323 window_rect, | |
| 324 &windowless_dibs_[0], | |
| 325 &windowless_contexts_[0]); | |
| 326 CreateDIBAndCGContextFromHandle(windowless_buffer1, | |
| 327 window_rect, | |
| 328 &windowless_dibs_[1], | |
| 329 &windowless_contexts_[1]); | |
| 330 } | |
| 331 | |
| 332 #else | |
| 333 | |
| 334 void WebPluginProxy::SetWindowlessBuffers( | |
| 335 const TransportDIB::Handle& windowless_buffer0, | |
| 336 const TransportDIB::Handle& windowless_buffer1, | |
| 337 const gfx::Rect& window_rect) { | |
| 338 NOTIMPLEMENTED(); | |
| 339 } | |
| 340 | |
| 341 #endif | |
| 342 | |
| 343 void WebPluginProxy::CancelDocumentLoad() { | |
| 344 Send(new PluginHostMsg_CancelDocumentLoad(route_id_)); | |
| 345 } | |
| 346 | |
| 347 void WebPluginProxy::DidStartLoading() { | |
| 348 Send(new PluginHostMsg_DidStartLoading(route_id_)); | |
| 349 } | |
| 350 | |
| 351 void WebPluginProxy::DidStopLoading() { | |
| 352 Send(new PluginHostMsg_DidStopLoading(route_id_)); | |
| 353 } | |
| 354 | |
| 355 #if defined(OS_MACOSX) | |
| 356 void WebPluginProxy::FocusChanged(bool focused) { | |
| 357 IPC::Message* msg = new PluginHostMsg_FocusChanged(route_id_, focused); | |
| 358 Send(msg); | |
| 359 } | |
| 360 | |
| 361 void WebPluginProxy::StartIme() { | |
| 362 IPC::Message* msg = new PluginHostMsg_StartIme(route_id_); | |
| 363 // This message can be sent during event-handling, and needs to be delivered | |
| 364 // within that context. | |
| 365 msg->set_unblock(true); | |
| 366 Send(msg); | |
| 367 } | |
| 368 | |
| 369 WebPluginAcceleratedSurface* WebPluginProxy::GetAcceleratedSurface( | |
| 370 gfx::GpuPreference gpu_preference) { | |
| 371 if (!accelerated_surface_) | |
| 372 accelerated_surface_.reset( | |
| 373 WebPluginAcceleratedSurfaceProxy::Create(this, gpu_preference)); | |
| 374 return accelerated_surface_.get(); | |
| 375 } | |
| 376 | |
| 377 void WebPluginProxy::AcceleratedPluginEnabledRendering() { | |
| 378 Send(new PluginHostMsg_AcceleratedPluginEnabledRendering(route_id_)); | |
| 379 } | |
| 380 | |
| 381 void WebPluginProxy::AcceleratedPluginAllocatedIOSurface(int32_t width, | |
| 382 int32_t height, | |
| 383 uint32_t surface_id) { | |
| 384 Send(new PluginHostMsg_AcceleratedPluginAllocatedIOSurface( | |
| 385 route_id_, width, height, surface_id)); | |
| 386 } | |
| 387 | |
| 388 void WebPluginProxy::AcceleratedPluginSwappedIOSurface() { | |
| 389 Send(new PluginHostMsg_AcceleratedPluginSwappedIOSurface( | |
| 390 route_id_)); | |
| 391 } | |
| 392 #endif | |
| 393 | |
| 394 void WebPluginProxy::OnPaint(const gfx::Rect& damaged_rect) { | |
| 395 GetContentClient()->SetActiveURL(page_url_); | |
| 396 | |
| 397 Paint(damaged_rect); | |
| 398 Send(new PluginHostMsg_InvalidateRect(route_id_, damaged_rect)); | |
| 399 } | |
| 400 | |
| 401 bool WebPluginProxy::IsOffTheRecord() { | |
| 402 return channel_->incognito(); | |
| 403 } | |
| 404 | |
| 405 } // namespace content | |
| OLD | NEW |