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/renderer/npapi/webplugin_impl.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/command_line.h" | |
9 #include "base/debug/crash_logging.h" | |
10 #include "base/location.h" | |
11 #include "base/logging.h" | |
12 #include "base/memory/linked_ptr.h" | |
13 #include "base/metrics/user_metrics_action.h" | |
14 #include "base/single_thread_task_runner.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "base/strings/stringprintf.h" | |
17 #include "base/strings/utf_string_conversions.h" | |
18 #include "base/thread_task_runner_handle.h" | |
19 #include "build/build_config.h" | |
20 #include "cc/blink/web_layer_impl.h" | |
21 #include "cc/layers/io_surface_layer.h" | |
22 #include "content/child/appcache/web_application_cache_host_impl.h" | |
23 #include "content/child/npapi/plugin_host.h" | |
24 #include "content/child/npapi/plugin_instance.h" | |
25 #include "content/child/npapi/webplugin_delegate_impl.h" | |
26 #include "content/child/npapi/webplugin_resource_client.h" | |
27 #include "content/common/view_messages.h" | |
28 #include "content/public/common/content_constants.h" | |
29 #include "content/public/common/content_switches.h" | |
30 #include "content/public/renderer/content_renderer_client.h" | |
31 #include "content/renderer/npapi/webplugin_delegate_proxy.h" | |
32 #include "content/renderer/render_frame_impl.h" | |
33 #include "content/renderer/render_process.h" | |
34 #include "content/renderer/render_thread_impl.h" | |
35 #include "content/renderer/render_view_impl.h" | |
36 #include "net/base/escape.h" | |
37 #include "net/base/net_errors.h" | |
38 #include "net/http/http_response_headers.h" | |
39 #include "skia/ext/platform_canvas.h" | |
40 #include "third_party/WebKit/public/platform/WebCookieJar.h" | |
41 #include "third_party/WebKit/public/platform/WebCursorInfo.h" | |
42 #include "third_party/WebKit/public/platform/WebData.h" | |
43 #include "third_party/WebKit/public/platform/WebHTTPBody.h" | |
44 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" | |
45 #include "third_party/WebKit/public/platform/WebURL.h" | |
46 #include "third_party/WebKit/public/platform/WebURLError.h" | |
47 #include "third_party/WebKit/public/platform/WebURLLoader.h" | |
48 #include "third_party/WebKit/public/platform/WebURLResponse.h" | |
49 #include "third_party/WebKit/public/web/WebConsoleMessage.h" | |
50 #include "third_party/WebKit/public/web/WebDocument.h" | |
51 #include "third_party/WebKit/public/web/WebFrame.h" | |
52 #include "third_party/WebKit/public/web/WebInputEvent.h" | |
53 #include "third_party/WebKit/public/web/WebKit.h" | |
54 #include "third_party/WebKit/public/web/WebPluginContainer.h" | |
55 #include "third_party/WebKit/public/web/WebPluginParams.h" | |
56 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h" | |
57 #include "third_party/WebKit/public/web/WebView.h" | |
58 #include "ui/gfx/geometry/rect.h" | |
59 #include "url/gurl.h" | |
60 #include "url/url_util.h" | |
61 | |
62 using blink::WebCanvas; | |
63 using blink::WebConsoleMessage; | |
64 using blink::WebCookieJar; | |
65 using blink::WebCursorInfo; | |
66 using blink::WebData; | |
67 using blink::WebDataSource; | |
68 using blink::WebFrame; | |
69 using blink::WebHTTPBody; | |
70 using blink::WebHTTPHeaderVisitor; | |
71 using blink::WebInputEvent; | |
72 using blink::WebInputEventResult; | |
73 using blink::WebKeyboardEvent; | |
74 using blink::WebMouseEvent; | |
75 using blink::WebPluginContainer; | |
76 using blink::WebPluginParams; | |
77 using blink::WebRect; | |
78 using blink::WebString; | |
79 using blink::WebURL; | |
80 using blink::WebURLError; | |
81 using blink::WebURLLoader; | |
82 using blink::WebURLLoaderOptions; | |
83 using blink::WebURLRequest; | |
84 using blink::WebURLResponse; | |
85 using blink::WebVector; | |
86 using blink::WebView; | |
87 | |
88 namespace content { | |
89 | |
90 // blink::WebPlugin ---------------------------------------------------------- | |
91 | |
92 bool WebPluginImpl::initialize(WebPluginContainer* container) { | |
93 if (!render_view_.get()) { | |
94 LOG(ERROR) << "No RenderView"; | |
95 return false; | |
96 } | |
97 | |
98 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy( | |
99 this, mime_type_, render_view_, render_frame_); | |
100 | |
101 // Set the container before Initialize because the plugin may | |
102 // synchronously call NPN_GetValue to get its container, or make calls | |
103 // passing script objects that need to be tracked, during initialization. | |
104 SetContainer(container); | |
105 | |
106 bool ok = plugin_delegate->Initialize( | |
107 plugin_url_, arg_names_, arg_values_, load_manually_); | |
108 if (!ok) { | |
109 plugin_delegate->PluginDestroyed(); | |
110 | |
111 blink::WebPlugin* replacement_plugin = | |
112 GetContentClient()->renderer()->CreatePluginReplacement( | |
113 render_frame_, file_path_); | |
114 if (!replacement_plugin) { | |
115 // Maintain invariant that container() returns null when initialize() | |
116 // returns false. | |
117 SetContainer(nullptr); | |
118 return false; | |
119 } | |
120 | |
121 // The replacement plugin, if it exists, must never fail to initialize. | |
122 container->setPlugin(replacement_plugin); | |
123 CHECK(replacement_plugin->initialize(container)); | |
124 | |
125 DCHECK(container->plugin() == replacement_plugin); | |
126 DCHECK(replacement_plugin->container() == container); | |
127 | |
128 // Since the container now owns the replacement plugin instead of this | |
129 // object, we must schedule ourselves for deletion. This also implicitly | |
130 // disables scripting while un-setting the container. | |
131 destroy(); | |
132 | |
133 return true; | |
134 } | |
135 | |
136 delegate_ = plugin_delegate; | |
137 | |
138 return true; | |
139 } | |
140 | |
141 void WebPluginImpl::destroy() { | |
142 SetContainer(NULL); | |
143 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
144 } | |
145 | |
146 void WebPluginImpl::updateAllLifecyclePhases() { | |
147 if (!container_) | |
148 return; | |
149 | |
150 #if defined(OS_WIN) | |
151 // Force a geometry update if needed to allow plugins like media player | |
152 // which defer the initial geometry update to work. Do it now, rather | |
153 // than in paint, so that the paint rect invalidation is registered. | |
154 // Otherwise we may never get the paint call. | |
155 container_->reportGeometry(); | |
156 #endif // OS_WIN | |
157 } | |
158 | |
159 void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) { | |
160 if (!delegate_ || !container_) | |
161 return; | |
162 | |
163 // Note that |canvas| is only used when in windowless mode. | |
164 delegate_->Paint(canvas, paint_rect); | |
165 } | |
166 | |
167 void WebPluginImpl::updateGeometry(const WebRect& window_rect, | |
168 const WebRect& clip_rect, | |
169 const WebRect& unobscured_rect, | |
170 const WebVector<WebRect>& cut_outs_rects, | |
171 bool is_visible) { | |
172 WebPluginGeometry new_geometry; | |
173 new_geometry.window_rect = window_rect; | |
174 new_geometry.clip_rect = clip_rect; | |
175 new_geometry.visible = is_visible; | |
176 new_geometry.rects_valid = true; | |
177 for (size_t i = 0; i < cut_outs_rects.size(); ++i) | |
178 new_geometry.cutout_rects.push_back(cut_outs_rects[i]); | |
179 | |
180 // Only UpdateGeometry if either the window or clip rects have changed. | |
181 if (delegate_ && (first_geometry_update_ || | |
182 new_geometry.window_rect != geometry_.window_rect || | |
183 new_geometry.clip_rect != geometry_.clip_rect)) { | |
184 // Notify the plugin that its parameters have changed. | |
185 delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect); | |
186 } | |
187 | |
188 #if defined(OS_WIN) | |
189 // Don't cache the geometry during the first geometry update. The first | |
190 // geometry update sequence is received when Widget::setParent is called. | |
191 // For plugins like media player which have a bug where they only honor | |
192 // the first geometry update, we have a quirk which ignores the first | |
193 // geometry update. To ensure that these plugins work correctly in cases | |
194 // where we receive only one geometry update from webkit, we also force | |
195 // a geometry update during paint which should go out correctly as the | |
196 // initial geometry update was not cached. | |
197 if (!first_geometry_update_) | |
198 geometry_ = new_geometry; | |
199 #else // OS_WIN | |
200 geometry_ = new_geometry; | |
201 #endif // OS_WIN | |
202 first_geometry_update_ = false; | |
203 } | |
204 | |
205 void WebPluginImpl::updateFocus(bool focused, blink::WebFocusType focus_type) { | |
206 delegate_->SetFocus(focused); | |
207 } | |
208 | |
209 void WebPluginImpl::updateVisibility(bool visible) { | |
210 } | |
211 | |
212 bool WebPluginImpl::acceptsInputEvents() { | |
213 return true; | |
214 } | |
215 | |
216 WebInputEventResult WebPluginImpl::handleInputEvent( | |
217 const WebInputEvent& event, | |
218 WebCursorInfo& cursor_info) { | |
219 // Swallow context menu events in order to suppress the default context menu. | |
220 if (event.type == WebInputEvent::ContextMenu) | |
221 return WebInputEventResult::HandledSuppressed; | |
222 | |
223 WebCursor::CursorInfo web_cursor_info; | |
224 bool ret = delegate_->HandleInputEvent(event, &web_cursor_info); | |
225 cursor_info.type = web_cursor_info.type; | |
226 cursor_info.hotSpot = web_cursor_info.hotspot; | |
227 cursor_info.customImage = web_cursor_info.custom_image; | |
228 cursor_info.imageScaleFactor = web_cursor_info.image_scale_factor; | |
229 #if defined(OS_WIN) | |
230 cursor_info.externalHandle = web_cursor_info.external_handle; | |
231 #endif | |
232 return ret ? WebInputEventResult::HandledApplication | |
233 : WebInputEventResult::NotHandled; | |
234 } | |
235 | |
236 bool WebPluginImpl::isPlaceholder() { | |
237 return false; | |
238 } | |
239 | |
240 // ----------------------------------------------------------------------------- | |
241 | |
242 WebPluginImpl::WebPluginImpl( | |
243 WebFrame* webframe, | |
244 const WebPluginParams& params, | |
245 const base::FilePath& file_path, | |
246 const base::WeakPtr<RenderViewImpl>& render_view, | |
247 RenderFrameImpl* render_frame) | |
248 : render_frame_(render_frame), | |
249 render_view_(render_view), | |
250 webframe_(webframe), | |
251 delegate_(NULL), | |
252 container_(NULL), | |
253 plugin_url_(params.url), | |
254 load_manually_(params.loadManually), | |
255 first_geometry_update_(true), | |
256 ignore_response_error_(false), | |
257 file_path_(file_path), | |
258 mime_type_(base::ToLowerASCII(base::UTF16ToASCII( | |
259 base::StringPiece16(params.mimeType)))) { | |
260 DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size()); | |
261 | |
262 for (size_t i = 0; i < params.attributeNames.size(); ++i) { | |
263 arg_names_.push_back(params.attributeNames[i].utf8()); | |
264 arg_values_.push_back(params.attributeValues[i].utf8()); | |
265 } | |
266 | |
267 // Set subresource URL for crash reporting. | |
268 base::debug::SetCrashKeyValue("subresource_url", plugin_url_.spec()); | |
269 } | |
270 | |
271 WebPluginImpl::~WebPluginImpl() { | |
272 } | |
273 | |
274 GURL WebPluginImpl::CompleteURL(const char* url) { | |
275 if (!webframe_) { | |
276 NOTREACHED(); | |
277 return GURL(); | |
278 } | |
279 // TODO(darin): Is conversion from UTF8 correct here? | |
280 return webframe_->document().completeURL(WebString::fromUTF8(url)); | |
281 } | |
282 | |
283 bool WebPluginImpl::SetPostData(WebURLRequest* request, | |
284 const char* buf, | |
285 uint32_t length) { | |
286 std::vector<std::string> names; | |
287 std::vector<std::string> values; | |
288 std::vector<char> body; | |
289 bool rv = PluginHost::SetPostData(buf, length, &names, &values, &body); | |
290 | |
291 for (size_t i = 0; i < names.size(); ++i) { | |
292 request->addHTTPHeaderField(WebString::fromUTF8(names[i]), | |
293 WebString::fromUTF8(values[i])); | |
294 } | |
295 | |
296 WebString content_type_header = WebString::fromUTF8("Content-Type"); | |
297 const WebString& content_type = | |
298 request->httpHeaderField(content_type_header); | |
299 if (content_type.isEmpty()) { | |
300 request->setHTTPHeaderField( | |
301 content_type_header, | |
302 WebString::fromUTF8("application/x-www-form-urlencoded")); | |
303 } | |
304 | |
305 WebHTTPBody http_body; | |
306 if (body.size()) { | |
307 http_body.initialize(); | |
308 http_body.appendData(WebData(&body[0], body.size())); | |
309 } | |
310 request->setHTTPBody(http_body); | |
311 | |
312 return rv; | |
313 } | |
314 | |
315 bool WebPluginImpl::IsValidUrl(const GURL& url, ReferrerValue referrer_flag) { | |
316 if (referrer_flag == PLUGIN_SRC && | |
317 mime_type_ == kFlashPluginSwfMimeType && | |
318 url.GetOrigin() != plugin_url_.GetOrigin()) { | |
319 // Do url check to make sure that there are no @, ;, \ chars in between url | |
320 // scheme and url path. | |
321 const char* url_to_check(url.spec().data()); | |
322 url::Parsed parsed; | |
323 url::ParseStandardURL(url_to_check, strlen(url_to_check), &parsed); | |
324 if (parsed.path.begin <= parsed.scheme.end()) | |
325 return true; | |
326 std::string string_to_search; | |
327 string_to_search.assign(url_to_check + parsed.scheme.end(), | |
328 parsed.path.begin - parsed.scheme.end()); | |
329 if (string_to_search.find("@") != std::string::npos || | |
330 string_to_search.find(";") != std::string::npos || | |
331 string_to_search.find("\\") != std::string::npos) | |
332 return false; | |
333 } | |
334 | |
335 return true; | |
336 } | |
337 | |
338 WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame( | |
339 const char* url, | |
340 bool is_javascript_url, | |
341 bool popups_allowed, | |
342 const char* method, | |
343 const char* target, | |
344 const char* buf, | |
345 unsigned int len, | |
346 ReferrerValue referrer_flag) { | |
347 // If there is no target, there is nothing to do | |
348 if (!target) | |
349 return NOT_ROUTED; | |
350 | |
351 // This could happen if the WebPluginContainer was already deleted. | |
352 if (!webframe_) | |
353 return NOT_ROUTED; | |
354 | |
355 WebString target_str = WebString::fromUTF8(target); | |
356 | |
357 // Take special action for JavaScript URLs | |
358 if (is_javascript_url) { | |
359 WebFrame* target_frame = | |
360 webframe_->view()->findFrameByName(target_str, webframe_); | |
361 // For security reasons, do not allow JavaScript on frames | |
362 // other than this frame. | |
363 if (target_frame != webframe_) { | |
364 // TODO(darin): Localize this message. | |
365 const char kMessage[] = | |
366 "Ignoring cross-frame javascript URL load requested by plugin."; | |
367 webframe_->addMessageToConsole( | |
368 WebConsoleMessage(WebConsoleMessage::LevelError, | |
369 WebString::fromUTF8(kMessage))); | |
370 return ROUTED; | |
371 } | |
372 | |
373 // Route javascript calls back to the plugin. | |
374 return NOT_ROUTED; | |
375 } | |
376 | |
377 // If we got this far, we're routing content to a target frame. | |
378 // Go fetch the URL. | |
379 | |
380 GURL complete_url = CompleteURL(url); | |
381 // Remove when flash bug is fixed. http://crbug.com/40016. | |
382 if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag)) | |
383 return INVALID_URL; | |
384 | |
385 if (strcmp(method, "GET") != 0) { | |
386 // We're only going to route HTTP/HTTPS requests | |
387 if (!complete_url.SchemeIsHTTPOrHTTPS()) | |
388 return INVALID_URL; | |
389 } | |
390 | |
391 WebURLRequest request(complete_url); | |
392 SetReferrer(&request, referrer_flag); | |
393 | |
394 request.setHTTPMethod(WebString::fromUTF8(method)); | |
395 request.setFirstPartyForCookies( | |
396 webframe_->document().firstPartyForCookies()); | |
397 request.setHasUserGesture(popups_allowed); | |
398 // ServiceWorker is disabled for NPAPI. | |
399 request.setSkipServiceWorker(true); | |
400 if (len > 0) { | |
401 if (!SetPostData(&request, buf, len)) { | |
402 // Uhoh - we're in trouble. There isn't a good way | |
403 // to recover at this point. Break out. | |
404 NOTREACHED(); | |
405 return ROUTED; | |
406 } | |
407 } | |
408 | |
409 container_->loadFrameRequest(request, target_str); | |
410 return ROUTED; | |
411 } | |
412 | |
413 bool WebPluginImpl::FindProxyForUrl(const GURL& url, std::string* proxy_list) { | |
414 // Proxy resolving doesn't work in single-process mode. | |
415 return false; | |
416 } | |
417 | |
418 void WebPluginImpl::SetCookie(const GURL& url, | |
419 const GURL& first_party_for_cookies, | |
420 const std::string& cookie) { | |
421 if (!render_view_.get()) | |
422 return; | |
423 | |
424 WebCookieJar* cookie_jar = render_frame_->cookie_jar(); | |
425 if (!cookie_jar) { | |
426 DLOG(WARNING) << "No cookie jar!"; | |
427 return; | |
428 } | |
429 | |
430 cookie_jar->setCookie( | |
431 url, first_party_for_cookies, WebString::fromUTF8(cookie)); | |
432 } | |
433 | |
434 std::string WebPluginImpl::GetCookies(const GURL& url, | |
435 const GURL& first_party_for_cookies) { | |
436 if (!render_view_.get()) | |
437 return std::string(); | |
438 | |
439 WebCookieJar* cookie_jar = render_frame_->cookie_jar(); | |
440 if (!cookie_jar) { | |
441 DLOG(WARNING) << "No cookie jar!"; | |
442 return std::string(); | |
443 } | |
444 | |
445 return base::UTF16ToUTF8(base::StringPiece16( | |
446 cookie_jar->cookies(url, first_party_for_cookies))); | |
447 } | |
448 | |
449 #if defined(OS_MACOSX) | |
450 WebPluginAcceleratedSurface* WebPluginImpl::GetAcceleratedSurface( | |
451 gfx::GpuPreference gpu_preference) { | |
452 return NULL; | |
453 } | |
454 | |
455 void WebPluginImpl::AcceleratedPluginEnabledRendering() { | |
456 } | |
457 | |
458 void WebPluginImpl::AcceleratedPluginAllocatedIOSurface(int32_t width, | |
459 int32_t height, | |
460 uint32_t surface_id) { | |
461 next_io_surface_allocated_ = true; | |
462 next_io_surface_width_ = width; | |
463 next_io_surface_height_ = height; | |
464 next_io_surface_id_ = surface_id; | |
465 } | |
466 | |
467 void WebPluginImpl::AcceleratedPluginSwappedIOSurface() { | |
468 if (!container_) | |
469 return; | |
470 // Deferring the call to setBackingIOSurfaceId is an attempt to | |
471 // work around garbage occasionally showing up in the plugin's | |
472 // area during live resizing of Core Animation plugins. The | |
473 // assumption was that by the time this was called, the plugin | |
474 // process would have populated the newly allocated IOSurface. It | |
475 // is not 100% clear at this point why any garbage is getting | |
476 // through. More investigation is needed. http://crbug.com/105346 | |
477 if (next_io_surface_allocated_) { | |
478 if (next_io_surface_id_) { | |
479 if (!io_surface_layer_.get()) { | |
480 io_surface_layer_ = cc::IOSurfaceLayer::Create(); | |
481 web_layer_.reset(new cc_blink::WebLayerImpl(io_surface_layer_)); | |
482 container_->setWebLayer(web_layer_.get()); | |
483 } | |
484 io_surface_layer_->SetIOSurfaceProperties( | |
485 next_io_surface_id_, | |
486 gfx::Size(next_io_surface_width_, next_io_surface_height_)); | |
487 } else { | |
488 container_->setWebLayer(NULL); | |
489 web_layer_.reset(); | |
490 io_surface_layer_ = NULL; | |
491 } | |
492 next_io_surface_allocated_ = false; | |
493 } else { | |
494 if (io_surface_layer_.get()) | |
495 io_surface_layer_->SetNeedsDisplay(); | |
496 } | |
497 } | |
498 #endif | |
499 | |
500 void WebPluginImpl::Invalidate() { | |
501 if (container_) | |
502 container_->invalidate(); | |
503 } | |
504 | |
505 void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) { | |
506 if (container_) | |
507 container_->invalidateRect(rect); | |
508 } | |
509 | |
510 void WebPluginImpl::SetContainer(WebPluginContainer* container) { | |
511 if (!container) | |
512 TearDownPluginInstance(NULL); | |
513 container_ = container; | |
514 } | |
515 | |
516 unsigned long WebPluginImpl::GetNextResourceId() { | |
517 if (!webframe_) | |
518 return 0; | |
519 WebView* view = webframe_->view(); | |
520 if (!view) | |
521 return 0; | |
522 return view->createUniqueIdentifierForRequest(); | |
523 } | |
524 | |
525 void WebPluginImpl::CancelDocumentLoad() { | |
526 if (webframe_) { | |
527 ignore_response_error_ = true; | |
528 webframe_->stopLoading(); | |
529 } | |
530 } | |
531 | |
532 void WebPluginImpl::DidStartLoading() { | |
533 if (render_view_.get()) { | |
534 // TODO(darin): Make is_loading_ be a counter! | |
535 render_view_->DidStartLoading(); | |
536 } | |
537 } | |
538 | |
539 void WebPluginImpl::DidStopLoading() { | |
540 if (render_view_.get()) { | |
541 // TODO(darin): Make is_loading_ be a counter! | |
542 render_view_->DidStopLoading(); | |
543 } | |
544 } | |
545 | |
546 bool WebPluginImpl::IsOffTheRecord() { | |
547 return false; | |
548 } | |
549 | |
550 bool WebPluginImpl::ReinitializePluginForResponse( | |
551 WebURLLoader* loader) { | |
552 WebFrame* webframe = webframe_; | |
553 if (!webframe) | |
554 return false; | |
555 | |
556 WebView* webview = webframe->view(); | |
557 if (!webview) | |
558 return false; | |
559 | |
560 WebPluginContainer* container_widget = container_; | |
561 | |
562 // Destroy the current plugin instance. | |
563 TearDownPluginInstance(loader); | |
564 | |
565 container_ = container_widget; | |
566 webframe_ = webframe; | |
567 | |
568 WebPluginDelegateProxy* plugin_delegate = new WebPluginDelegateProxy( | |
569 this, mime_type_, render_view_, render_frame_); | |
570 | |
571 bool ok = plugin_delegate && plugin_delegate->Initialize( | |
572 plugin_url_, arg_names_, arg_values_, load_manually_); | |
573 | |
574 if (!ok) { | |
575 container_ = NULL; | |
576 // TODO(iyengar) Should we delete the current plugin instance here? | |
577 return false; | |
578 } | |
579 | |
580 delegate_ = plugin_delegate; | |
581 | |
582 // Force a geometry update to occur to ensure that the plugin becomes | |
583 // visible. | |
584 container_->reportGeometry(); | |
585 | |
586 // The plugin move sequences accumulated via DidMove are sent to the browser | |
587 // whenever the renderer paints. Force a paint here to ensure that changes | |
588 // to the plugin window are propagated to the browser. | |
589 container_->invalidate(); | |
590 return true; | |
591 } | |
592 | |
593 void WebPluginImpl::TearDownPluginInstance( | |
594 WebURLLoader* loader_to_ignore) { | |
595 // JavaScript garbage collection may cause plugin script object references to | |
596 // be retained long after the plugin is destroyed. Some plugins won't cope | |
597 // with their objects being released after they've been destroyed, and once | |
598 // we've actually unloaded the plugin the object's releaseobject() code may | |
599 // no longer be in memory. The container tracks the plugin's objects and lets | |
600 // us invalidate them, releasing the references to them held by the JavaScript | |
601 // runtime. | |
602 if (container_) { | |
603 container_->setWebLayer(NULL); | |
604 } | |
605 | |
606 // Call PluginDestroyed() first to prevent the plugin from calling us back | |
607 // in the middle of tearing down the render tree. | |
608 if (delegate_) { | |
609 // The plugin may call into the browser and pass script objects even during | |
610 // teardown, so temporarily re-enable plugin script objects. | |
611 DCHECK(container_); | |
612 | |
613 delegate_->PluginDestroyed(); | |
614 delegate_ = NULL; | |
615 } | |
616 | |
617 // This needs to be called now and not in the destructor since the | |
618 // webframe_ might not be valid anymore. | |
619 webframe_ = NULL; | |
620 } | |
621 | |
622 void WebPluginImpl::SetReferrer(blink::WebURLRequest* request, | |
623 ReferrerValue referrer_flag) { | |
624 switch (referrer_flag) { | |
625 case DOCUMENT_URL: | |
626 webframe_->setReferrerForRequest(*request, GURL()); | |
627 break; | |
628 | |
629 case PLUGIN_SRC: | |
630 webframe_->setReferrerForRequest(*request, plugin_url_); | |
631 break; | |
632 | |
633 default: | |
634 break; | |
635 } | |
636 } | |
637 | |
638 } // namespace content | |
OLD | NEW |