Roll src/third_party/WebKit a452221:9ff6d11 (svn 202117:202119)
[chromium-blink-merge.git] / content / renderer / pepper / pepper_plugin_instance_impl.cc
blob27b2d73c91820dbc154bd9094a311f7299b3bc48
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.
5 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/memory/linked_ptr.h"
12 #include "base/metrics/histogram.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_offset_string_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/time/time.h"
21 #include "base/trace_event/trace_event.h"
22 #include "cc/blink/web_layer_impl.h"
23 #include "cc/layers/texture_layer.h"
24 #include "content/common/content_constants_internal.h"
25 #include "content/common/frame_messages.h"
26 #include "content/public/common/content_constants.h"
27 #include "content/public/renderer/content_renderer_client.h"
28 #include "content/renderer/pepper/content_decryptor_delegate.h"
29 #include "content/renderer/pepper/event_conversion.h"
30 #include "content/renderer/pepper/fullscreen_container.h"
31 #include "content/renderer/pepper/gfx_conversion.h"
32 #include "content/renderer/pepper/host_dispatcher_wrapper.h"
33 #include "content/renderer/pepper/host_globals.h"
34 #include "content/renderer/pepper/message_channel.h"
35 #include "content/renderer/pepper/pepper_browser_connection.h"
36 #include "content/renderer/pepper/pepper_compositor_host.h"
37 #include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
38 #include "content/renderer/pepper/pepper_graphics_2d_host.h"
39 #include "content/renderer/pepper/pepper_in_process_router.h"
40 #include "content/renderer/pepper/pepper_plugin_instance_metrics.h"
41 #include "content/renderer/pepper/pepper_try_catch.h"
42 #include "content/renderer/pepper/pepper_url_loader_host.h"
43 #include "content/renderer/pepper/plugin_instance_throttler_impl.h"
44 #include "content/renderer/pepper/plugin_module.h"
45 #include "content/renderer/pepper/plugin_object.h"
46 #include "content/renderer/pepper/ppapi_preferences_builder.h"
47 #include "content/renderer/pepper/ppb_buffer_impl.h"
48 #include "content/renderer/pepper/ppb_graphics_3d_impl.h"
49 #include "content/renderer/pepper/ppb_image_data_impl.h"
50 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
51 #include "content/renderer/pepper/url_request_info_util.h"
52 #include "content/renderer/pepper/url_response_info_util.h"
53 #include "content/renderer/render_frame_impl.h"
54 #include "content/renderer/render_thread_impl.h"
55 #include "content/renderer/render_view_impl.h"
56 #include "content/renderer/render_widget.h"
57 #include "content/renderer/render_widget_fullscreen_pepper.h"
58 #include "content/renderer/sad_plugin.h"
59 #include "media/base/audio_hardware_config.h"
60 #include "ppapi/c/dev/ppp_text_input_dev.h"
61 #include "ppapi/c/pp_rect.h"
62 #include "ppapi/c/ppb_audio_config.h"
63 #include "ppapi/c/ppb_core.h"
64 #include "ppapi/c/ppb_gamepad.h"
65 #include "ppapi/c/ppp_input_event.h"
66 #include "ppapi/c/ppp_instance.h"
67 #include "ppapi/c/ppp_messaging.h"
68 #include "ppapi/c/ppp_mouse_lock.h"
69 #include "ppapi/c/private/ppb_find_private.h"
70 #include "ppapi/c/private/ppp_find_private.h"
71 #include "ppapi/c/private/ppp_instance_private.h"
72 #include "ppapi/c/private/ppp_pdf.h"
73 #include "ppapi/host/ppapi_host.h"
74 #include "ppapi/proxy/ppapi_messages.h"
75 #include "ppapi/proxy/serialized_var.h"
76 #include "ppapi/proxy/uma_private_resource.h"
77 #include "ppapi/proxy/url_loader_resource.h"
78 #include "ppapi/shared_impl/ppapi_permissions.h"
79 #include "ppapi/shared_impl/ppb_gamepad_shared.h"
80 #include "ppapi/shared_impl/ppb_input_event_shared.h"
81 #include "ppapi/shared_impl/ppb_url_util_shared.h"
82 #include "ppapi/shared_impl/ppb_view_shared.h"
83 #include "ppapi/shared_impl/ppp_instance_combined.h"
84 #include "ppapi/shared_impl/resource.h"
85 #include "ppapi/shared_impl/scoped_pp_resource.h"
86 #include "ppapi/shared_impl/scoped_pp_var.h"
87 #include "ppapi/shared_impl/time_conversion.h"
88 #include "ppapi/shared_impl/url_request_info_data.h"
89 #include "ppapi/shared_impl/var.h"
90 #include "ppapi/thunk/enter.h"
91 #include "ppapi/thunk/ppb_buffer_api.h"
92 #include "printing/metafile_skia_wrapper.h"
93 #include "printing/pdf_metafile_skia.h"
94 #include "skia/ext/platform_canvas.h"
95 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
96 #include "third_party/WebKit/public/platform/WebGamepads.h"
97 #include "third_party/WebKit/public/platform/WebRect.h"
98 #include "third_party/WebKit/public/platform/WebString.h"
99 #include "third_party/WebKit/public/platform/WebURL.h"
100 #include "third_party/WebKit/public/platform/WebURLError.h"
101 #include "third_party/WebKit/public/platform/WebURLRequest.h"
102 #include "third_party/WebKit/public/web/WebBindings.h"
103 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
104 #include "third_party/WebKit/public/web/WebDataSource.h"
105 #include "third_party/WebKit/public/web/WebDocument.h"
106 #include "third_party/WebKit/public/web/WebInputEvent.h"
107 #include "third_party/WebKit/public/web/WebLocalFrame.h"
108 #include "third_party/WebKit/public/web/WebPluginContainer.h"
109 #include "third_party/WebKit/public/web/WebPluginScriptForbiddenScope.h"
110 #include "third_party/WebKit/public/web/WebPrintParams.h"
111 #include "third_party/WebKit/public/web/WebPrintPresetOptions.h"
112 #include "third_party/WebKit/public/web/WebPrintScalingOption.h"
113 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
114 #include "third_party/WebKit/public/web/WebScriptSource.h"
115 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
116 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
117 #include "third_party/WebKit/public/web/WebView.h"
118 #include "third_party/khronos/GLES2/gl2.h"
119 #include "ui/gfx/image/image_skia.h"
120 #include "ui/gfx/image/image_skia_rep.h"
121 #include "ui/gfx/range/range.h"
122 #include "v8/include/v8.h"
124 #if defined(OS_CHROMEOS)
125 #include "ui/events/keycodes/keyboard_codes_posix.h"
126 #endif
128 using base::StringPrintf;
129 using ppapi::InputEventData;
130 using ppapi::PpapiGlobals;
131 using ppapi::PPB_InputEvent_Shared;
132 using ppapi::PPB_View_Shared;
133 using ppapi::PPP_Instance_Combined;
134 using ppapi::Resource;
135 using ppapi::ScopedPPResource;
136 using ppapi::ScopedPPVar;
137 using ppapi::StringVar;
138 using ppapi::TrackedCallback;
139 using ppapi::thunk::EnterResourceNoLock;
140 using ppapi::thunk::PPB_Buffer_API;
141 using ppapi::thunk::PPB_Gamepad_API;
142 using ppapi::thunk::PPB_Graphics2D_API;
143 using ppapi::thunk::PPB_Graphics3D_API;
144 using ppapi::thunk::PPB_ImageData_API;
145 using ppapi::Var;
146 using ppapi::ArrayBufferVar;
147 using ppapi::ViewData;
148 using blink::WebBindings;
149 using blink::WebCanvas;
150 using blink::WebCursorInfo;
151 using blink::WebDocument;
152 using blink::WebElement;
153 using blink::WebFrame;
154 using blink::WebInputEvent;
155 using blink::WebLocalFrame;
156 using blink::WebPlugin;
157 using blink::WebPluginContainer;
158 using blink::WebPrintParams;
159 using blink::WebPrintScalingOption;
160 using blink::WebScopedUserGesture;
161 using blink::WebString;
162 using blink::WebURLError;
163 using blink::WebURLLoader;
164 using blink::WebURLLoaderClient;
165 using blink::WebURLRequest;
166 using blink::WebURLResponse;
167 using blink::WebUserGestureIndicator;
168 using blink::WebUserGestureToken;
169 using blink::WebView;
171 namespace content {
173 namespace {
175 #define STATIC_ASSERT_PP_MATCHING_ENUM(a, b) \
176 static_assert(static_cast<int>(a) == static_cast<int>(b), \
177 "mismatching enums: " #a)
179 // Check PP_TextInput_Type and ui::TextInputType are kept in sync.
180 STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_NONE,
181 PP_TEXTINPUT_TYPE_NONE);
182 STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_TEXT,
183 PP_TEXTINPUT_TYPE_TEXT);
184 STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_PASSWORD,
185 PP_TEXTINPUT_TYPE_PASSWORD);
186 STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_SEARCH,
187 PP_TEXTINPUT_TYPE_SEARCH);
188 STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_EMAIL,
189 PP_TEXTINPUT_TYPE_EMAIL);
190 STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_NUMBER,
191 PP_TEXTINPUT_TYPE_NUMBER);
192 STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_TELEPHONE,
193 PP_TEXTINPUT_TYPE_TELEPHONE);
194 STATIC_ASSERT_PP_MATCHING_ENUM(ui::TEXT_INPUT_TYPE_URL,
195 PP_TEXTINPUT_TYPE_URL);
197 // The default text input type is to regard the plugin always accept text input.
198 // This is for allowing users to use input methods even on completely-IME-
199 // unaware plugins (e.g., PPAPI Flash or PDF plugin for M16).
200 // Plugins need to explicitly opt out the text input mode if they know
201 // that they don't accept texts.
202 const ui::TextInputType kPluginDefaultTextInputType = ui::TEXT_INPUT_TYPE_TEXT;
204 // <embed>/<object> attributes.
205 const char kWidth[] = "width";
206 const char kHeight[] = "height";
207 const char kBorder[] = "border"; // According to w3c, deprecated.
208 const char kStyle[] = "style";
210 #define STATIC_ASSERT_MATCHING_ENUM(webkit_name, np_name) \
211 static_assert(static_cast<int>(WebCursorInfo::webkit_name) == \
212 static_cast<int>(np_name), \
213 "mismatching enums: " #webkit_name)
215 STATIC_ASSERT_MATCHING_ENUM(TypePointer, PP_MOUSECURSOR_TYPE_POINTER);
216 STATIC_ASSERT_MATCHING_ENUM(TypeCross, PP_MOUSECURSOR_TYPE_CROSS);
217 STATIC_ASSERT_MATCHING_ENUM(TypeHand, PP_MOUSECURSOR_TYPE_HAND);
218 STATIC_ASSERT_MATCHING_ENUM(TypeIBeam, PP_MOUSECURSOR_TYPE_IBEAM);
219 STATIC_ASSERT_MATCHING_ENUM(TypeWait, PP_MOUSECURSOR_TYPE_WAIT);
220 STATIC_ASSERT_MATCHING_ENUM(TypeHelp, PP_MOUSECURSOR_TYPE_HELP);
221 STATIC_ASSERT_MATCHING_ENUM(TypeEastResize, PP_MOUSECURSOR_TYPE_EASTRESIZE);
222 STATIC_ASSERT_MATCHING_ENUM(TypeNorthResize, PP_MOUSECURSOR_TYPE_NORTHRESIZE);
223 STATIC_ASSERT_MATCHING_ENUM(TypeNorthEastResize,
224 PP_MOUSECURSOR_TYPE_NORTHEASTRESIZE);
225 STATIC_ASSERT_MATCHING_ENUM(TypeNorthWestResize,
226 PP_MOUSECURSOR_TYPE_NORTHWESTRESIZE);
227 STATIC_ASSERT_MATCHING_ENUM(TypeSouthResize, PP_MOUSECURSOR_TYPE_SOUTHRESIZE);
228 STATIC_ASSERT_MATCHING_ENUM(TypeSouthEastResize,
229 PP_MOUSECURSOR_TYPE_SOUTHEASTRESIZE);
230 STATIC_ASSERT_MATCHING_ENUM(TypeSouthWestResize,
231 PP_MOUSECURSOR_TYPE_SOUTHWESTRESIZE);
232 STATIC_ASSERT_MATCHING_ENUM(TypeWestResize, PP_MOUSECURSOR_TYPE_WESTRESIZE);
233 STATIC_ASSERT_MATCHING_ENUM(TypeNorthSouthResize,
234 PP_MOUSECURSOR_TYPE_NORTHSOUTHRESIZE);
235 STATIC_ASSERT_MATCHING_ENUM(TypeEastWestResize,
236 PP_MOUSECURSOR_TYPE_EASTWESTRESIZE);
237 STATIC_ASSERT_MATCHING_ENUM(TypeNorthEastSouthWestResize,
238 PP_MOUSECURSOR_TYPE_NORTHEASTSOUTHWESTRESIZE);
239 STATIC_ASSERT_MATCHING_ENUM(TypeNorthWestSouthEastResize,
240 PP_MOUSECURSOR_TYPE_NORTHWESTSOUTHEASTRESIZE);
241 STATIC_ASSERT_MATCHING_ENUM(TypeColumnResize,
242 PP_MOUSECURSOR_TYPE_COLUMNRESIZE);
243 STATIC_ASSERT_MATCHING_ENUM(TypeRowResize, PP_MOUSECURSOR_TYPE_ROWRESIZE);
244 STATIC_ASSERT_MATCHING_ENUM(TypeMiddlePanning,
245 PP_MOUSECURSOR_TYPE_MIDDLEPANNING);
246 STATIC_ASSERT_MATCHING_ENUM(TypeEastPanning, PP_MOUSECURSOR_TYPE_EASTPANNING);
247 STATIC_ASSERT_MATCHING_ENUM(TypeNorthPanning,
248 PP_MOUSECURSOR_TYPE_NORTHPANNING);
249 STATIC_ASSERT_MATCHING_ENUM(TypeNorthEastPanning,
250 PP_MOUSECURSOR_TYPE_NORTHEASTPANNING);
251 STATIC_ASSERT_MATCHING_ENUM(TypeNorthWestPanning,
252 PP_MOUSECURSOR_TYPE_NORTHWESTPANNING);
253 STATIC_ASSERT_MATCHING_ENUM(TypeSouthPanning,
254 PP_MOUSECURSOR_TYPE_SOUTHPANNING);
255 STATIC_ASSERT_MATCHING_ENUM(TypeSouthEastPanning,
256 PP_MOUSECURSOR_TYPE_SOUTHEASTPANNING);
257 STATIC_ASSERT_MATCHING_ENUM(TypeSouthWestPanning,
258 PP_MOUSECURSOR_TYPE_SOUTHWESTPANNING);
259 STATIC_ASSERT_MATCHING_ENUM(TypeWestPanning, PP_MOUSECURSOR_TYPE_WESTPANNING);
260 STATIC_ASSERT_MATCHING_ENUM(TypeMove, PP_MOUSECURSOR_TYPE_MOVE);
261 STATIC_ASSERT_MATCHING_ENUM(TypeVerticalText,
262 PP_MOUSECURSOR_TYPE_VERTICALTEXT);
263 STATIC_ASSERT_MATCHING_ENUM(TypeCell, PP_MOUSECURSOR_TYPE_CELL);
264 STATIC_ASSERT_MATCHING_ENUM(TypeContextMenu, PP_MOUSECURSOR_TYPE_CONTEXTMENU);
265 STATIC_ASSERT_MATCHING_ENUM(TypeAlias, PP_MOUSECURSOR_TYPE_ALIAS);
266 STATIC_ASSERT_MATCHING_ENUM(TypeProgress, PP_MOUSECURSOR_TYPE_PROGRESS);
267 STATIC_ASSERT_MATCHING_ENUM(TypeNoDrop, PP_MOUSECURSOR_TYPE_NODROP);
268 STATIC_ASSERT_MATCHING_ENUM(TypeCopy, PP_MOUSECURSOR_TYPE_COPY);
269 STATIC_ASSERT_MATCHING_ENUM(TypeNone, PP_MOUSECURSOR_TYPE_NONE);
270 STATIC_ASSERT_MATCHING_ENUM(TypeNotAllowed, PP_MOUSECURSOR_TYPE_NOTALLOWED);
271 STATIC_ASSERT_MATCHING_ENUM(TypeZoomIn, PP_MOUSECURSOR_TYPE_ZOOMIN);
272 STATIC_ASSERT_MATCHING_ENUM(TypeZoomOut, PP_MOUSECURSOR_TYPE_ZOOMOUT);
273 STATIC_ASSERT_MATCHING_ENUM(TypeGrab, PP_MOUSECURSOR_TYPE_GRAB);
274 STATIC_ASSERT_MATCHING_ENUM(TypeGrabbing, PP_MOUSECURSOR_TYPE_GRABBING);
275 // Do not assert WebCursorInfo::TypeCustom == PP_CURSORTYPE_CUSTOM;
276 // PP_CURSORTYPE_CUSTOM is pinned to allow new cursor types.
278 STATIC_ASSERT_PP_MATCHING_ENUM(blink::WebPrintScalingOptionNone,
279 PP_PRINTSCALINGOPTION_NONE);
280 STATIC_ASSERT_PP_MATCHING_ENUM(
281 blink::WebPrintScalingOptionFitToPrintableArea,
282 PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA);
283 STATIC_ASSERT_PP_MATCHING_ENUM(
284 blink::WebPrintScalingOptionSourceSize,
285 PP_PRINTSCALINGOPTION_SOURCE_SIZE);
287 // Sets |*security_origin| to be the WebKit security origin associated with the
288 // document containing the given plugin instance. On success, returns true. If
289 // the instance is invalid, returns false and |*security_origin| will be
290 // unchanged.
291 bool SecurityOriginForInstance(PP_Instance instance_id,
292 blink::WebSecurityOrigin* security_origin) {
293 PepperPluginInstanceImpl* instance =
294 HostGlobals::Get()->GetInstance(instance_id);
295 if (!instance)
296 return false;
298 WebElement plugin_element = instance->container()->element();
299 *security_origin = plugin_element.document().securityOrigin();
300 return true;
303 // Convert the given vector to an array of C-strings. The strings in the
304 // returned vector are only guaranteed valid so long as the vector of strings
305 // is not modified.
306 scoped_ptr<const char* []> StringVectorToArgArray(
307 const std::vector<std::string>& vector) {
308 scoped_ptr<const char * []> array(new const char* [vector.size()]);
309 for (size_t i = 0; i < vector.size(); ++i)
310 array[i] = vector[i].c_str();
311 return array.Pass();
314 // Returns true if this is a "system reserved" key which should not be sent to
315 // a plugin. Some poorly behaving plugins (like Flash) incorrectly report that
316 // they handle all keys sent to them. This can prevent keystrokes from working
317 // for things like screen brightness and volume control.
318 bool IsReservedSystemInputEvent(const blink::WebInputEvent& event) {
319 #if defined(OS_CHROMEOS)
320 if (event.type != WebInputEvent::KeyDown &&
321 event.type != WebInputEvent::KeyUp)
322 return false;
323 const blink::WebKeyboardEvent& key_event =
324 static_cast<const blink::WebKeyboardEvent&>(event);
325 switch (key_event.windowsKeyCode) {
326 case ui::VKEY_BRIGHTNESS_DOWN:
327 case ui::VKEY_BRIGHTNESS_UP:
328 case ui::VKEY_KBD_BRIGHTNESS_DOWN:
329 case ui::VKEY_KBD_BRIGHTNESS_UP:
330 case ui::VKEY_VOLUME_MUTE:
331 case ui::VKEY_VOLUME_DOWN:
332 case ui::VKEY_VOLUME_UP:
333 return true;
334 default:
335 return false;
337 #endif // defined(OS_CHROMEOS)
338 return false;
341 class PluginInstanceLockTarget : public MouseLockDispatcher::LockTarget {
342 public:
343 explicit PluginInstanceLockTarget(PepperPluginInstanceImpl* plugin)
344 : plugin_(plugin) {}
346 void OnLockMouseACK(bool succeeded) override {
347 plugin_->OnLockMouseACK(succeeded);
350 void OnMouseLockLost() override { plugin_->OnMouseLockLost(); }
352 bool HandleMouseLockedInputEvent(const blink::WebMouseEvent& event) override {
353 plugin_->HandleMouseLockedInputEvent(event);
354 return true;
357 private:
358 PepperPluginInstanceImpl* plugin_;
361 } // namespace
363 // static
364 PepperPluginInstanceImpl* PepperPluginInstanceImpl::Create(
365 RenderFrameImpl* render_frame,
366 PluginModule* module,
367 WebPluginContainer* container,
368 const GURL& plugin_url) {
369 base::Callback<const void*(const char*)> get_plugin_interface_func =
370 base::Bind(&PluginModule::GetPluginInterface, module);
371 PPP_Instance_Combined* ppp_instance_combined =
372 PPP_Instance_Combined::Create(get_plugin_interface_func);
373 if (!ppp_instance_combined)
374 return NULL;
376 return new PepperPluginInstanceImpl(render_frame,
377 module,
378 ppp_instance_combined,
379 container,
380 plugin_url);
383 PepperPluginInstanceImpl::ExternalDocumentLoader::ExternalDocumentLoader()
384 : finished_loading_(false) {}
386 PepperPluginInstanceImpl::ExternalDocumentLoader::~ExternalDocumentLoader() {}
388 void PepperPluginInstanceImpl::ExternalDocumentLoader::ReplayReceivedData(
389 WebURLLoaderClient* document_loader) {
390 for (std::list<std::string>::iterator it = data_.begin(); it != data_.end();
391 ++it) {
392 document_loader->didReceiveData(
393 NULL, it->c_str(), it->length(), 0 /* encoded_data_length */);
395 if (finished_loading_) {
396 document_loader->didFinishLoading(
397 NULL,
398 0 /* finish_time */,
399 blink::WebURLLoaderClient::kUnknownEncodedDataLength);
400 } else if (error_.get()) {
401 DCHECK(!finished_loading_);
402 document_loader->didFail(NULL, *error_);
406 void PepperPluginInstanceImpl::ExternalDocumentLoader::didReceiveData(
407 WebURLLoader* loader,
408 const char* data,
409 int data_length,
410 int encoded_data_length) {
411 data_.push_back(std::string(data, data_length));
414 void PepperPluginInstanceImpl::ExternalDocumentLoader::didFinishLoading(
415 WebURLLoader* loader,
416 double finish_time,
417 int64_t total_encoded_data_length) {
418 DCHECK(!finished_loading_);
420 if (error_.get())
421 return;
423 finished_loading_ = true;
426 void PepperPluginInstanceImpl::ExternalDocumentLoader::didFail(
427 WebURLLoader* loader,
428 const WebURLError& error) {
429 DCHECK(!error_.get());
431 if (finished_loading_)
432 return;
434 error_.reset(new WebURLError(error));
437 PepperPluginInstanceImpl::GamepadImpl::GamepadImpl()
438 : Resource(ppapi::Resource::Untracked()) {}
440 PepperPluginInstanceImpl::GamepadImpl::~GamepadImpl() {}
442 PPB_Gamepad_API* PepperPluginInstanceImpl::GamepadImpl::AsPPB_Gamepad_API() {
443 return this;
446 void PepperPluginInstanceImpl::GamepadImpl::Sample(
447 PP_Instance instance,
448 PP_GamepadsSampleData* data) {
449 blink::WebGamepads webkit_data;
450 RenderThreadImpl::current()->SampleGamepads(&webkit_data);
451 ConvertWebKitGamepadData(bit_cast<ppapi::WebKitGamepads>(webkit_data), data);
454 PepperPluginInstanceImpl::PepperPluginInstanceImpl(
455 RenderFrameImpl* render_frame,
456 PluginModule* module,
457 ppapi::PPP_Instance_Combined* instance_interface,
458 WebPluginContainer* container,
459 const GURL& plugin_url)
460 : RenderFrameObserver(render_frame),
461 render_frame_(render_frame),
462 module_(module),
463 instance_interface_(instance_interface),
464 pp_instance_(0),
465 container_(container),
466 layer_bound_to_fullscreen_(false),
467 layer_is_hardware_(false),
468 plugin_url_(plugin_url),
469 document_url_(container ? GURL(container->element().document().url())
470 : GURL()),
471 is_flash_plugin_(module->name() == kFlashPluginName),
472 has_been_clicked_(false),
473 javascript_used_(false),
474 full_frame_(false),
475 sent_initial_did_change_view_(false),
476 bound_graphics_2d_platform_(NULL),
477 bound_compositor_(NULL),
478 has_webkit_focus_(false),
479 has_content_area_focus_(false),
480 find_identifier_(-1),
481 plugin_find_interface_(NULL),
482 plugin_input_event_interface_(NULL),
483 plugin_mouse_lock_interface_(NULL),
484 plugin_pdf_interface_(NULL),
485 plugin_private_interface_(NULL),
486 plugin_textinput_interface_(NULL),
487 checked_for_plugin_input_event_interface_(false),
488 checked_for_plugin_pdf_interface_(false),
489 gamepad_impl_(new GamepadImpl()),
490 uma_private_impl_(NULL),
491 plugin_print_interface_(NULL),
492 plugin_graphics_3d_interface_(NULL),
493 always_on_top_(false),
494 fullscreen_container_(NULL),
495 flash_fullscreen_(false),
496 desired_fullscreen_state_(false),
497 message_channel_(NULL),
498 sad_plugin_(NULL),
499 input_event_mask_(0),
500 filtered_input_event_mask_(0),
501 text_input_type_(kPluginDefaultTextInputType),
502 text_input_caret_(0, 0, 0, 0),
503 text_input_caret_bounds_(0, 0, 0, 0),
504 text_input_caret_set_(false),
505 selection_caret_(0),
506 selection_anchor_(0),
507 pending_user_gesture_(0.0),
508 document_loader_(NULL),
509 external_document_load_(false),
510 isolate_(v8::Isolate::GetCurrent()),
511 is_deleted_(false),
512 initialized_(false),
513 view_change_weak_ptr_factory_(this),
514 weak_factory_(this) {
515 pp_instance_ = HostGlobals::Get()->AddInstance(this);
517 memset(&current_print_settings_, 0, sizeof(current_print_settings_));
518 module_->InstanceCreated(this);
520 if (render_frame) { // NULL in tests
521 render_frame->render_view()->PepperInstanceCreated(this);
522 // Bind a callback now so that we can inform the RenderViewImpl when we are
523 // destroyed. This works around a temporary problem stemming from work to
524 // move parts of RenderViewImpl in to RenderFrameImpl (see
525 // crbug.com/245126). If destruction happens in this order:
526 // 1) RenderFrameImpl
527 // 2) PepperPluginInstanceImpl
528 // 3) RenderViewImpl
529 // Then after 1), the PepperPluginInstanceImpl doesn't have any way to talk
530 // to the RenderViewImpl. But when the instance is destroyed, it still
531 // needs to inform the RenderViewImpl that it has gone away, otherwise
532 // between (2) and (3), the RenderViewImpl will still have the dead
533 // instance in its active set, and so might make calls on the deleted
534 // instance. See crbug.com/343576 for more information. Once the plugin
535 // calls move entirely from RenderViewImpl in to RenderFrameImpl, this
536 // can be a little bit simplified by instead making a direct call on
537 // RenderFrameImpl in the destructor (but only if render_frame_ is valid).
538 instance_deleted_callback_ =
539 base::Bind(&RenderViewImpl::PepperInstanceDeleted,
540 render_frame->render_view()->AsWeakPtr(),
541 base::Unretained(this));
542 view_data_.is_page_visible = !render_frame_->GetRenderWidget()->is_hidden();
544 // Set the initial focus.
545 SetContentAreaFocus(render_frame_->GetRenderWidget()->has_focus());
547 if (!module_->IsProxied()) {
548 PepperBrowserConnection* browser_connection =
549 PepperBrowserConnection::Get(render_frame_);
550 browser_connection->DidCreateInProcessInstance(
551 pp_instance(),
552 render_frame_->GetRoutingID(),
553 document_url_,
554 GetPluginURL());
558 RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
559 resource_creation_ = host_impl->CreateInProcessResourceCreationAPI(this);
561 if (GetContentClient()->renderer() && // NULL in unit tests.
562 GetContentClient()->renderer()->IsExternalPepperPlugin(module->name()))
563 external_document_load_ = true;
566 PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
567 DCHECK(!fullscreen_container_);
569 // Notify all the plugin objects of deletion. This will prevent blink from
570 // calling into the plugin any more.
572 // Swap out the set so we can delete from it (the objects will try to
573 // unregister themselves inside the delete call).
574 PluginObjectSet plugin_object_copy;
575 live_plugin_objects_.swap(plugin_object_copy);
576 for (PluginObjectSet::iterator i = plugin_object_copy.begin();
577 i != plugin_object_copy.end();
578 ++i) {
579 (*i)->InstanceDeleted();
582 if (message_channel_)
583 message_channel_->InstanceDeleted();
584 message_channel_object_.Reset();
586 if (TrackedCallback::IsPending(lock_mouse_callback_))
587 lock_mouse_callback_->Abort();
589 if (!instance_deleted_callback_.is_null())
590 instance_deleted_callback_.Run();
592 if (!module_->IsProxied() && render_frame_) {
593 PepperBrowserConnection* browser_connection =
594 PepperBrowserConnection::Get(render_frame_);
595 browser_connection->DidDeleteInProcessInstance(pp_instance());
598 UnSetAndDeleteLockTargetAdapter();
599 module_->InstanceDeleted(this);
600 // If we switched from the NaCl plugin module, notify it too.
601 if (original_module_.get())
602 original_module_->InstanceDeleted(this);
604 // This should be last since some of the above "instance deleted" calls will
605 // want to look up in the global map to get info off of our object.
606 HostGlobals::Get()->InstanceDeleted(pp_instance_);
608 if (throttler_)
609 throttler_->RemoveObserver(this);
612 // NOTE: Any of these methods that calls into the plugin needs to take into
613 // account that the plugin may use Var to remove the <embed> from the DOM, which
614 // will make the PepperWebPluginImpl drop its reference, usually the last one.
615 // If a method needs to access a member of the instance after the call has
616 // returned, then it needs to keep its own reference on the stack.
618 v8::Local<v8::Object> PepperPluginInstanceImpl::GetMessageChannelObject() {
619 return v8::Local<v8::Object>::New(isolate_, message_channel_object_);
622 void PepperPluginInstanceImpl::MessageChannelDestroyed() {
623 message_channel_ = NULL;
624 message_channel_object_.Reset();
627 v8::Local<v8::Context> PepperPluginInstanceImpl::GetMainWorldContext() {
628 if (!container_)
629 return v8::Local<v8::Context>();
631 if (container_->element().isNull())
632 return v8::Local<v8::Context>();
634 if (container_->element().document().isNull())
635 return v8::Local<v8::Context>();
637 if (!container_->element().document().frame())
638 return v8::Local<v8::Context>();
640 v8::Local<v8::Context> context =
641 container_->element().document().frame()->mainWorldScriptContext();
642 DCHECK(context->GetIsolate() == isolate_);
643 return context;
646 void PepperPluginInstanceImpl::Delete() {
647 is_deleted_ = true;
649 if (render_frame_ && render_frame_->render_view() &&
650 render_frame_->render_view()->plugin_find_handler() == this) {
651 render_frame_->render_view()->set_plugin_find_handler(NULL);
654 // Keep a reference on the stack. See NOTE above.
655 scoped_refptr<PepperPluginInstanceImpl> ref(this);
657 // It is important to destroy the throttler before anything else.
658 // The plugin instance may flush its graphics pipeline during its postmortem
659 // spasm, causing the throttler to engage and obtain new dangling reference
660 // to the plugin container being destroyed.
661 throttler_.reset();
663 // Force the MessageChannel to release its "passthrough object" which should
664 // release our last reference to the "InstanceObject" and will probably
665 // destroy it. We want to do this prior to calling DidDestroy in case the
666 // destructor of the instance object tries to use the instance.
667 if (message_channel_)
668 message_channel_->SetPassthroughObject(v8::Local<v8::Object>());
669 // If this is a NaCl plugin instance, shut down the NaCl plugin by calling
670 // its DidDestroy. Don't call DidDestroy on the untrusted plugin instance,
671 // since there is little that it can do at this point.
672 if (original_instance_interface_) {
673 base::TimeTicks start = base::TimeTicks::Now();
674 original_instance_interface_->DidDestroy(pp_instance());
675 UMA_HISTOGRAM_CUSTOM_TIMES("NaCl.Perf.ShutdownTime.Total",
676 base::TimeTicks::Now() - start,
677 base::TimeDelta::FromMilliseconds(1),
678 base::TimeDelta::FromSeconds(20),
679 100);
680 } else {
681 instance_interface_->DidDestroy(pp_instance());
683 // Ensure we don't attempt to call functions on the destroyed instance.
684 original_instance_interface_.reset();
685 instance_interface_.reset();
687 if (fullscreen_container_) {
688 fullscreen_container_->Destroy();
689 fullscreen_container_ = NULL;
692 // Force-unbind any Graphics. In the case of Graphics2D, if the plugin
693 // leaks the graphics 2D, it may actually get cleaned up after our
694 // destruction, so we need its pointers to be up-to-date.
695 BindGraphics(pp_instance(), 0);
696 container_ = NULL;
699 bool PepperPluginInstanceImpl::is_deleted() const { return is_deleted_; }
701 void PepperPluginInstanceImpl::Paint(WebCanvas* canvas,
702 const gfx::Rect& plugin_rect,
703 const gfx::Rect& paint_rect) {
704 TRACE_EVENT0("ppapi", "PluginInstance::Paint");
705 if (module()->is_crashed()) {
706 // Crashed plugin painting.
707 if (!sad_plugin_) // Lazily initialize bitmap.
708 sad_plugin_ = GetContentClient()->renderer()->GetSadPluginBitmap();
709 if (sad_plugin_)
710 PaintSadPlugin(canvas, plugin_rect, *sad_plugin_);
711 return;
714 if (bound_graphics_2d_platform_)
715 bound_graphics_2d_platform_->Paint(canvas, plugin_rect, paint_rect);
718 void PepperPluginInstanceImpl::InvalidateRect(const gfx::Rect& rect) {
719 if (fullscreen_container_) {
720 if (rect.IsEmpty())
721 fullscreen_container_->Invalidate();
722 else
723 fullscreen_container_->InvalidateRect(rect);
724 } else {
725 if (!container_ || view_data_.rect.size.width == 0 ||
726 view_data_.rect.size.height == 0)
727 return; // Nothing to do.
728 if (rect.IsEmpty())
729 container_->invalidate();
730 else
731 container_->invalidateRect(rect);
734 cc::Layer* layer =
735 texture_layer_.get() ? texture_layer_.get() : compositor_layer_.get();
736 if (layer) {
737 if (rect.IsEmpty()) {
738 layer->SetNeedsDisplay();
739 } else {
740 layer->SetNeedsDisplayRect(rect);
745 void PepperPluginInstanceImpl::ScrollRect(int dx,
746 int dy,
747 const gfx::Rect& rect) {
748 cc::Layer* layer =
749 texture_layer_.get() ? texture_layer_.get() : compositor_layer_.get();
750 if (layer) {
751 InvalidateRect(rect);
752 } else if (fullscreen_container_) {
753 fullscreen_container_->ScrollRect(dx, dy, rect);
754 } else {
755 if (full_frame_ && !IsViewAccelerated()) {
756 container_->scrollRect(rect);
757 } else {
758 // Can't do optimized scrolling since there could be other elements on top
759 // of us or the view renders via the accelerated compositor which is
760 // incompatible with the move and backfill scrolling model.
761 InvalidateRect(rect);
766 void PepperPluginInstanceImpl::CommitBackingTexture() {
767 if (!texture_layer_.get())
768 return;
769 gpu::Mailbox mailbox;
770 uint32 sync_point = 0;
771 bound_graphics_3d_->GetBackingMailbox(&mailbox, &sync_point);
772 DCHECK(!mailbox.IsZero());
773 DCHECK_NE(sync_point, 0u);
774 texture_layer_->SetTextureMailboxWithoutReleaseCallback(
775 cc::TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point));
776 texture_layer_->SetNeedsDisplay();
779 void PepperPluginInstanceImpl::InstanceCrashed() {
780 // Force free all resources and vars.
781 HostGlobals::Get()->InstanceCrashed(pp_instance());
783 // Free any associated graphics.
784 SetFullscreen(false);
785 FlashSetFullscreen(false, false);
786 // Unbind current 2D or 3D graphics context.
787 BindGraphics(pp_instance(), 0);
788 InvalidateRect(gfx::Rect());
790 if (content_decryptor_delegate_) {
791 content_decryptor_delegate_->InstanceCrashed();
792 content_decryptor_delegate_.reset();
795 if (render_frame_)
796 render_frame_->PluginCrashed(module_->path(), module_->GetPeerProcessId());
797 UnSetAndDeleteLockTargetAdapter();
800 bool PepperPluginInstanceImpl::Initialize(
801 const std::vector<std::string>& arg_names,
802 const std::vector<std::string>& arg_values,
803 bool full_frame,
804 scoped_ptr<PluginInstanceThrottlerImpl> throttler) {
805 DCHECK(!throttler_);
807 if (!render_frame_)
808 return false;
810 if (throttler) {
811 throttler_ = throttler.Pass();
812 throttler_->AddObserver(this);
815 message_channel_ = MessageChannel::Create(this, &message_channel_object_);
817 full_frame_ = full_frame;
819 UpdateTouchEventRequest();
820 container_->setWantsWheelEvents(IsAcceptingWheelEvents());
822 SetGPUHistogram(ppapi::Preferences(PpapiPreferencesBuilder::Build(
823 render_frame_->render_view()->webkit_preferences())),
824 arg_names,
825 arg_values);
827 argn_ = arg_names;
828 argv_ = arg_values;
829 scoped_ptr<const char * []> argn_array(StringVectorToArgArray(argn_));
830 scoped_ptr<const char * []> argv_array(StringVectorToArgArray(argv_));
831 auto weak_this = weak_factory_.GetWeakPtr();
832 bool success = PP_ToBool(instance_interface_->DidCreate(
833 pp_instance(), argn_.size(), argn_array.get(), argv_array.get()));
834 if (!weak_this) {
835 // The plugin may do synchronous scripting during "DidCreate", so |this|
836 // may be deleted. In that case, return failure and don't touch any
837 // member variables.
838 return false;
840 // If this is a plugin that hosts external plugins, we should delay messages
841 // so that the child plugin that's created later will receive all the
842 // messages. (E.g., NaCl trusted plugin starting a child NaCl app.)
844 // A host for external plugins will call ResetAsProxied later, at which point
845 // we can Start() the MessageChannel.
846 if (success && (!module_->renderer_ppapi_host()->IsExternalPluginHost())) {
847 if (message_channel_)
848 message_channel_->Start();
850 initialized_ = success;
851 return success;
854 bool PepperPluginInstanceImpl::HandleDocumentLoad(
855 const blink::WebURLResponse& response) {
856 DCHECK(!document_loader_);
857 if (external_document_load_) {
858 // The external proxy isn't available, so save the response and record
859 // document load notifications for later replay.
860 external_document_response_ = response;
861 external_document_loader_.reset(new ExternalDocumentLoader());
862 document_loader_ = external_document_loader_.get();
863 return true;
866 if (module()->is_crashed()) {
867 // Don't create a resource for a crashed plugin.
868 container()->element().document().frame()->stopLoading();
869 return false;
872 DCHECK(!document_loader_);
874 // Create a loader resource host for this load. Note that we have to set
875 // the document_loader before issuing the in-process
876 // PPP_Instance.HandleDocumentLoad call below, since this may reentrantly
877 // call into the instance and expect it to be valid.
878 RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
879 PepperURLLoaderHost* loader_host =
880 new PepperURLLoaderHost(host_impl, true, pp_instance(), 0);
881 // TODO(teravest): Remove set_document_loader() from instance and clean up
882 // this relationship.
883 set_document_loader(loader_host);
884 loader_host->didReceiveResponse(NULL, response);
886 // This host will be pending until the resource object attaches to it.
888 // PpapiHost now owns the pointer to loader_host, so we don't have to worry
889 // about managing it.
890 int pending_host_id = host_impl->GetPpapiHost()->AddPendingResourceHost(
891 scoped_ptr<ppapi::host::ResourceHost>(loader_host));
892 DCHECK(pending_host_id);
894 DataFromWebURLResponse(
895 host_impl,
896 pp_instance(),
897 response,
898 base::Bind(&PepperPluginInstanceImpl::DidDataFromWebURLResponse,
899 weak_factory_.GetWeakPtr(),
900 response,
901 pending_host_id));
903 // If the load was not abandoned, document_loader_ will now be set. It's
904 // possible that the load was canceled by now and document_loader_ was
905 // already nulled out.
906 return true;
909 bool PepperPluginInstanceImpl::SendCompositionEventToPlugin(
910 PP_InputEvent_Type type,
911 const base::string16& text) {
912 std::vector<blink::WebCompositionUnderline> empty;
913 return SendCompositionEventWithUnderlineInformationToPlugin(
914 type,
915 text,
916 empty,
917 static_cast<int>(text.size()),
918 static_cast<int>(text.size()));
921 bool
922 PepperPluginInstanceImpl::SendCompositionEventWithUnderlineInformationToPlugin(
923 PP_InputEvent_Type type,
924 const base::string16& text,
925 const std::vector<blink::WebCompositionUnderline>& underlines,
926 int selection_start,
927 int selection_end) {
928 // Keep a reference on the stack. See NOTE above.
929 scoped_refptr<PepperPluginInstanceImpl> ref(this);
931 if (!LoadInputEventInterface())
932 return false;
934 PP_InputEvent_Class event_class = PP_INPUTEVENT_CLASS_IME;
935 if (!(filtered_input_event_mask_ & event_class) &&
936 !(input_event_mask_ & event_class))
937 return false;
939 ppapi::InputEventData event;
940 event.event_type = type;
941 event.event_time_stamp =
942 ppapi::TimeTicksToPPTimeTicks(base::TimeTicks::Now());
944 // Convert UTF16 text to UTF8 with offset conversion.
945 std::vector<size_t> utf16_offsets;
946 utf16_offsets.push_back(selection_start);
947 utf16_offsets.push_back(selection_end);
948 for (size_t i = 0; i < underlines.size(); ++i) {
949 utf16_offsets.push_back(underlines[i].startOffset);
950 utf16_offsets.push_back(underlines[i].endOffset);
952 std::vector<size_t> utf8_offsets(utf16_offsets);
953 event.character_text = base::UTF16ToUTF8AndAdjustOffsets(text, &utf8_offsets);
955 // Set the converted selection range.
956 event.composition_selection_start =
957 (utf8_offsets[0] == std::string::npos ? event.character_text.size()
958 : utf8_offsets[0]);
959 event.composition_selection_end =
960 (utf8_offsets[1] == std::string::npos ? event.character_text.size()
961 : utf8_offsets[1]);
963 // Set the converted segmentation points.
964 // Be sure to add 0 and size(), and remove duplication or errors.
965 std::set<size_t> offset_set(utf8_offsets.begin() + 2, utf8_offsets.end());
966 offset_set.insert(0);
967 offset_set.insert(event.character_text.size());
968 offset_set.erase(std::string::npos);
969 event.composition_segment_offsets.assign(offset_set.begin(),
970 offset_set.end());
972 // Set the composition target.
973 for (size_t i = 0; i < underlines.size(); ++i) {
974 if (underlines[i].thick) {
975 std::vector<uint32_t>::iterator it =
976 std::find(event.composition_segment_offsets.begin(),
977 event.composition_segment_offsets.end(),
978 utf8_offsets[2 * i + 2]);
979 if (it != event.composition_segment_offsets.end()) {
980 event.composition_target_segment =
981 it - event.composition_segment_offsets.begin();
982 break;
987 // Send the event.
988 bool handled = false;
989 if (filtered_input_event_mask_ & event_class)
990 event.is_filtered = true;
991 else
992 handled = true; // Unfiltered events are assumed to be handled.
993 scoped_refptr<PPB_InputEvent_Shared> event_resource(
994 new PPB_InputEvent_Shared(ppapi::OBJECT_IS_IMPL, pp_instance(), event));
995 handled |= PP_ToBool(plugin_input_event_interface_->HandleInputEvent(
996 pp_instance(), event_resource->pp_resource()));
997 return handled;
1000 void PepperPluginInstanceImpl::RequestInputEventsHelper(
1001 uint32_t event_classes) {
1002 if (event_classes & PP_INPUTEVENT_CLASS_TOUCH)
1003 UpdateTouchEventRequest();
1004 if (event_classes & PP_INPUTEVENT_CLASS_WHEEL)
1005 container_->setWantsWheelEvents(IsAcceptingWheelEvents());
1008 bool PepperPluginInstanceImpl::HandleCompositionStart(
1009 const base::string16& text) {
1010 return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_COMPOSITION_START,
1011 text);
1014 bool PepperPluginInstanceImpl::HandleCompositionUpdate(
1015 const base::string16& text,
1016 const std::vector<blink::WebCompositionUnderline>& underlines,
1017 int selection_start,
1018 int selection_end) {
1019 return SendCompositionEventWithUnderlineInformationToPlugin(
1020 PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE,
1021 text,
1022 underlines,
1023 selection_start,
1024 selection_end);
1027 bool PepperPluginInstanceImpl::HandleCompositionEnd(
1028 const base::string16& text) {
1029 return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_COMPOSITION_END,
1030 text);
1033 bool PepperPluginInstanceImpl::HandleTextInput(const base::string16& text) {
1034 return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_TEXT, text);
1037 void PepperPluginInstanceImpl::GetSurroundingText(base::string16* text,
1038 gfx::Range* range) const {
1039 std::vector<size_t> offsets;
1040 offsets.push_back(selection_anchor_);
1041 offsets.push_back(selection_caret_);
1042 *text = base::UTF8ToUTF16AndAdjustOffsets(surrounding_text_, &offsets);
1043 range->set_start(offsets[0] == base::string16::npos ? text->size()
1044 : offsets[0]);
1045 range->set_end(offsets[1] == base::string16::npos ? text->size()
1046 : offsets[1]);
1049 bool PepperPluginInstanceImpl::IsPluginAcceptingCompositionEvents() const {
1050 return (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_IME) ||
1051 (input_event_mask_ & PP_INPUTEVENT_CLASS_IME);
1054 gfx::Rect PepperPluginInstanceImpl::GetCaretBounds() const {
1055 if (!text_input_caret_set_) {
1056 // If it is never set by the plugin, use the bottom left corner.
1057 return gfx::Rect(view_data_.rect.point.x,
1058 view_data_.rect.point.y + view_data_.rect.size.height,
1063 // TODO(kinaba) Take CSS transformation into accont.
1064 // TODO(kinaba) Take bounding_box into account. On some platforms, an
1065 // "exclude rectangle" where candidate window must avoid the region can be
1066 // passed to IME. Currently, we pass only the caret rectangle because
1067 // it is the only information supported uniformly in Chromium.
1068 gfx::Rect caret(text_input_caret_);
1069 caret.Offset(view_data_.rect.point.x, view_data_.rect.point.y);
1070 return caret;
1073 bool PepperPluginInstanceImpl::HandleInputEvent(
1074 const blink::WebInputEvent& event,
1075 WebCursorInfo* cursor_info) {
1076 TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleInputEvent");
1078 if (!has_been_clicked_ && is_flash_plugin_ &&
1079 event.type == blink::WebInputEvent::MouseDown &&
1080 (event.modifiers & blink::WebInputEvent::LeftButtonDown)) {
1081 has_been_clicked_ = true;
1082 blink::WebRect bounds = container()->element().boundsInViewportSpace();
1083 RecordFlashClickSizeMetric(bounds.width, bounds.height);
1086 if (throttler_ && throttler_->ConsumeInputEvent(event))
1087 return true;
1089 if (!render_frame_)
1090 return false;
1091 if (WebInputEvent::isMouseEventType(event.type)) {
1092 render_frame_->PepperDidReceiveMouseEvent(this);
1095 // Don't dispatch input events to crashed plugins.
1096 if (module()->is_crashed())
1097 return false;
1099 // Don't send reserved system key events to plugins.
1100 if (IsReservedSystemInputEvent(event))
1101 return false;
1103 // Keep a reference on the stack. See NOTE above.
1104 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1106 bool rv = false;
1107 if (LoadInputEventInterface()) {
1108 PP_InputEvent_Class event_class = ClassifyInputEvent(event.type);
1109 if (!event_class)
1110 return false;
1112 if ((filtered_input_event_mask_ & event_class) ||
1113 (input_event_mask_ & event_class)) {
1114 // Actually send the event.
1115 std::vector<ppapi::InputEventData> events;
1116 CreateInputEventData(event, &events);
1118 // Allow the user gesture to be pending after the plugin handles the
1119 // event. This allows out-of-process plugins to respond to the user
1120 // gesture after processing has finished here.
1121 if (WebUserGestureIndicator::isProcessingUserGesture()) {
1122 pending_user_gesture_ =
1123 ppapi::EventTimeToPPTimeTicks(event.timeStampSeconds);
1124 pending_user_gesture_token_ =
1125 WebUserGestureIndicator::currentUserGestureToken();
1126 pending_user_gesture_token_.setOutOfProcess();
1129 // Each input event may generate more than one PP_InputEvent.
1130 for (size_t i = 0; i < events.size(); i++) {
1131 if (filtered_input_event_mask_ & event_class)
1132 events[i].is_filtered = true;
1133 else
1134 rv = true; // Unfiltered events are assumed to be handled.
1135 scoped_refptr<PPB_InputEvent_Shared> event_resource(
1136 new PPB_InputEvent_Shared(
1137 ppapi::OBJECT_IS_IMPL, pp_instance(), events[i]));
1139 rv |= PP_ToBool(plugin_input_event_interface_->HandleInputEvent(
1140 pp_instance(), event_resource->pp_resource()));
1145 if (cursor_)
1146 *cursor_info = *cursor_;
1147 return rv;
1150 void PepperPluginInstanceImpl::HandleMessage(ScopedPPVar message) {
1151 TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleMessage");
1152 if (is_deleted_)
1153 return;
1154 ppapi::proxy::HostDispatcher* dispatcher =
1155 ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
1156 if (!dispatcher || (message.get().type == PP_VARTYPE_OBJECT)) {
1157 // The dispatcher should always be valid, and MessageChannel should never
1158 // send an 'object' var over PPP_Messaging.
1159 NOTREACHED();
1160 return;
1162 dispatcher->Send(new PpapiMsg_PPPMessaging_HandleMessage(
1163 ppapi::API_ID_PPP_MESSAGING,
1164 pp_instance(),
1165 ppapi::proxy::SerializedVarSendInputShmem(dispatcher, message.get(),
1166 pp_instance())));
1169 bool PepperPluginInstanceImpl::HandleBlockingMessage(ScopedPPVar message,
1170 ScopedPPVar* result) {
1171 TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleBlockingMessage");
1172 if (is_deleted_)
1173 return false;
1174 ppapi::proxy::HostDispatcher* dispatcher =
1175 ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
1176 if (!dispatcher || (message.get().type == PP_VARTYPE_OBJECT)) {
1177 // The dispatcher should always be valid, and MessageChannel should never
1178 // send an 'object' var over PPP_Messaging.
1179 NOTREACHED();
1180 return false;
1182 ppapi::proxy::ReceiveSerializedVarReturnValue msg_reply;
1183 bool was_handled = false;
1184 dispatcher->Send(new PpapiMsg_PPPMessageHandler_HandleBlockingMessage(
1185 ppapi::API_ID_PPP_MESSAGING,
1186 pp_instance(),
1187 ppapi::proxy::SerializedVarSendInputShmem(dispatcher, message.get(),
1188 pp_instance()),
1189 &msg_reply,
1190 &was_handled));
1191 *result = ScopedPPVar(ScopedPPVar::PassRef(), msg_reply.Return(dispatcher));
1192 TRACE_EVENT0("ppapi",
1193 "PepperPluginInstanceImpl::HandleBlockingMessage return.");
1194 return was_handled;
1197 PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) {
1198 // Keep a reference on the stack. See NOTE above.
1199 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1201 DCHECK_EQ(isolate, isolate_);
1202 RecordFlashJavaScriptUse();
1204 // If the plugin supports the private instance interface, try to retrieve its
1205 // instance object.
1206 if (LoadPrivateInterface())
1207 return plugin_private_interface_->GetInstanceObject(pp_instance());
1208 return PP_MakeUndefined();
1211 void PepperPluginInstanceImpl::ViewChanged(
1212 const gfx::Rect& window,
1213 const gfx::Rect& clip,
1214 const gfx::Rect& unobscured,
1215 const std::vector<gfx::Rect>& cut_outs_rects) {
1216 // WebKit can give weird (x,y) positions for empty clip rects (since the
1217 // position technically doesn't matter). But we want to make these
1218 // consistent since this is given to the plugin, so force everything to 0
1219 // in the "everything is clipped" case.
1220 gfx::Rect new_clip;
1221 if (!clip.IsEmpty())
1222 new_clip = clip;
1224 unobscured_rect_ = unobscured;
1226 cut_outs_rects_ = cut_outs_rects;
1228 view_data_.rect = PP_FromGfxRect(window);
1229 view_data_.clip_rect = PP_FromGfxRect(clip);
1230 view_data_.device_scale = container_->deviceScaleFactor();
1231 view_data_.css_scale =
1232 container_->pageZoomFactor() * container_->pageScaleFactor();
1234 gfx::Size scroll_offset =
1235 container_->element().document().frame()->scrollOffset();
1236 view_data_.scroll_offset = PP_MakePoint(scroll_offset.width(),
1237 scroll_offset.height());
1239 if (desired_fullscreen_state_ || view_data_.is_fullscreen) {
1240 WebElement element = container_->element();
1241 WebDocument document = element.document();
1242 bool is_fullscreen_element = (element == document.fullScreenElement());
1243 if (!view_data_.is_fullscreen && desired_fullscreen_state_ &&
1244 render_frame()->GetRenderWidget()->is_fullscreen_granted() &&
1245 is_fullscreen_element) {
1246 // Entered fullscreen. Only possible via SetFullscreen().
1247 view_data_.is_fullscreen = true;
1248 } else if (view_data_.is_fullscreen && !is_fullscreen_element) {
1249 // Exited fullscreen. Possible via SetFullscreen() or F11/link,
1250 // so desired_fullscreen_state might be out-of-date.
1251 desired_fullscreen_state_ = false;
1252 view_data_.is_fullscreen = false;
1254 // This operation will cause the plugin to re-layout which will send more
1255 // DidChangeView updates. Schedule an asynchronous update and suppress
1256 // notifications until that completes to avoid sending intermediate sizes
1257 // to the plugins.
1258 ScheduleAsyncDidChangeView();
1260 // Reset the size attributes that we hacked to fill in the screen and
1261 // retrigger ViewChanged. Make sure we don't forward duplicates of
1262 // this view to the plugin.
1263 ResetSizeAttributesAfterFullscreen();
1264 return;
1268 UpdateFlashFullscreenState(fullscreen_container_ != NULL);
1270 // During plugin initialization, there are often re-layouts. Avoid sending
1271 // intermediate sizes the plugin and throttler.
1272 if (sent_initial_did_change_view_)
1273 SendDidChangeView();
1274 else
1275 ScheduleAsyncDidChangeView();
1278 void PepperPluginInstanceImpl::SetWebKitFocus(bool has_focus) {
1279 if (has_webkit_focus_ == has_focus)
1280 return;
1282 bool old_plugin_focus = PluginHasFocus();
1283 has_webkit_focus_ = has_focus;
1284 if (PluginHasFocus() != old_plugin_focus)
1285 SendFocusChangeNotification();
1288 void PepperPluginInstanceImpl::SetContentAreaFocus(bool has_focus) {
1289 if (has_content_area_focus_ == has_focus)
1290 return;
1292 bool old_plugin_focus = PluginHasFocus();
1293 has_content_area_focus_ = has_focus;
1294 if (PluginHasFocus() != old_plugin_focus)
1295 SendFocusChangeNotification();
1298 void PepperPluginInstanceImpl::PageVisibilityChanged(bool is_visible) {
1299 if (is_visible == view_data_.is_page_visible)
1300 return; // Nothing to do.
1301 view_data_.is_page_visible = is_visible;
1303 // If the initial DidChangeView notification hasn't been sent to the plugin,
1304 // let it pass the visibility state for us, instead of sending a notification
1305 // immediately. It is possible that PepperPluginInstanceImpl::ViewChanged()
1306 // hasn't been called for the first time. In that case, most of the fields in
1307 // |view_data_| haven't been properly initialized.
1308 if (sent_initial_did_change_view_)
1309 SendDidChangeView();
1312 void PepperPluginInstanceImpl::ViewInitiatedPaint() {
1313 if (bound_graphics_2d_platform_)
1314 bound_graphics_2d_platform_->ViewInitiatedPaint();
1315 else if (bound_graphics_3d_.get())
1316 bound_graphics_3d_->ViewInitiatedPaint();
1317 else if (bound_compositor_)
1318 bound_compositor_->ViewInitiatedPaint();
1321 void PepperPluginInstanceImpl::SetSelectedText(
1322 const base::string16& selected_text) {
1323 selected_text_ = selected_text;
1324 gfx::Range range(0, selected_text.length());
1325 render_frame_->SetSelectedText(selected_text, 0, range);
1328 void PepperPluginInstanceImpl::SetLinkUnderCursor(const std::string& url) {
1329 link_under_cursor_ = base::UTF8ToUTF16(url);
1332 void PepperPluginInstanceImpl::SetTextInputType(ui::TextInputType type) {
1333 text_input_type_ = type;
1334 render_frame_->PepperTextInputTypeChanged(this);
1337 void PepperPluginInstanceImpl::PostMessageToJavaScript(PP_Var message) {
1338 if (message_channel_)
1339 message_channel_->PostMessageToJavaScript(message);
1342 int32_t PepperPluginInstanceImpl::RegisterMessageHandler(
1343 PP_Instance instance,
1344 void* user_data,
1345 const PPP_MessageHandler_0_2* handler,
1346 PP_Resource message_loop) {
1347 // Not supported in-process.
1348 NOTIMPLEMENTED();
1349 return PP_ERROR_FAILED;
1352 void PepperPluginInstanceImpl::UnregisterMessageHandler(PP_Instance instance) {
1353 // Not supported in-process.
1354 NOTIMPLEMENTED();
1357 base::string16 PepperPluginInstanceImpl::GetSelectedText(bool html) {
1358 return selected_text_;
1361 base::string16 PepperPluginInstanceImpl::GetLinkAtPosition(
1362 const gfx::Point& point) {
1363 // Keep a reference on the stack. See NOTE above.
1364 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1365 if (!LoadPdfInterface()) {
1366 // TODO(koz): Change the containing function to GetLinkUnderCursor(). We can
1367 // return |link_under_cursor_| here because this is only ever called with
1368 // the current mouse coordinates.
1369 return link_under_cursor_;
1372 PP_Point p;
1373 p.x = point.x();
1374 p.y = point.y();
1375 PP_Var rv = plugin_pdf_interface_->GetLinkAtPosition(pp_instance(), p);
1376 // If the plugin returns undefined for this function it has switched to
1377 // providing us with the link under the cursor eagerly.
1378 if (rv.type == PP_VARTYPE_UNDEFINED)
1379 return link_under_cursor_;
1380 StringVar* string = StringVar::FromPPVar(rv);
1381 base::string16 link;
1382 if (string)
1383 link = base::UTF8ToUTF16(string->value());
1384 // Release the ref the plugin transfered to us.
1385 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(rv);
1386 return link;
1389 void PepperPluginInstanceImpl::RequestSurroundingText(
1390 size_t desired_number_of_characters) {
1391 // Keep a reference on the stack. See NOTE above.
1392 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1393 if (!LoadTextInputInterface())
1394 return;
1395 plugin_textinput_interface_->RequestSurroundingText(
1396 pp_instance(), desired_number_of_characters);
1399 bool PepperPluginInstanceImpl::StartFind(const base::string16& search_text,
1400 bool case_sensitive,
1401 int identifier) {
1402 // Keep a reference on the stack. See NOTE above.
1403 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1404 if (!LoadFindInterface())
1405 return false;
1406 find_identifier_ = identifier;
1407 return PP_ToBool(
1408 plugin_find_interface_->StartFind(pp_instance(),
1409 base::UTF16ToUTF8(search_text).c_str(),
1410 PP_FromBool(case_sensitive)));
1413 void PepperPluginInstanceImpl::SelectFindResult(bool forward) {
1414 // Keep a reference on the stack. See NOTE above.
1415 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1416 if (LoadFindInterface())
1417 plugin_find_interface_->SelectFindResult(pp_instance(),
1418 PP_FromBool(forward));
1421 void PepperPluginInstanceImpl::StopFind() {
1422 // Keep a reference on the stack. See NOTE above.
1423 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1424 if (!LoadFindInterface())
1425 return;
1426 find_identifier_ = -1;
1427 plugin_find_interface_->StopFind(pp_instance());
1430 bool PepperPluginInstanceImpl::LoadFindInterface() {
1431 if (!module_->permissions().HasPermission(ppapi::PERMISSION_PRIVATE))
1432 return false;
1433 if (!plugin_find_interface_) {
1434 plugin_find_interface_ = static_cast<const PPP_Find_Private*>(
1435 module_->GetPluginInterface(PPP_FIND_PRIVATE_INTERFACE));
1438 return !!plugin_find_interface_;
1441 bool PepperPluginInstanceImpl::LoadInputEventInterface() {
1442 if (!checked_for_plugin_input_event_interface_) {
1443 checked_for_plugin_input_event_interface_ = true;
1444 plugin_input_event_interface_ = static_cast<const PPP_InputEvent*>(
1445 module_->GetPluginInterface(PPP_INPUT_EVENT_INTERFACE));
1447 return !!plugin_input_event_interface_;
1450 bool PepperPluginInstanceImpl::LoadMouseLockInterface() {
1451 if (!plugin_mouse_lock_interface_) {
1452 plugin_mouse_lock_interface_ = static_cast<const PPP_MouseLock*>(
1453 module_->GetPluginInterface(PPP_MOUSELOCK_INTERFACE));
1456 return !!plugin_mouse_lock_interface_;
1459 bool PepperPluginInstanceImpl::LoadPdfInterface() {
1460 if (!checked_for_plugin_pdf_interface_) {
1461 checked_for_plugin_pdf_interface_ = true;
1462 plugin_pdf_interface_ = static_cast<const PPP_Pdf*>(
1463 module_->GetPluginInterface(PPP_PDF_INTERFACE_1));
1466 return !!plugin_pdf_interface_;
1469 bool PepperPluginInstanceImpl::LoadPrintInterface() {
1470 // Only check for the interface if the plugin has dev permission.
1471 if (!module_->permissions().HasPermission(ppapi::PERMISSION_DEV))
1472 return false;
1473 if (!plugin_print_interface_) {
1474 plugin_print_interface_ = static_cast<const PPP_Printing_Dev*>(
1475 module_->GetPluginInterface(PPP_PRINTING_DEV_INTERFACE));
1477 return !!plugin_print_interface_;
1480 bool PepperPluginInstanceImpl::LoadPrivateInterface() {
1481 // If this is a NaCl app, we want to talk to the trusted NaCl plugin to
1482 // call GetInstanceObject. This is necessary to ensure that the properties
1483 // the trusted plugin exposes (readyState and lastError) work properly. Note
1484 // that untrusted NaCl apps are not allowed to provide PPP_InstancePrivate,
1485 // so it's correct to never look up PPP_InstancePrivate for them.
1487 // If this is *not* a NaCl plugin, original_module_ will never be set; we talk
1488 // to the "real" module.
1489 scoped_refptr<PluginModule> module =
1490 original_module_.get() ? original_module_ : module_;
1491 // Only check for the interface if the plugin has private permission.
1492 if (!module->permissions().HasPermission(ppapi::PERMISSION_PRIVATE))
1493 return false;
1494 if (!plugin_private_interface_) {
1495 plugin_private_interface_ = static_cast<const PPP_Instance_Private*>(
1496 module->GetPluginInterface(PPP_INSTANCE_PRIVATE_INTERFACE));
1499 return !!plugin_private_interface_;
1502 bool PepperPluginInstanceImpl::LoadTextInputInterface() {
1503 if (!plugin_textinput_interface_) {
1504 plugin_textinput_interface_ = static_cast<const PPP_TextInput_Dev*>(
1505 module_->GetPluginInterface(PPP_TEXTINPUT_DEV_INTERFACE));
1508 return !!plugin_textinput_interface_;
1511 void PepperPluginInstanceImpl::UpdateLayerTransform() {
1512 if (!bound_graphics_2d_platform_ || !texture_layer_.get()) {
1513 // Currently the transform is only applied for Graphics2D.
1514 return;
1516 // Set the UV coordinates of the texture based on the size of the Graphics2D
1517 // context. By default a texture gets scaled to the size of the layer. But
1518 // if the size of the Graphics2D context doesn't match the size of the plugin
1519 // then it will be incorrectly stretched. This also affects how the plugin
1520 // is painted when it is being resized. If the Graphics2D contents are
1521 // stretched when a plugin is resized while waiting for a new frame from the
1522 // plugin to be rendered, then flickering behavior occurs as in
1523 // crbug.com/353453.
1524 gfx::SizeF graphics_2d_size_in_dip =
1525 gfx::ScaleSize(bound_graphics_2d_platform_->Size(),
1526 bound_graphics_2d_platform_->GetScale());
1527 gfx::Size plugin_size_in_dip(view_data_.rect.size.width,
1528 view_data_.rect.size.height);
1530 texture_layer_->SetUV(
1531 gfx::PointF(0.0f, 0.0f),
1532 gfx::PointF(
1533 plugin_size_in_dip.width() / graphics_2d_size_in_dip.width(),
1534 plugin_size_in_dip.height() / graphics_2d_size_in_dip.height()));
1537 bool PepperPluginInstanceImpl::PluginHasFocus() const {
1538 return flash_fullscreen_ || (has_webkit_focus_ && has_content_area_focus_);
1541 void PepperPluginInstanceImpl::SendFocusChangeNotification() {
1542 // Keep a reference on the stack. RenderViewImpl::PepperFocusChanged may
1543 // remove the <embed> from the DOM, which will make the PepperWebPluginImpl
1544 // drop its reference, usually the last one. This is similar to possible
1545 // plugin behavior described at the NOTE above Delete().
1546 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1548 if (!render_frame_)
1549 return;
1551 bool has_focus = PluginHasFocus();
1552 render_frame_->render_view()->PepperFocusChanged(this, has_focus);
1554 // instance_interface_ may have been cleared in Delete() if the
1555 // PepperWebPluginImpl is destroyed.
1556 if (instance_interface_)
1557 instance_interface_->DidChangeFocus(pp_instance(), PP_FromBool(has_focus));
1560 void PepperPluginInstanceImpl::UpdateTouchEventRequest() {
1561 bool raw_touch = (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_TOUCH) ||
1562 (input_event_mask_ & PP_INPUTEVENT_CLASS_TOUCH);
1563 container_->requestTouchEventType(
1564 raw_touch
1565 ? blink::WebPluginContainer::TouchEventRequestTypeRaw
1566 : blink::WebPluginContainer::TouchEventRequestTypeSynthesizedMouse);
1569 bool PepperPluginInstanceImpl::IsAcceptingWheelEvents() const {
1570 return (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_WHEEL) ||
1571 (input_event_mask_ & PP_INPUTEVENT_CLASS_WHEEL);
1574 void PepperPluginInstanceImpl::ScheduleAsyncDidChangeView() {
1575 if (view_change_weak_ptr_factory_.HasWeakPtrs())
1576 return; // Already scheduled.
1577 base::ThreadTaskRunnerHandle::Get()->PostTask(
1578 FROM_HERE, base::Bind(&PepperPluginInstanceImpl::SendAsyncDidChangeView,
1579 view_change_weak_ptr_factory_.GetWeakPtr()));
1582 void PepperPluginInstanceImpl::SendAsyncDidChangeView() {
1583 // The bound callback that owns the weak pointer is still valid until after
1584 // this function returns. SendDidChangeView checks HasWeakPtrs, so we need to
1585 // invalidate them here.
1586 // NOTE: If we ever want to have more than one pending callback, it should
1587 // use a different factory, or we should have a different strategy here.
1588 view_change_weak_ptr_factory_.InvalidateWeakPtrs();
1589 SendDidChangeView();
1592 void PepperPluginInstanceImpl::SendDidChangeView() {
1593 // An asynchronous view update is scheduled. Skip sending this update.
1594 if (view_change_weak_ptr_factory_.HasWeakPtrs())
1595 return;
1597 // Don't send DidChangeView to crashed plugins.
1598 if (module()->is_crashed())
1599 return;
1601 // During the first view update, initialize the throttler.
1602 if (!sent_initial_did_change_view_) {
1603 if (is_flash_plugin_ && RenderThread::Get()) {
1604 RenderThread::Get()->RecordAction(
1605 base::UserMetricsAction("Flash.PluginInstanceCreated"));
1606 RecordFlashSizeMetric(unobscured_rect_.width(),
1607 unobscured_rect_.height());
1610 if (throttler_) {
1611 throttler_->Initialize(render_frame_, plugin_url_.GetOrigin(),
1612 module()->name(), unobscured_rect_.size());
1616 ppapi::ViewData view_data = view_data_;
1618 // When plugin content is throttled, fake the page being offscreen. We cannot
1619 // send empty view data here, as some plugins rely on accurate view data.
1620 if (throttler_ && throttler_->IsThrottled()) {
1621 view_data.is_page_visible = false;
1622 view_data.clip_rect.point.x = 0;
1623 view_data.clip_rect.point.y = 0;
1624 view_data.clip_rect.size.width = 0;
1625 view_data.clip_rect.size.height = 0;
1628 if (sent_initial_did_change_view_ && last_sent_view_data_.Equals(view_data))
1629 return; // Nothing to update.
1631 sent_initial_did_change_view_ = true;
1632 last_sent_view_data_ = view_data;
1633 ScopedPPResource resource(
1634 ScopedPPResource::PassRef(),
1635 (new PPB_View_Shared(ppapi::OBJECT_IS_IMPL, pp_instance(), view_data))
1636 ->GetReference());
1638 UpdateLayerTransform();
1640 if (bound_graphics_2d_platform_ &&
1641 (!view_data.is_page_visible ||
1642 PP_ToGfxRect(view_data.clip_rect).IsEmpty())) {
1643 bound_graphics_2d_platform_->ClearCache();
1646 // It's possible that Delete() has been called but the renderer hasn't
1647 // released its reference to this object yet.
1648 if (instance_interface_) {
1649 instance_interface_->DidChangeView(
1650 pp_instance(), resource, &view_data.rect, &view_data.clip_rect);
1654 void PepperPluginInstanceImpl::ReportGeometry() {
1655 // If this call was delayed, we may have transitioned back to fullscreen in
1656 // the mean time, so only report the geometry if we are actually in normal
1657 // mode.
1658 if (container_ && !fullscreen_container_ && !flash_fullscreen_)
1659 container_->reportGeometry();
1662 bool PepperPluginInstanceImpl::GetPreferredPrintOutputFormat(
1663 PP_PrintOutputFormat_Dev* format) {
1664 // Keep a reference on the stack. See NOTE above.
1665 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1666 if (!LoadPrintInterface())
1667 return false;
1668 uint32_t supported_formats =
1669 plugin_print_interface_->QuerySupportedFormats(pp_instance());
1670 if (supported_formats & PP_PRINTOUTPUTFORMAT_PDF) {
1671 *format = PP_PRINTOUTPUTFORMAT_PDF;
1672 return true;
1674 return false;
1677 bool PepperPluginInstanceImpl::SupportsPrintInterface() {
1678 PP_PrintOutputFormat_Dev format;
1679 return GetPreferredPrintOutputFormat(&format);
1682 bool PepperPluginInstanceImpl::IsPrintScalingDisabled() {
1683 DCHECK(plugin_print_interface_);
1684 if (!plugin_print_interface_)
1685 return false;
1686 return plugin_print_interface_->IsScalingDisabled(pp_instance()) == PP_TRUE;
1689 int PepperPluginInstanceImpl::PrintBegin(const WebPrintParams& print_params) {
1690 // Keep a reference on the stack. See NOTE above.
1691 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1692 PP_PrintOutputFormat_Dev format;
1693 if (!GetPreferredPrintOutputFormat(&format)) {
1694 // PrintBegin should not have been called since SupportsPrintInterface
1695 // would have returned false;
1696 NOTREACHED();
1697 return 0;
1699 int num_pages = 0;
1700 PP_PrintSettings_Dev print_settings;
1701 print_settings.printable_area = PP_FromGfxRect(print_params.printableArea);
1702 print_settings.content_area = PP_FromGfxRect(print_params.printContentArea);
1703 print_settings.paper_size = PP_FromGfxSize(print_params.paperSize);
1704 print_settings.dpi = print_params.printerDPI;
1705 print_settings.orientation = PP_PRINTORIENTATION_NORMAL;
1706 print_settings.grayscale = PP_FALSE;
1707 print_settings.print_scaling_option =
1708 static_cast<PP_PrintScalingOption_Dev>(print_params.printScalingOption);
1709 print_settings.format = format;
1710 num_pages = plugin_print_interface_->Begin(pp_instance(), &print_settings);
1711 if (!num_pages)
1712 return 0;
1713 current_print_settings_ = print_settings;
1714 canvas_.clear();
1715 ranges_.clear();
1716 return num_pages;
1719 void PepperPluginInstanceImpl::PrintPage(int page_number,
1720 blink::WebCanvas* canvas) {
1721 #if defined(ENABLE_PRINTING)
1722 DCHECK(plugin_print_interface_);
1723 PP_PrintPageNumberRange_Dev page_range;
1724 page_range.first_page_number = page_range.last_page_number = page_number;
1725 // The canvas only has a metafile on it for print preview.
1726 bool save_for_later =
1727 (printing::MetafileSkiaWrapper::GetMetafileFromCanvas(*canvas) != NULL);
1728 #if defined(OS_MACOSX)
1729 save_for_later = save_for_later && skia::IsPreviewMetafile(*canvas);
1730 #endif // defined(OS_MACOSX)
1731 if (save_for_later) {
1732 ranges_.push_back(page_range);
1733 canvas_ = skia::SharePtr(canvas);
1734 } else {
1735 PrintPageHelper(&page_range, 1, canvas);
1737 #endif
1740 void PepperPluginInstanceImpl::PrintPageHelper(
1741 PP_PrintPageNumberRange_Dev* page_ranges,
1742 int num_ranges,
1743 blink::WebCanvas* canvas) {
1744 // Keep a reference on the stack. See NOTE above.
1745 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1746 DCHECK(plugin_print_interface_);
1747 if (!plugin_print_interface_)
1748 return;
1749 PP_Resource print_output = plugin_print_interface_->PrintPages(
1750 pp_instance(), page_ranges, num_ranges);
1751 if (!print_output)
1752 return;
1754 if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF)
1755 PrintPDFOutput(print_output, canvas);
1757 // Now we need to release the print output resource.
1758 PluginModule::GetCore()->ReleaseResource(print_output);
1761 void PepperPluginInstanceImpl::PrintEnd() {
1762 // Keep a reference on the stack. See NOTE above.
1763 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1764 if (!ranges_.empty())
1765 PrintPageHelper(&(ranges_.front()), ranges_.size(), canvas_.get());
1766 canvas_.clear();
1767 ranges_.clear();
1769 DCHECK(plugin_print_interface_);
1770 if (plugin_print_interface_)
1771 plugin_print_interface_->End(pp_instance());
1773 memset(&current_print_settings_, 0, sizeof(current_print_settings_));
1774 #if defined(OS_MACOSX)
1775 last_printed_page_ = NULL;
1776 #endif // defined(OS_MACOSX)
1779 bool PepperPluginInstanceImpl::GetPrintPresetOptionsFromDocument(
1780 blink::WebPrintPresetOptions* preset_options) {
1781 // Keep a reference on the stack. See NOTE above.
1782 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1783 if (!LoadPdfInterface())
1784 return false;
1786 PP_PdfPrintPresetOptions_Dev options;
1787 if (!plugin_pdf_interface_->GetPrintPresetOptionsFromDocument(pp_instance(),
1788 &options)) {
1789 return false;
1792 preset_options->isScalingDisabled = PP_ToBool(options.is_scaling_disabled);
1793 switch (options.duplex) {
1794 case PP_PRIVATEDUPLEXMODE_SIMPLEX:
1795 preset_options->duplexMode = blink::WebSimplex;
1796 break;
1797 case PP_PRIVATEDUPLEXMODE_SHORT_EDGE:
1798 preset_options->duplexMode = blink::WebShortEdge;
1799 break;
1800 case PP_PRIVATEDUPLEXMODE_LONG_EDGE:
1801 preset_options->duplexMode = blink::WebLongEdge;
1802 break;
1803 default:
1804 preset_options->duplexMode = blink::WebUnknownDuplexMode;
1805 break;
1807 preset_options->copies = options.copies;
1808 preset_options->isPageSizeUniform = PP_ToBool(options.is_page_size_uniform);
1809 preset_options->uniformPageSize =
1810 blink::WebSize(options.uniform_page_size.width,
1811 options.uniform_page_size.height);
1813 return true;
1816 bool PepperPluginInstanceImpl::CanRotateView() {
1817 if (!LoadPdfInterface() || module()->is_crashed())
1818 return false;
1820 return true;
1823 void PepperPluginInstanceImpl::RotateView(WebPlugin::RotationType type) {
1824 if (!LoadPdfInterface())
1825 return;
1826 PP_PrivatePageTransformType transform_type =
1827 type == WebPlugin::RotationType90Clockwise
1828 ? PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CW
1829 : PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CCW;
1830 plugin_pdf_interface_->Transform(pp_instance(), transform_type);
1831 // NOTE: plugin instance may have been deleted.
1834 bool PepperPluginInstanceImpl::FlashIsFullscreenOrPending() {
1835 return fullscreen_container_ != NULL;
1838 bool PepperPluginInstanceImpl::IsFullscreenOrPending() {
1839 return desired_fullscreen_state_;
1842 bool PepperPluginInstanceImpl::SetFullscreen(bool fullscreen) {
1843 // Keep a reference on the stack. See NOTE above.
1844 scoped_refptr<PepperPluginInstanceImpl> ref(this);
1846 // Check whether we are trying to switch to the state we're already going
1847 // to (i.e. if we're already switching to fullscreen but the fullscreen
1848 // container isn't ready yet, don't do anything more).
1849 if (fullscreen == IsFullscreenOrPending())
1850 return false;
1852 if (!render_frame_)
1853 return false;
1854 if (fullscreen && !render_frame_->render_view()
1855 ->renderer_preferences()
1856 .plugin_fullscreen_allowed)
1857 return false;
1859 // Check whether we are trying to switch while the state is in transition.
1860 // The 2nd request gets dropped while messing up the internal state, so
1861 // disallow this.
1862 if (view_data_.is_fullscreen != desired_fullscreen_state_)
1863 return false;
1865 if (fullscreen && !IsProcessingUserGesture())
1866 return false;
1868 DVLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
1869 desired_fullscreen_state_ = fullscreen;
1871 if (fullscreen) {
1872 // Create the user gesture in case we're processing one that's pending.
1873 WebScopedUserGesture user_gesture(CurrentUserGestureToken());
1874 // WebKit does not resize the plugin to fill the screen in fullscreen mode,
1875 // so we will tweak plugin's attributes to support the expected behavior.
1876 KeepSizeAttributesBeforeFullscreen();
1877 SetSizeAttributesForFullscreen();
1878 container_->element().requestFullScreen();
1879 } else {
1880 container_->element().document().cancelFullScreen();
1882 return true;
1885 void PepperPluginInstanceImpl::UpdateFlashFullscreenState(
1886 bool flash_fullscreen) {
1887 bool is_mouselock_pending = TrackedCallback::IsPending(lock_mouse_callback_);
1889 if (flash_fullscreen == flash_fullscreen_) {
1890 // Manually clear callback when fullscreen fails with mouselock pending.
1891 if (!flash_fullscreen && is_mouselock_pending)
1892 lock_mouse_callback_->Run(PP_ERROR_FAILED);
1893 return;
1896 UpdateLayer(false);
1898 bool old_plugin_focus = PluginHasFocus();
1899 flash_fullscreen_ = flash_fullscreen;
1900 if (is_mouselock_pending && !IsMouseLocked()) {
1901 if (!IsProcessingUserGesture() &&
1902 !module_->permissions().HasPermission(
1903 ppapi::PERMISSION_BYPASS_USER_GESTURE)) {
1904 lock_mouse_callback_->Run(PP_ERROR_NO_USER_GESTURE);
1905 } else {
1906 // Open a user gesture here so the Webkit user gesture checks will succeed
1907 // for out-of-process plugins.
1908 WebScopedUserGesture user_gesture(CurrentUserGestureToken());
1909 if (!LockMouse())
1910 lock_mouse_callback_->Run(PP_ERROR_FAILED);
1914 if (PluginHasFocus() != old_plugin_focus)
1915 SendFocusChangeNotification();
1918 bool PepperPluginInstanceImpl::IsViewAccelerated() {
1919 if (!container_)
1920 return false;
1922 WebDocument document = container_->element().document();
1923 WebLocalFrame* frame = document.frame();
1924 if (!frame)
1925 return false;
1926 WebView* view = frame->view();
1927 if (!view)
1928 return false;
1930 return view->isAcceleratedCompositingActive();
1933 bool PepperPluginInstanceImpl::PrintPDFOutput(PP_Resource print_output,
1934 blink::WebCanvas* canvas) {
1935 #if defined(ENABLE_PRINTING)
1936 ppapi::thunk::EnterResourceNoLock<PPB_Buffer_API> enter(print_output, true);
1937 if (enter.failed())
1938 return false;
1940 BufferAutoMapper mapper(enter.object());
1941 if (!mapper.data() || !mapper.size()) {
1942 NOTREACHED();
1943 return false;
1946 printing::PdfMetafileSkia* metafile =
1947 printing::MetafileSkiaWrapper::GetMetafileFromCanvas(*canvas);
1948 if (metafile)
1949 return metafile->InitFromData(mapper.data(), mapper.size());
1951 NOTREACHED();
1952 #endif // ENABLE_PRINTING
1953 return false;
1956 void PepperPluginInstanceImpl::UpdateLayer(bool device_changed) {
1957 if (!container_)
1958 return;
1960 gpu::Mailbox mailbox;
1961 uint32 sync_point = 0;
1962 if (bound_graphics_3d_.get()) {
1963 bound_graphics_3d_->GetBackingMailbox(&mailbox, &sync_point);
1964 DCHECK_EQ(mailbox.IsZero(), sync_point == 0);
1966 bool want_3d_layer = !mailbox.IsZero();
1967 bool want_2d_layer = !!bound_graphics_2d_platform_;
1968 bool want_texture_layer = want_3d_layer || want_2d_layer;
1969 bool want_compositor_layer = !!bound_compositor_;
1971 if (throttler_ && throttler_->IsHiddenForPlaceholder()) {
1972 want_3d_layer = false;
1973 want_2d_layer = false;
1974 want_texture_layer = false;
1975 want_compositor_layer = false;
1978 if (!device_changed && (want_texture_layer == !!texture_layer_.get()) &&
1979 (want_3d_layer == layer_is_hardware_) &&
1980 (want_compositor_layer == !!compositor_layer_.get()) &&
1981 layer_bound_to_fullscreen_ == !!fullscreen_container_) {
1982 UpdateLayerTransform();
1983 return;
1986 if (texture_layer_.get() || compositor_layer_.get()) {
1987 if (!layer_bound_to_fullscreen_)
1988 container_->setWebLayer(NULL);
1989 else if (fullscreen_container_)
1990 fullscreen_container_->SetLayer(NULL);
1991 web_layer_.reset();
1992 if (texture_layer_) {
1993 texture_layer_->ClearClient();
1994 texture_layer_ = NULL;
1996 compositor_layer_ = NULL;
1999 if (want_texture_layer) {
2000 bool opaque = false;
2001 if (want_3d_layer) {
2002 DCHECK(bound_graphics_3d_.get());
2003 texture_layer_ = cc::TextureLayer::CreateForMailbox(
2004 cc_blink::WebLayerImpl::LayerSettings(), NULL);
2005 opaque = bound_graphics_3d_->IsOpaque();
2006 texture_layer_->SetTextureMailboxWithoutReleaseCallback(
2007 cc::TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point));
2008 } else {
2009 DCHECK(bound_graphics_2d_platform_);
2010 texture_layer_ = cc::TextureLayer::CreateForMailbox(
2011 cc_blink::WebLayerImpl::LayerSettings(), this);
2012 bound_graphics_2d_platform_->AttachedToNewLayer();
2013 opaque = bound_graphics_2d_platform_->IsAlwaysOpaque();
2014 texture_layer_->SetFlipped(false);
2017 // Ignore transparency in fullscreen, since that's what Flash always
2018 // wants to do, and that lets it not recreate a context if
2019 // wmode=transparent was specified.
2020 opaque = opaque || fullscreen_container_;
2021 texture_layer_->SetContentsOpaque(opaque);
2022 web_layer_.reset(new cc_blink::WebLayerImpl(texture_layer_));
2023 } else if (want_compositor_layer) {
2024 compositor_layer_ = bound_compositor_->layer();
2025 web_layer_.reset(new cc_blink::WebLayerImpl(compositor_layer_));
2028 if (web_layer_) {
2029 if (fullscreen_container_) {
2030 fullscreen_container_->SetLayer(web_layer_.get());
2031 } else {
2032 container_->setWebLayer(web_layer_.get());
2036 layer_bound_to_fullscreen_ = !!fullscreen_container_;
2037 layer_is_hardware_ = want_3d_layer;
2038 UpdateLayerTransform();
2041 bool PepperPluginInstanceImpl::PrepareTextureMailbox(
2042 cc::TextureMailbox* mailbox,
2043 scoped_ptr<cc::SingleReleaseCallback>* release_callback,
2044 bool use_shared_memory) {
2045 if (!bound_graphics_2d_platform_)
2046 return false;
2047 return bound_graphics_2d_platform_->PrepareTextureMailbox(mailbox,
2048 release_callback);
2051 void PepperPluginInstanceImpl::OnDestruct() { render_frame_ = NULL; }
2053 void PepperPluginInstanceImpl::OnThrottleStateChange() {
2054 SendDidChangeView();
2056 bool is_throttled = throttler_->IsThrottled();
2057 render_frame()->Send(new FrameHostMsg_PluginInstanceThrottleStateChange(
2058 module_->GetPluginChildId(), pp_instance_, is_throttled));
2061 void PepperPluginInstanceImpl::OnHiddenForPlaceholder(bool hidden) {
2062 UpdateLayer(false /* device_changed */);
2065 void PepperPluginInstanceImpl::AddPluginObject(PluginObject* plugin_object) {
2066 DCHECK(live_plugin_objects_.find(plugin_object) ==
2067 live_plugin_objects_.end());
2068 live_plugin_objects_.insert(plugin_object);
2071 void PepperPluginInstanceImpl::RemovePluginObject(PluginObject* plugin_object) {
2072 // Don't actually verify that the object is in the set since during module
2073 // deletion we'll be in the process of freeing them.
2074 live_plugin_objects_.erase(plugin_object);
2077 bool PepperPluginInstanceImpl::IsProcessingUserGesture() {
2078 PP_TimeTicks now = ppapi::TimeTicksToPPTimeTicks(base::TimeTicks::Now());
2079 // Give a lot of slack so tests won't be flaky.
2080 const PP_TimeTicks kUserGestureDurationInSeconds = 10.0;
2081 return pending_user_gesture_token_.hasGestures() &&
2082 (now - pending_user_gesture_ < kUserGestureDurationInSeconds);
2085 WebUserGestureToken PepperPluginInstanceImpl::CurrentUserGestureToken() {
2086 if (!IsProcessingUserGesture())
2087 pending_user_gesture_token_ = WebUserGestureToken();
2088 return pending_user_gesture_token_;
2091 void PepperPluginInstanceImpl::OnLockMouseACK(bool succeeded) {
2092 if (TrackedCallback::IsPending(lock_mouse_callback_))
2093 lock_mouse_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
2096 void PepperPluginInstanceImpl::OnMouseLockLost() {
2097 if (LoadMouseLockInterface())
2098 plugin_mouse_lock_interface_->MouseLockLost(pp_instance());
2101 void PepperPluginInstanceImpl::HandleMouseLockedInputEvent(
2102 const blink::WebMouseEvent& event) {
2103 // |cursor_info| is ignored since it is hidden when the mouse is locked.
2104 blink::WebCursorInfo cursor_info;
2105 HandleInputEvent(event, &cursor_info);
2108 void PepperPluginInstanceImpl::SimulateInputEvent(
2109 const InputEventData& input_event) {
2110 WebView* web_view = container()->element().document().frame()->view();
2111 if (!web_view) {
2112 NOTREACHED();
2113 return;
2116 bool handled = SimulateIMEEvent(input_event);
2117 if (handled)
2118 return;
2120 std::vector<linked_ptr<WebInputEvent> > events =
2121 CreateSimulatedWebInputEvents(
2122 input_event,
2123 view_data_.rect.point.x + view_data_.rect.size.width / 2,
2124 view_data_.rect.point.y + view_data_.rect.size.height / 2);
2125 for (std::vector<linked_ptr<WebInputEvent> >::iterator it = events.begin();
2126 it != events.end();
2127 ++it) {
2128 web_view->handleInputEvent(*it->get());
2132 bool PepperPluginInstanceImpl::SimulateIMEEvent(
2133 const InputEventData& input_event) {
2134 switch (input_event.event_type) {
2135 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
2136 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
2137 SimulateImeSetCompositionEvent(input_event);
2138 break;
2139 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
2140 DCHECK(input_event.character_text.empty());
2141 SimulateImeSetCompositionEvent(input_event);
2142 break;
2143 case PP_INPUTEVENT_TYPE_IME_TEXT:
2144 if (!render_frame_)
2145 return false;
2146 render_frame_->SimulateImeConfirmComposition(
2147 base::UTF8ToUTF16(input_event.character_text), gfx::Range());
2148 break;
2149 default:
2150 return false;
2152 return true;
2155 void PepperPluginInstanceImpl::SimulateImeSetCompositionEvent(
2156 const InputEventData& input_event) {
2157 if (!render_frame_)
2158 return;
2160 std::vector<size_t> offsets;
2161 offsets.push_back(input_event.composition_selection_start);
2162 offsets.push_back(input_event.composition_selection_end);
2163 offsets.insert(offsets.end(),
2164 input_event.composition_segment_offsets.begin(),
2165 input_event.composition_segment_offsets.end());
2167 base::string16 utf16_text =
2168 base::UTF8ToUTF16AndAdjustOffsets(input_event.character_text, &offsets);
2170 std::vector<blink::WebCompositionUnderline> underlines;
2171 for (size_t i = 2; i + 1 < offsets.size(); ++i) {
2172 blink::WebCompositionUnderline underline;
2173 underline.startOffset = offsets[i];
2174 underline.endOffset = offsets[i + 1];
2175 if (input_event.composition_target_segment == static_cast<int32_t>(i - 2))
2176 underline.thick = true;
2177 underlines.push_back(underline);
2180 render_frame_->SimulateImeSetComposition(
2181 utf16_text, underlines, offsets[0], offsets[1]);
2184 ContentDecryptorDelegate*
2185 PepperPluginInstanceImpl::GetContentDecryptorDelegate() {
2186 if (content_decryptor_delegate_)
2187 return content_decryptor_delegate_.get();
2189 const PPP_ContentDecryptor_Private* plugin_decryption_interface =
2190 static_cast<const PPP_ContentDecryptor_Private*>(
2191 module_->GetPluginInterface(PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE));
2192 if (!plugin_decryption_interface)
2193 return NULL;
2195 content_decryptor_delegate_.reset(
2196 new ContentDecryptorDelegate(pp_instance_, plugin_decryption_interface));
2197 return content_decryptor_delegate_.get();
2200 PP_Bool PepperPluginInstanceImpl::BindGraphics(PP_Instance instance,
2201 PP_Resource device) {
2202 TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::BindGraphics");
2203 // The Graphics3D instance can't be destroyed until we call
2204 // UpdateLayer().
2205 scoped_refptr<ppapi::Resource> old_graphics = bound_graphics_3d_.get();
2206 if (bound_graphics_3d_.get()) {
2207 bound_graphics_3d_->BindToInstance(false);
2208 bound_graphics_3d_ = NULL;
2210 if (bound_graphics_2d_platform_) {
2211 bound_graphics_2d_platform_->BindToInstance(NULL);
2212 bound_graphics_2d_platform_ = NULL;
2214 if (bound_compositor_) {
2215 bound_compositor_->BindToInstance(NULL);
2216 bound_compositor_ = NULL;
2219 // Special-case clearing the current device.
2220 if (!device) {
2221 UpdateLayer(true);
2222 InvalidateRect(gfx::Rect());
2223 return PP_TRUE;
2226 // Refuse to bind if in transition to fullscreen with PPB_FlashFullscreen or
2227 // to/from fullscreen with PPB_Fullscreen.
2228 if ((fullscreen_container_ && !flash_fullscreen_) ||
2229 desired_fullscreen_state_ != view_data_.is_fullscreen)
2230 return PP_FALSE;
2232 const ppapi::host::PpapiHost* ppapi_host =
2233 RendererPpapiHost::GetForPPInstance(instance)->GetPpapiHost();
2234 ppapi::host::ResourceHost* host = ppapi_host->GetResourceHost(device);
2235 PepperGraphics2DHost* graphics_2d = NULL;
2236 PepperCompositorHost* compositor = NULL;
2237 if (host) {
2238 if (host->IsGraphics2DHost()) {
2239 graphics_2d = static_cast<PepperGraphics2DHost*>(host);
2240 } else if (host->IsCompositorHost()) {
2241 compositor = static_cast<PepperCompositorHost*>(host);
2242 } else {
2243 DLOG(ERROR) <<
2244 "Resource is not PepperCompositorHost or PepperGraphics2DHost.";
2248 EnterResourceNoLock<PPB_Graphics3D_API> enter_3d(device, false);
2249 PPB_Graphics3D_Impl* graphics_3d =
2250 enter_3d.succeeded()
2251 ? static_cast<PPB_Graphics3D_Impl*>(enter_3d.object())
2252 : NULL;
2254 if (compositor) {
2255 if (compositor->BindToInstance(this)) {
2256 bound_compositor_ = compositor;
2257 UpdateLayer(true);
2258 return PP_TRUE;
2260 } else if (graphics_2d) {
2261 if (graphics_2d->BindToInstance(this)) {
2262 bound_graphics_2d_platform_ = graphics_2d;
2263 UpdateLayer(true);
2264 return PP_TRUE;
2266 } else if (graphics_3d) {
2267 // Make sure graphics can only be bound to the instance it is
2268 // associated with.
2269 if (graphics_3d->pp_instance() == pp_instance() &&
2270 graphics_3d->BindToInstance(true)) {
2271 bound_graphics_3d_ = graphics_3d;
2272 UpdateLayer(true);
2273 return PP_TRUE;
2277 // The instance cannot be bound or the device is not a valid resource type.
2278 return PP_FALSE;
2281 PP_Bool PepperPluginInstanceImpl::IsFullFrame(PP_Instance instance) {
2282 return PP_FromBool(full_frame());
2285 const ViewData* PepperPluginInstanceImpl::GetViewData(PP_Instance instance) {
2286 return &view_data_;
2289 PP_Bool PepperPluginInstanceImpl::FlashIsFullscreen(PP_Instance instance) {
2290 return PP_FromBool(flash_fullscreen_);
2293 PP_Var PepperPluginInstanceImpl::GetWindowObject(PP_Instance instance) {
2294 if (!container_)
2295 return PP_MakeUndefined();
2296 RecordFlashJavaScriptUse();
2297 V8VarConverter converter(pp_instance_, V8VarConverter::kAllowObjectVars);
2298 PepperTryCatchVar try_catch(this, &converter, NULL);
2299 WebLocalFrame* frame = container_->element().document().frame();
2300 if (!frame) {
2301 try_catch.SetException("No frame exists for window object.");
2302 return PP_MakeUndefined();
2305 ScopedPPVar result =
2306 try_catch.FromV8(frame->mainWorldScriptContext()->Global());
2307 DCHECK(!try_catch.HasException());
2308 return result.Release();
2311 PP_Var PepperPluginInstanceImpl::GetOwnerElementObject(PP_Instance instance) {
2312 if (!container_)
2313 return PP_MakeUndefined();
2314 RecordFlashJavaScriptUse();
2315 V8VarConverter converter(pp_instance_, V8VarConverter::kAllowObjectVars);
2316 PepperTryCatchVar try_catch(this, &converter, NULL);
2317 ScopedPPVar result = try_catch.FromV8(container_->v8ObjectForElement());
2318 DCHECK(!try_catch.HasException());
2319 return result.Release();
2322 PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance,
2323 PP_Var script_var,
2324 PP_Var* exception) {
2325 if (!container_)
2326 return PP_MakeUndefined();
2327 if (is_deleted_ && blink::WebPluginScriptForbiddenScope::isForbidden())
2328 return PP_MakeUndefined();
2329 RecordFlashJavaScriptUse();
2331 // Executing the script may remove the plugin from the DOM, so we need to keep
2332 // a reference to ourselves so that we can still process the result after the
2333 // WebBindings::evaluate() below.
2334 scoped_refptr<PepperPluginInstanceImpl> ref(this);
2335 V8VarConverter converter(pp_instance_, V8VarConverter::kAllowObjectVars);
2336 PepperTryCatchVar try_catch(this, &converter, exception);
2338 // Check for an exception due to the context being destroyed.
2339 if (try_catch.HasException())
2340 return PP_MakeUndefined();
2342 WebLocalFrame* frame = container_->element().document().frame();
2343 if (!frame) {
2344 try_catch.SetException("No frame to execute script in.");
2345 return PP_MakeUndefined();
2348 StringVar* script_string_var = StringVar::FromPPVar(script_var);
2349 if (!script_string_var) {
2350 try_catch.SetException("Script param to ExecuteScript must be a string.");
2351 return PP_MakeUndefined();
2354 std::string script_string = script_string_var->value();
2355 blink::WebScriptSource script(
2356 blink::WebString::fromUTF8(script_string.c_str()));
2357 v8::Local<v8::Value> result;
2358 if (IsProcessingUserGesture()) {
2359 blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
2360 result = frame->executeScriptAndReturnValue(script);
2361 } else {
2362 result = frame->executeScriptAndReturnValue(script);
2365 ScopedPPVar var_result = try_catch.FromV8(result);
2366 if (try_catch.HasException())
2367 return PP_MakeUndefined();
2369 return var_result.Release();
2372 uint32_t PepperPluginInstanceImpl::GetAudioHardwareOutputSampleRate(
2373 PP_Instance instance) {
2374 RenderThreadImpl* thread = RenderThreadImpl::current();
2375 return thread->GetAudioHardwareConfig()->GetOutputSampleRate();
2378 uint32_t PepperPluginInstanceImpl::GetAudioHardwareOutputBufferSize(
2379 PP_Instance instance) {
2380 RenderThreadImpl* thread = RenderThreadImpl::current();
2381 return thread->GetAudioHardwareConfig()->GetOutputBufferSize();
2384 PP_Var PepperPluginInstanceImpl::GetDefaultCharSet(PP_Instance instance) {
2385 if (!render_frame_)
2386 return PP_MakeUndefined();
2387 return StringVar::StringToPPVar(
2388 render_frame_->render_view()->webkit_preferences().default_encoding);
2391 // These PPB_ContentDecryptor_Private calls are responses to
2392 // PPP_ContentDecryptor_Private calls made on |content_decryptor_delegate_|.
2393 // Therefore, |content_decryptor_delegate_| must have been initialized when
2394 // the following methods are called.
2395 void PepperPluginInstanceImpl::PromiseResolved(PP_Instance instance,
2396 uint32 promise_id) {
2397 content_decryptor_delegate_->OnPromiseResolved(promise_id);
2400 void PepperPluginInstanceImpl::PromiseResolvedWithSession(
2401 PP_Instance instance,
2402 uint32 promise_id,
2403 PP_Var session_id_var) {
2404 content_decryptor_delegate_->OnPromiseResolvedWithSession(promise_id,
2405 session_id_var);
2408 void PepperPluginInstanceImpl::PromiseRejected(
2409 PP_Instance instance,
2410 uint32 promise_id,
2411 PP_CdmExceptionCode exception_code,
2412 uint32 system_code,
2413 PP_Var error_description_var) {
2414 content_decryptor_delegate_->OnPromiseRejected(
2415 promise_id, exception_code, system_code, error_description_var);
2418 void PepperPluginInstanceImpl::SessionMessage(PP_Instance instance,
2419 PP_Var session_id_var,
2420 PP_CdmMessageType message_type,
2421 PP_Var message_var,
2422 PP_Var legacy_destination_url) {
2423 content_decryptor_delegate_->OnSessionMessage(
2424 session_id_var, message_type, message_var, legacy_destination_url);
2427 void PepperPluginInstanceImpl::SessionKeysChange(
2428 PP_Instance instance,
2429 PP_Var session_id_var,
2430 PP_Bool has_additional_usable_key,
2431 uint32_t key_count,
2432 const struct PP_KeyInformation key_information[]) {
2433 content_decryptor_delegate_->OnSessionKeysChange(
2434 session_id_var, has_additional_usable_key, key_count, key_information);
2437 void PepperPluginInstanceImpl::SessionExpirationChange(
2438 PP_Instance instance,
2439 PP_Var session_id_var,
2440 PP_Time new_expiry_time) {
2441 content_decryptor_delegate_->OnSessionExpirationChange(session_id_var,
2442 new_expiry_time);
2445 void PepperPluginInstanceImpl::SessionClosed(PP_Instance instance,
2446 PP_Var session_id_var) {
2447 content_decryptor_delegate_->OnSessionClosed(session_id_var);
2450 void PepperPluginInstanceImpl::LegacySessionError(
2451 PP_Instance instance,
2452 PP_Var session_id_var,
2453 PP_CdmExceptionCode exception_code,
2454 uint32 system_code,
2455 PP_Var error_description_var) {
2456 content_decryptor_delegate_->OnLegacySessionError(
2457 session_id_var, exception_code, system_code, error_description_var);
2460 void PepperPluginInstanceImpl::DeliverBlock(
2461 PP_Instance instance,
2462 PP_Resource decrypted_block,
2463 const PP_DecryptedBlockInfo* block_info) {
2464 content_decryptor_delegate_->DeliverBlock(decrypted_block, block_info);
2467 void PepperPluginInstanceImpl::DecoderInitializeDone(
2468 PP_Instance instance,
2469 PP_DecryptorStreamType decoder_type,
2470 uint32_t request_id,
2471 PP_Bool success) {
2472 content_decryptor_delegate_->DecoderInitializeDone(
2473 decoder_type, request_id, success);
2476 void PepperPluginInstanceImpl::DecoderDeinitializeDone(
2477 PP_Instance instance,
2478 PP_DecryptorStreamType decoder_type,
2479 uint32_t request_id) {
2480 content_decryptor_delegate_->DecoderDeinitializeDone(decoder_type,
2481 request_id);
2484 void PepperPluginInstanceImpl::DecoderResetDone(
2485 PP_Instance instance,
2486 PP_DecryptorStreamType decoder_type,
2487 uint32_t request_id) {
2488 content_decryptor_delegate_->DecoderResetDone(decoder_type, request_id);
2491 void PepperPluginInstanceImpl::DeliverFrame(
2492 PP_Instance instance,
2493 PP_Resource decrypted_frame,
2494 const PP_DecryptedFrameInfo* frame_info) {
2495 content_decryptor_delegate_->DeliverFrame(decrypted_frame, frame_info);
2498 void PepperPluginInstanceImpl::DeliverSamples(
2499 PP_Instance instance,
2500 PP_Resource audio_frames,
2501 const PP_DecryptedSampleInfo* sample_info) {
2502 content_decryptor_delegate_->DeliverSamples(audio_frames, sample_info);
2505 void PepperPluginInstanceImpl::SetPluginToHandleFindRequests(
2506 PP_Instance instance) {
2507 if (!LoadFindInterface())
2508 return;
2509 bool is_main_frame =
2510 render_frame_ &&
2511 render_frame_->GetRenderView()->GetMainRenderFrame() == render_frame_;
2512 if (!is_main_frame)
2513 return;
2514 render_frame_->render_view()->set_plugin_find_handler(this);
2517 void PepperPluginInstanceImpl::NumberOfFindResultsChanged(
2518 PP_Instance instance,
2519 int32_t total,
2520 PP_Bool final_result) {
2521 DCHECK_NE(find_identifier_, -1);
2522 if (render_frame_) {
2523 render_frame_->reportFindInPageMatchCount(
2524 find_identifier_, total, PP_ToBool(final_result));
2528 void PepperPluginInstanceImpl::SelectedFindResultChanged(PP_Instance instance,
2529 int32_t index) {
2530 DCHECK_NE(find_identifier_, -1);
2531 if (render_frame_) {
2532 render_frame_->reportFindInPageSelection(
2533 find_identifier_, index + 1, blink::WebRect());
2537 void PepperPluginInstanceImpl::SetTickmarks(PP_Instance instance,
2538 const PP_Rect* tickmarks,
2539 uint32_t count) {
2540 if (!render_frame_ || !render_frame_->GetWebFrame())
2541 return;
2543 blink::WebVector<blink::WebRect> tickmarks_converted(
2544 static_cast<size_t>(count));
2545 for (uint32 i = 0; i < count; ++i) {
2546 tickmarks_converted[i] = blink::WebRect(tickmarks[i].point.x,
2547 tickmarks[i].point.y,
2548 tickmarks[i].size.width,
2549 tickmarks[i].size.height);
2551 blink::WebFrame* frame = render_frame_->GetWebFrame();
2552 frame->setTickmarks(tickmarks_converted);
2555 PP_Bool PepperPluginInstanceImpl::IsFullscreen(PP_Instance instance) {
2556 return PP_FromBool(view_data_.is_fullscreen);
2559 PP_Bool PepperPluginInstanceImpl::SetFullscreen(PP_Instance instance,
2560 PP_Bool fullscreen) {
2561 return PP_FromBool(SetFullscreen(PP_ToBool(fullscreen)));
2564 PP_Bool PepperPluginInstanceImpl::GetScreenSize(PP_Instance instance,
2565 PP_Size* size) {
2566 if (flash_fullscreen_) {
2567 // Workaround for Flash rendering bug: Flash is assuming the fullscreen view
2568 // size will be equal to the physical screen size. However, the fullscreen
2569 // view is sized by the browser UI, and may not be the same size as the
2570 // screen or the desktop. Therefore, report the view size as the screen
2571 // size when in fullscreen mode. http://crbug.com/506016
2572 // TODO(miu): Remove this workaround once Flash has been fixed.
2573 *size = view_data_.rect.size;
2574 } else {
2575 // All other cases: Report the screen size.
2576 blink::WebScreenInfo info = render_frame()->GetRenderWidget()->screenInfo();
2577 *size = PP_MakeSize(info.rect.width, info.rect.height);
2579 return PP_TRUE;
2582 ppapi::Resource* PepperPluginInstanceImpl::GetSingletonResource(
2583 PP_Instance instance,
2584 ppapi::SingletonResourceID id) {
2585 // Flash APIs and some others aren't implemented in-process.
2586 switch (id) {
2587 case ppapi::BROKER_SINGLETON_ID:
2588 case ppapi::BROWSER_FONT_SINGLETON_ID:
2589 case ppapi::FLASH_CLIPBOARD_SINGLETON_ID:
2590 case ppapi::FLASH_FILE_SINGLETON_ID:
2591 case ppapi::FLASH_FULLSCREEN_SINGLETON_ID:
2592 case ppapi::FLASH_SINGLETON_ID:
2593 case ppapi::ISOLATED_FILESYSTEM_SINGLETON_ID:
2594 case ppapi::NETWORK_PROXY_SINGLETON_ID:
2595 case ppapi::PDF_SINGLETON_ID:
2596 case ppapi::TRUETYPE_FONT_SINGLETON_ID:
2597 NOTIMPLEMENTED();
2598 return NULL;
2599 case ppapi::GAMEPAD_SINGLETON_ID:
2600 return gamepad_impl_.get();
2601 case ppapi::UMA_SINGLETON_ID: {
2602 if (!uma_private_impl_.get()) {
2603 RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
2604 if (host_impl->in_process_router()) {
2605 uma_private_impl_ = new ppapi::proxy::UMAPrivateResource(
2606 host_impl->in_process_router()->GetPluginConnection(instance),
2607 instance);
2610 return uma_private_impl_.get();
2614 NOTREACHED();
2615 return NULL;
2618 int32_t PepperPluginInstanceImpl::RequestInputEvents(PP_Instance instance,
2619 uint32_t event_classes) {
2620 input_event_mask_ |= event_classes;
2621 filtered_input_event_mask_ &= ~(event_classes);
2622 RequestInputEventsHelper(event_classes);
2623 return ValidateRequestInputEvents(false, event_classes);
2626 int32_t PepperPluginInstanceImpl::RequestFilteringInputEvents(
2627 PP_Instance instance,
2628 uint32_t event_classes) {
2629 filtered_input_event_mask_ |= event_classes;
2630 input_event_mask_ &= ~(event_classes);
2631 RequestInputEventsHelper(event_classes);
2632 return ValidateRequestInputEvents(true, event_classes);
2635 void PepperPluginInstanceImpl::ClearInputEventRequest(PP_Instance instance,
2636 uint32_t event_classes) {
2637 input_event_mask_ &= ~(event_classes);
2638 filtered_input_event_mask_ &= ~(event_classes);
2639 RequestInputEventsHelper(event_classes);
2642 void PepperPluginInstanceImpl::PostMessage(PP_Instance instance,
2643 PP_Var message) {
2644 PostMessageToJavaScript(message);
2647 PP_Bool PepperPluginInstanceImpl::SetCursor(PP_Instance instance,
2648 PP_MouseCursor_Type type,
2649 PP_Resource image,
2650 const PP_Point* hot_spot) {
2651 if (!ValidateSetCursorParams(type, image, hot_spot))
2652 return PP_FALSE;
2654 if (type != PP_MOUSECURSOR_TYPE_CUSTOM) {
2655 DoSetCursor(new WebCursorInfo(static_cast<WebCursorInfo::Type>(type)));
2656 return PP_TRUE;
2659 EnterResourceNoLock<PPB_ImageData_API> enter(image, true);
2660 if (enter.failed())
2661 return PP_FALSE;
2662 PPB_ImageData_Impl* image_data =
2663 static_cast<PPB_ImageData_Impl*>(enter.object());
2665 ImageDataAutoMapper auto_mapper(image_data);
2666 if (!auto_mapper.is_valid())
2667 return PP_FALSE;
2669 scoped_ptr<WebCursorInfo> custom_cursor(
2670 new WebCursorInfo(WebCursorInfo::TypeCustom));
2671 custom_cursor->hotSpot.x = hot_spot->x;
2672 custom_cursor->hotSpot.y = hot_spot->y;
2674 const SkBitmap* bitmap = image_data->GetMappedBitmap();
2675 // Make a deep copy, so that the cursor remains valid even after the original
2676 // image data gets freed.
2677 if (!bitmap->copyTo(&custom_cursor->customImage.getSkBitmap())) {
2678 return PP_FALSE;
2681 DoSetCursor(custom_cursor.release());
2682 return PP_TRUE;
2685 int32_t PepperPluginInstanceImpl::LockMouse(
2686 PP_Instance instance,
2687 scoped_refptr<TrackedCallback> callback) {
2688 if (TrackedCallback::IsPending(lock_mouse_callback_))
2689 return PP_ERROR_INPROGRESS;
2691 if (IsMouseLocked())
2692 return PP_OK;
2694 if (!CanAccessMainFrame())
2695 return PP_ERROR_NOACCESS;
2697 if (!IsProcessingUserGesture())
2698 return PP_ERROR_NO_USER_GESTURE;
2700 // Attempt mouselock only if Flash isn't waiting on fullscreen, otherwise
2701 // we wait and call LockMouse() in UpdateFlashFullscreenState().
2702 if (!FlashIsFullscreenOrPending() || flash_fullscreen_) {
2703 // Open a user gesture here so the Webkit user gesture checks will succeed
2704 // for out-of-process plugins.
2705 WebScopedUserGesture user_gesture(CurrentUserGestureToken());
2706 if (!LockMouse())
2707 return PP_ERROR_FAILED;
2710 // Either mouselock succeeded or a Flash fullscreen is pending.
2711 lock_mouse_callback_ = callback;
2712 return PP_OK_COMPLETIONPENDING;
2715 void PepperPluginInstanceImpl::UnlockMouse(PP_Instance instance) {
2716 GetMouseLockDispatcher()->UnlockMouse(GetOrCreateLockTargetAdapter());
2719 void PepperPluginInstanceImpl::SetTextInputType(PP_Instance instance,
2720 PP_TextInput_Type type) {
2721 if (!render_frame_)
2722 return;
2723 int itype = type;
2724 if (itype < 0 || itype > ui::TEXT_INPUT_TYPE_URL)
2725 itype = ui::TEXT_INPUT_TYPE_NONE;
2726 SetTextInputType(static_cast<ui::TextInputType>(itype));
2729 void PepperPluginInstanceImpl::UpdateCaretPosition(
2730 PP_Instance instance,
2731 const PP_Rect& caret,
2732 const PP_Rect& bounding_box) {
2733 if (!render_frame_)
2734 return;
2735 text_input_caret_ = PP_ToGfxRect(caret);
2736 text_input_caret_bounds_ = PP_ToGfxRect(bounding_box);
2737 text_input_caret_set_ = true;
2738 render_frame_->PepperCaretPositionChanged(this);
2741 void PepperPluginInstanceImpl::CancelCompositionText(PP_Instance instance) {
2742 if (render_frame_)
2743 render_frame_->PepperCancelComposition(this);
2746 void PepperPluginInstanceImpl::SelectionChanged(PP_Instance instance) {
2747 // TODO(kinaba): currently the browser always calls RequestSurroundingText.
2748 // It can be optimized so that it won't call it back until the information
2749 // is really needed.
2751 // Avoid calling in nested context or else this will reenter the plugin. This
2752 // uses a weak pointer rather than exploiting the fact that this class is
2753 // refcounted because we don't actually want this operation to affect the
2754 // lifetime of the instance.
2755 base::ThreadTaskRunnerHandle::Get()->PostTask(
2756 FROM_HERE, base::Bind(&PepperPluginInstanceImpl::RequestSurroundingText,
2757 weak_factory_.GetWeakPtr(),
2758 static_cast<size_t>(kExtraCharsForTextInput)));
2761 void PepperPluginInstanceImpl::UpdateSurroundingText(PP_Instance instance,
2762 const char* text,
2763 uint32_t caret,
2764 uint32_t anchor) {
2765 if (!render_frame_)
2766 return;
2767 surrounding_text_ = text;
2768 selection_caret_ = caret;
2769 selection_anchor_ = anchor;
2770 render_frame_->PepperSelectionChanged(this);
2773 PP_Var PepperPluginInstanceImpl::ResolveRelativeToDocument(
2774 PP_Instance instance,
2775 PP_Var relative,
2776 PP_URLComponents_Dev* components) {
2777 StringVar* relative_string = StringVar::FromPPVar(relative);
2778 if (!relative_string)
2779 return PP_MakeNull();
2781 WebElement plugin_element = container()->element();
2782 GURL document_url = plugin_element.document().baseURL();
2783 return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(
2784 document_url.Resolve(relative_string->value()), components);
2787 PP_Bool PepperPluginInstanceImpl::DocumentCanRequest(PP_Instance instance,
2788 PP_Var url) {
2789 StringVar* url_string = StringVar::FromPPVar(url);
2790 if (!url_string)
2791 return PP_FALSE;
2793 blink::WebSecurityOrigin security_origin;
2794 if (!SecurityOriginForInstance(instance, &security_origin))
2795 return PP_FALSE;
2797 GURL gurl(url_string->value());
2798 if (!gurl.is_valid())
2799 return PP_FALSE;
2801 return PP_FromBool(security_origin.canRequest(gurl));
2804 PP_Bool PepperPluginInstanceImpl::DocumentCanAccessDocument(
2805 PP_Instance instance,
2806 PP_Instance target) {
2807 blink::WebSecurityOrigin our_origin;
2808 if (!SecurityOriginForInstance(instance, &our_origin))
2809 return PP_FALSE;
2811 blink::WebSecurityOrigin target_origin;
2812 if (!SecurityOriginForInstance(instance, &target_origin))
2813 return PP_FALSE;
2815 return PP_FromBool(our_origin.canAccess(target_origin));
2818 PP_Var PepperPluginInstanceImpl::GetDocumentURL(
2819 PP_Instance instance,
2820 PP_URLComponents_Dev* components) {
2821 blink::WebDocument document = container()->element().document();
2822 return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(document.url(),
2823 components);
2826 PP_Var PepperPluginInstanceImpl::GetPluginInstanceURL(
2827 PP_Instance instance,
2828 PP_URLComponents_Dev* components) {
2829 return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(plugin_url_, components);
2832 PP_Var PepperPluginInstanceImpl::GetPluginReferrerURL(
2833 PP_Instance instance,
2834 PP_URLComponents_Dev* components) {
2835 blink::WebDocument document = container()->element().document();
2836 if (!full_frame_)
2837 return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(document.url(),
2838 components);
2839 WebLocalFrame* frame = document.frame();
2840 if (!frame)
2841 return PP_MakeUndefined();
2842 const WebURLRequest& request = frame->dataSource()->originalRequest();
2843 WebString referer = request.httpHeaderField("Referer");
2844 if (referer.isEmpty())
2845 return PP_MakeUndefined();
2846 return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(GURL(referer),
2847 components);
2850 PP_ExternalPluginResult PepperPluginInstanceImpl::ResetAsProxied(
2851 scoped_refptr<PluginModule> module) {
2852 // Save the original module and switch over to the new one now that this
2853 // plugin is using the IPC-based proxy.
2854 original_module_ = module_;
2855 module_ = module;
2857 // For NaCl instances, remember the NaCl plugin instance interface, so we
2858 // can shut it down by calling its DidDestroy in our Delete() method.
2859 original_instance_interface_.reset(instance_interface_.release());
2861 base::Callback<const void*(const char*)> get_plugin_interface_func =
2862 base::Bind(&PluginModule::GetPluginInterface, module_.get());
2863 PPP_Instance_Combined* ppp_instance_combined =
2864 PPP_Instance_Combined::Create(get_plugin_interface_func);
2865 if (!ppp_instance_combined) {
2866 // The proxy must support at least one usable PPP_Instance interface.
2867 // While this could be a failure to implement the interface in the NaCl
2868 // module, it is more likely that the NaCl process has crashed. Either
2869 // way, report that module initialization failed.
2870 return PP_EXTERNAL_PLUGIN_ERROR_MODULE;
2873 instance_interface_.reset(ppp_instance_combined);
2874 // Clear all PPP interfaces we may have cached.
2875 plugin_find_interface_ = NULL;
2876 plugin_input_event_interface_ = NULL;
2877 checked_for_plugin_input_event_interface_ = false;
2878 plugin_mouse_lock_interface_ = NULL;
2879 plugin_pdf_interface_ = NULL;
2880 checked_for_plugin_pdf_interface_ = false;
2881 plugin_private_interface_ = NULL;
2882 plugin_textinput_interface_ = NULL;
2884 // Re-send the DidCreate event via the proxy.
2885 scoped_ptr<const char * []> argn_array(StringVectorToArgArray(argn_));
2886 scoped_ptr<const char * []> argv_array(StringVectorToArgArray(argv_));
2887 if (!instance_interface_->DidCreate(
2888 pp_instance(), argn_.size(), argn_array.get(), argv_array.get()))
2889 return PP_EXTERNAL_PLUGIN_ERROR_INSTANCE;
2890 if (message_channel_)
2891 message_channel_->Start();
2893 // Clear sent_initial_did_change_view_ and cancel any pending DidChangeView
2894 // event. This way, SendDidChangeView will send the "current" view
2895 // immediately (before other events like HandleDocumentLoad).
2896 sent_initial_did_change_view_ = false;
2897 view_change_weak_ptr_factory_.InvalidateWeakPtrs();
2898 SendDidChangeView();
2900 DCHECK(external_document_load_);
2901 external_document_load_ = false;
2902 if (!external_document_response_.isNull()) {
2903 document_loader_ = NULL;
2904 // Pass the response to the new proxy.
2905 HandleDocumentLoad(external_document_response_);
2906 external_document_response_ = blink::WebURLResponse();
2907 // Replay any document load events we've received to the real loader.
2908 external_document_loader_->ReplayReceivedData(document_loader_);
2909 external_document_loader_.reset(NULL);
2912 return PP_EXTERNAL_PLUGIN_OK;
2915 bool PepperPluginInstanceImpl::IsValidInstanceOf(PluginModule* module) {
2916 DCHECK(module);
2917 return module == module_.get() || module == original_module_.get();
2920 PepperPluginInstance* PepperPluginInstance::Get(PP_Instance instance_id) {
2921 return HostGlobals::Get()->GetInstance(instance_id);
2924 RenderView* PepperPluginInstanceImpl::GetRenderView() {
2925 return render_frame_ ? render_frame_->render_view() : NULL;
2928 blink::WebPluginContainer* PepperPluginInstanceImpl::GetContainer() {
2929 return container_;
2932 v8::Isolate* PepperPluginInstanceImpl::GetIsolate() const { return isolate_; }
2934 ppapi::VarTracker* PepperPluginInstanceImpl::GetVarTracker() {
2935 return HostGlobals::Get()->GetVarTracker();
2938 const GURL& PepperPluginInstanceImpl::GetPluginURL() { return plugin_url_; }
2940 base::FilePath PepperPluginInstanceImpl::GetModulePath() {
2941 return module_->path();
2944 PP_Resource PepperPluginInstanceImpl::CreateImage(gfx::ImageSkia* source_image,
2945 float scale) {
2946 gfx::ImageSkiaRep image_skia_rep = source_image->GetRepresentation(scale);
2948 if (image_skia_rep.is_null() || image_skia_rep.scale() != scale)
2949 return 0;
2951 scoped_refptr<PPB_ImageData_Impl> image_data(
2952 new PPB_ImageData_Impl(pp_instance(), PPB_ImageData_Impl::PLATFORM));
2953 if (!image_data->Init(PPB_ImageData_Impl::GetNativeImageDataFormat(),
2954 image_skia_rep.pixel_width(),
2955 image_skia_rep.pixel_height(),
2956 false)) {
2957 return 0;
2960 ImageDataAutoMapper mapper(image_data.get());
2961 if (!mapper.is_valid())
2962 return 0;
2964 skia::PlatformCanvas* canvas = image_data->GetPlatformCanvas();
2965 // Note: Do not SkBitmap::copyTo the canvas bitmap directly because it will
2966 // ignore the allocated pixels in shared memory and re-allocate a new buffer.
2967 canvas->writePixels(image_skia_rep.sk_bitmap(), 0, 0);
2969 return image_data->GetReference();
2972 PP_ExternalPluginResult PepperPluginInstanceImpl::SwitchToOutOfProcessProxy(
2973 const base::FilePath& file_path,
2974 ppapi::PpapiPermissions permissions,
2975 const IPC::ChannelHandle& channel_handle,
2976 base::ProcessId plugin_pid,
2977 int plugin_child_id) {
2978 // Create a new module for each instance of the external plugin that is using
2979 // the IPC based out-of-process proxy. We can't use the existing module,
2980 // because it is configured for the in-process plugin, and we must keep it
2981 // that way to allow the page to create other instances.
2982 scoped_refptr<PluginModule> external_plugin_module(
2983 module_->CreateModuleForExternalPluginInstance());
2985 RendererPpapiHostImpl* renderer_ppapi_host =
2986 external_plugin_module->CreateOutOfProcessModule(render_frame_,
2987 file_path,
2988 permissions,
2989 channel_handle,
2990 plugin_pid,
2991 plugin_child_id,
2992 true);
2993 if (!renderer_ppapi_host) {
2994 DLOG(ERROR) << "CreateExternalPluginModule() failed";
2995 return PP_EXTERNAL_PLUGIN_ERROR_MODULE;
2998 // Finally, switch the instance to the proxy.
2999 return external_plugin_module->InitAsProxiedExternalPlugin(this);
3002 void PepperPluginInstanceImpl::SetAlwaysOnTop(bool on_top) {
3003 always_on_top_ = on_top;
3006 void PepperPluginInstanceImpl::DoSetCursor(WebCursorInfo* cursor) {
3007 cursor_.reset(cursor);
3008 if (fullscreen_container_) {
3009 fullscreen_container_->DidChangeCursor(*cursor);
3010 } else if (render_frame_) {
3011 render_frame_->PepperDidChangeCursor(this, *cursor);
3015 bool PepperPluginInstanceImpl::IsFullPagePlugin() {
3016 WebLocalFrame* frame = container()->element().document().frame();
3017 return frame->view()->mainFrame()->isWebLocalFrame() &&
3018 frame->view()->mainFrame()->document().isPluginDocument();
3021 bool PepperPluginInstanceImpl::FlashSetFullscreen(bool fullscreen,
3022 bool delay_report) {
3023 TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::FlashSetFullscreen");
3024 // Keep a reference on the stack. See NOTE above.
3025 scoped_refptr<PepperPluginInstanceImpl> ref(this);
3027 // We check whether we are trying to switch to the state we're already going
3028 // to (i.e. if we're already switching to fullscreen but the fullscreen
3029 // container isn't ready yet, don't do anything more).
3030 if (fullscreen == FlashIsFullscreenOrPending())
3031 return true;
3033 if (!render_frame_)
3034 return false;
3035 if (fullscreen && !render_frame_->render_view()
3036 ->renderer_preferences()
3037 .plugin_fullscreen_allowed)
3038 return false;
3040 // Unbind current 2D or 3D graphics context.
3041 DVLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
3042 if (fullscreen) {
3043 DCHECK(!fullscreen_container_);
3044 fullscreen_container_ =
3045 render_frame_->CreatePepperFullscreenContainer(this);
3046 UpdateLayer(false);
3047 } else {
3048 DCHECK(fullscreen_container_);
3049 fullscreen_container_->Destroy();
3050 fullscreen_container_ = NULL;
3051 UpdateFlashFullscreenState(false);
3052 if (!delay_report) {
3053 ReportGeometry();
3054 } else {
3055 base::ThreadTaskRunnerHandle::Get()->PostTask(
3056 FROM_HERE,
3057 base::Bind(&PepperPluginInstanceImpl::ReportGeometry, this));
3061 return true;
3064 bool PepperPluginInstanceImpl::IsRectTopmost(const gfx::Rect& rect) {
3065 if (flash_fullscreen_)
3066 return true;
3068 return container_->isRectTopmost(rect);
3071 int32_t PepperPluginInstanceImpl::Navigate(
3072 const ppapi::URLRequestInfoData& request,
3073 const char* target,
3074 bool from_user_action) {
3075 if (!container_)
3076 return PP_ERROR_FAILED;
3078 WebDocument document = container_->element().document();
3079 WebLocalFrame* frame = document.frame();
3080 if (!frame)
3081 return PP_ERROR_FAILED;
3083 ppapi::URLRequestInfoData completed_request = request;
3085 WebURLRequest web_request;
3086 if (!CreateWebURLRequest(
3087 pp_instance_, &completed_request, frame, &web_request)) {
3088 return PP_ERROR_FAILED;
3090 web_request.setFirstPartyForCookies(document.firstPartyForCookies());
3091 if (IsProcessingUserGesture())
3092 web_request.setHasUserGesture(true);
3094 GURL gurl(web_request.url());
3095 if (gurl.SchemeIs(url::kJavaScriptScheme)) {
3096 // In imitation of the NPAPI implementation, only |target_frame == frame| is
3097 // allowed for security reasons.
3098 WebFrame* target_frame =
3099 frame->view()->findFrameByName(WebString::fromUTF8(target), frame);
3100 if (target_frame != frame)
3101 return PP_ERROR_NOACCESS;
3103 // TODO(viettrungluu): NPAPI sends the result back to the plugin -- do we
3104 // need that?
3105 blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
3106 WebString result = container_->executeScriptURL(gurl, false);
3107 return result.isNull() ? PP_ERROR_FAILED : PP_OK;
3110 // Only GETs and POSTs are supported.
3111 if (web_request.httpMethod() != "GET" && web_request.httpMethod() != "POST")
3112 return PP_ERROR_BADARGUMENT;
3114 WebString target_str = WebString::fromUTF8(target);
3115 blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
3116 container_->loadFrameRequest(web_request, target_str, false, NULL);
3117 return PP_OK;
3120 int PepperPluginInstanceImpl::MakePendingFileRefRendererHost(
3121 const base::FilePath& path) {
3122 RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
3123 PepperFileRefRendererHost* file_ref_host(
3124 new PepperFileRefRendererHost(host_impl, pp_instance(), 0, path));
3125 return host_impl->GetPpapiHost()->AddPendingResourceHost(
3126 scoped_ptr<ppapi::host::ResourceHost>(file_ref_host));
3129 void PepperPluginInstanceImpl::SetEmbedProperty(PP_Var key, PP_Var value) {
3130 if (message_channel_)
3131 message_channel_->SetReadOnlyProperty(key, value);
3134 bool PepperPluginInstanceImpl::CanAccessMainFrame() const {
3135 if (!container_)
3136 return false;
3137 blink::WebDocument containing_document = container_->element().document();
3139 if (!containing_document.frame() || !containing_document.frame()->view() ||
3140 !containing_document.frame()->view()->mainFrame()) {
3141 return false;
3143 blink::WebDocument main_document =
3144 containing_document.frame()->view()->mainFrame()->document();
3146 return containing_document.securityOrigin().canAccess(
3147 main_document.securityOrigin());
3150 void PepperPluginInstanceImpl::KeepSizeAttributesBeforeFullscreen() {
3151 WebElement element = container_->element();
3152 width_before_fullscreen_ = element.getAttribute(WebString::fromUTF8(kWidth));
3153 height_before_fullscreen_ =
3154 element.getAttribute(WebString::fromUTF8(kHeight));
3155 border_before_fullscreen_ =
3156 element.getAttribute(WebString::fromUTF8(kBorder));
3157 style_before_fullscreen_ = element.getAttribute(WebString::fromUTF8(kStyle));
3160 void PepperPluginInstanceImpl::SetSizeAttributesForFullscreen() {
3161 if (!render_frame_)
3162 return;
3164 // TODO(miu): Revisit this logic. If the style must be modified for correct
3165 // behavior, the width and height should probably be set to 100%, rather than
3166 // a fixed screen size.
3168 blink::WebScreenInfo info = render_frame_->GetRenderWidget()->screenInfo();
3169 screen_size_for_fullscreen_ = gfx::Size(info.rect.width, info.rect.height);
3170 std::string width = base::IntToString(screen_size_for_fullscreen_.width());
3171 std::string height = base::IntToString(screen_size_for_fullscreen_.height());
3173 WebElement element = container_->element();
3174 element.setAttribute(WebString::fromUTF8(kWidth), WebString::fromUTF8(width));
3175 element.setAttribute(WebString::fromUTF8(kHeight),
3176 WebString::fromUTF8(height));
3177 element.setAttribute(WebString::fromUTF8(kBorder), WebString::fromUTF8("0"));
3179 // There should be no style settings that matter in fullscreen mode,
3180 // so just replace them instead of appending.
3181 // NOTE: "position: fixed" and "display: block" reset the plugin and
3182 // using %% settings might not work without them (e.g. if the plugin is a
3183 // child of a container element).
3184 std::string style;
3185 style += StringPrintf("width: %s !important; ", width.c_str());
3186 style += StringPrintf("height: %s !important; ", height.c_str());
3187 style += "margin: 0 !important; padding: 0 !important; border: 0 !important";
3188 container_->element().setAttribute(kStyle, WebString::fromUTF8(style));
3191 void PepperPluginInstanceImpl::ResetSizeAttributesAfterFullscreen() {
3192 screen_size_for_fullscreen_ = gfx::Size();
3193 WebElement element = container_->element();
3194 element.setAttribute(WebString::fromUTF8(kWidth), width_before_fullscreen_);
3195 element.setAttribute(WebString::fromUTF8(kHeight), height_before_fullscreen_);
3196 element.setAttribute(WebString::fromUTF8(kBorder), border_before_fullscreen_);
3197 element.setAttribute(WebString::fromUTF8(kStyle), style_before_fullscreen_);
3200 bool PepperPluginInstanceImpl::IsMouseLocked() {
3201 return GetMouseLockDispatcher()->IsMouseLockedTo(
3202 GetOrCreateLockTargetAdapter());
3205 bool PepperPluginInstanceImpl::LockMouse() {
3206 return GetMouseLockDispatcher()->LockMouse(GetOrCreateLockTargetAdapter());
3209 MouseLockDispatcher::LockTarget*
3210 PepperPluginInstanceImpl::GetOrCreateLockTargetAdapter() {
3211 if (!lock_target_.get()) {
3212 lock_target_.reset(new PluginInstanceLockTarget(this));
3214 return lock_target_.get();
3217 MouseLockDispatcher* PepperPluginInstanceImpl::GetMouseLockDispatcher() {
3218 if (flash_fullscreen_) {
3219 RenderWidgetFullscreenPepper* container =
3220 static_cast<RenderWidgetFullscreenPepper*>(fullscreen_container_);
3221 return container->mouse_lock_dispatcher();
3222 } else if (render_frame_) {
3223 return render_frame_->render_view()->mouse_lock_dispatcher();
3225 return NULL;
3228 void PepperPluginInstanceImpl::UnSetAndDeleteLockTargetAdapter() {
3229 if (lock_target_.get()) {
3230 GetMouseLockDispatcher()->OnLockTargetDestroyed(lock_target_.get());
3231 lock_target_.reset();
3235 void PepperPluginInstanceImpl::DidDataFromWebURLResponse(
3236 const blink::WebURLResponse& response,
3237 int pending_host_id,
3238 const ppapi::URLResponseInfoData& data) {
3239 if (is_deleted_)
3240 return;
3242 RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
3244 if (host_impl->in_process_router()) {
3245 // Running in-process, we can just create the resource and call the
3246 // PPP_Instance function directly.
3247 scoped_refptr<ppapi::proxy::URLLoaderResource> loader_resource(
3248 new ppapi::proxy::URLLoaderResource(
3249 host_impl->in_process_router()->GetPluginConnection(pp_instance()),
3250 pp_instance(),
3251 pending_host_id,
3252 data));
3254 PP_Resource loader_pp_resource = loader_resource->GetReference();
3255 if (!instance_interface_->HandleDocumentLoad(pp_instance(),
3256 loader_pp_resource))
3257 loader_resource->Close();
3258 // We don't pass a ref into the plugin, if it wants one, it will have taken
3259 // an additional one.
3260 ppapi::PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(
3261 loader_pp_resource);
3262 } else {
3263 // Running out-of-process. Initiate an IPC call to notify the plugin
3264 // process.
3265 ppapi::proxy::HostDispatcher* dispatcher =
3266 ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
3267 dispatcher->Send(new PpapiMsg_PPPInstance_HandleDocumentLoad(
3268 ppapi::API_ID_PPP_INSTANCE, pp_instance(), pending_host_id, data));
3272 void PepperPluginInstanceImpl::RecordFlashJavaScriptUse() {
3273 if (initialized_ && !javascript_used_ && is_flash_plugin_) {
3274 javascript_used_ = true;
3275 RenderThread::Get()->RecordAction(
3276 base::UserMetricsAction("Flash.JavaScriptUsed"));
3280 } // namespace content