1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/bit_cast.h"
11 #include "base/callback_helpers.h"
12 #include "base/i18n/char_iterator.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_offset_string_conversions.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "base/time/time.h"
24 #include "base/trace_event/trace_event.h"
25 #include "build/build_config.h"
26 #include "cc/layers/texture_layer.h"
27 #include "content/common/content_constants_internal.h"
28 #include "content/common/frame_messages.h"
29 #include "content/public/common/content_constants.h"
30 #include "content/public/common/use_zoom_for_dsf_policy.h"
31 #include "content/public/renderer/content_renderer_client.h"
32 #include "content/renderer/pepper/event_conversion.h"
33 #include "content/renderer/pepper/gfx_conversion.h"
34 #include "content/renderer/pepper/host_dispatcher_wrapper.h"
35 #include "content/renderer/pepper/host_globals.h"
36 #include "content/renderer/pepper/message_channel.h"
37 #include "content/renderer/pepper/pepper_audio_controller.h"
38 #include "content/renderer/pepper/pepper_browser_connection.h"
39 #include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
40 #include "content/renderer/pepper/pepper_graphics_2d_host.h"
41 #include "content/renderer/pepper/pepper_in_process_router.h"
42 #include "content/renderer/pepper/pepper_try_catch.h"
43 #include "content/renderer/pepper/pepper_url_loader_host.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/sad_plugin.h"
58 #include "device/gamepad/public/cpp/gamepads.h"
59 #include "ppapi/c/dev/ppp_text_input_dev.h"
60 #include "ppapi/c/pp_rect.h"
61 #include "ppapi/c/ppb_audio_config.h"
62 #include "ppapi/c/ppb_core.h"
63 #include "ppapi/c/ppb_gamepad.h"
64 #include "ppapi/c/ppp_input_event.h"
65 #include "ppapi/c/ppp_instance.h"
66 #include "ppapi/c/ppp_messaging.h"
67 #include "ppapi/c/ppp_mouse_lock.h"
68 #include "ppapi/c/private/ppb_find_private.h"
69 #include "ppapi/c/private/ppp_find_private.h"
70 #include "ppapi/c/private/ppp_instance_private.h"
71 #include "ppapi/c/private/ppp_pdf.h"
72 #include "ppapi/host/ppapi_host.h"
73 #include "ppapi/proxy/ppapi_messages.h"
74 #include "ppapi/proxy/serialized_var.h"
75 #include "ppapi/proxy/uma_private_resource.h"
76 #include "ppapi/proxy/url_loader_resource.h"
77 #include "ppapi/shared_impl/ppapi_permissions.h"
78 #include "ppapi/shared_impl/ppb_gamepad_shared.h"
79 #include "ppapi/shared_impl/ppb_input_event_shared.h"
80 #include "ppapi/shared_impl/ppb_url_util_shared.h"
81 #include "ppapi/shared_impl/ppb_view_shared.h"
82 #include "ppapi/shared_impl/ppp_instance_combined.h"
83 #include "ppapi/shared_impl/resource.h"
84 #include "ppapi/shared_impl/scoped_pp_resource.h"
85 #include "ppapi/shared_impl/scoped_pp_var.h"
86 #include "ppapi/shared_impl/time_conversion.h"
87 #include "ppapi/shared_impl/url_request_info_data.h"
88 #include "ppapi/shared_impl/var.h"
89 #include "ppapi/thunk/enter.h"
90 #include "ppapi/thunk/ppb_buffer_api.h"
91 #include "printing/buildflags/buildflags.h"
92 #include "printing/mojom/print.mojom.h"
93 #include "skia/ext/platform_canvas.h"
94 #include "third_party/blink/public/common/input/web_coalesced_input_event.h"
95 #include "third_party/blink/public/common/input/web_input_event.h"
96 #include "third_party/blink/public/common/input/web_keyboard_event.h"
97 #include "third_party/blink/public/common/input/web_mouse_event.h"
98 #include "third_party/blink/public/common/input/web_pointer_event.h"
99 #include "third_party/blink/public/common/input/web_touch_event.h"
100 #include "third_party/blink/public/platform/url_conversion.h"
101 #include "third_party/blink/public/platform/web_rect.h"
102 #include "third_party/blink/public/platform/web_security_origin.h"
103 #include "third_party/blink/public/platform/web_string.h"
104 #include "third_party/blink/public/platform/web_url.h"
105 #include "third_party/blink/public/platform/web_url_error.h"
106 #include "third_party/blink/public/platform/web_url_request.h"
107 #include "third_party/blink/public/web/modules/media/audio/web_audio_device_factory.h"
108 #include "third_party/blink/public/web/web_document.h"
109 #include "third_party/blink/public/web/web_document_loader.h"
110 #include "third_party/blink/public/web/web_frame_widget.h"
111 #include "third_party/blink/public/web/web_local_frame.h"
112 #include "third_party/blink/public/web/web_plugin_container.h"
113 #include "third_party/blink/public/web/web_plugin_script_forbidden_scope.h"
114 #include "third_party/blink/public/web/web_print_params.h"
115 #include "third_party/blink/public/web/web_print_preset_options.h"
116 #include "third_party/blink/public/web/web_script_source.h"
117 #include "third_party/blink/public/web/web_view.h"
118 #include "third_party/khronos/GLES2/gl2.h"
119 #include "ui/events/base_event_utils.h"
120 #include "ui/events/blink/blink_event_util.h"
121 #include "ui/events/blink/web_input_event.h"
122 #include "ui/events/keycodes/dom/dom_code.h"
123 #include "ui/gfx/geometry/point.h"
124 #include "ui/gfx/geometry/rect_conversions.h"
125 #include "ui/gfx/image/image_skia.h"
126 #include "ui/gfx/image/image_skia_rep.h"
127 #include "ui/gfx/range/range.h"
128 #include "url/origin.h"
129 #include "v8/include/v8.h"
130 
131 #if BUILDFLAG(ENABLE_PRINTING)
132 // nogncheck because dependency on //printing is conditional upon
133 // enable_basic_printing flags.
134 #include "printing/metafile_skia.h"          // nogncheck
135 #endif
136 
137 #if defined(OS_CHROMEOS)
138 #include "ui/events/keycodes/keyboard_codes_posix.h"
139 #endif
140 
141 // Windows defines 'PostMessage', so we have to undef it.
142 #ifdef PostMessage
143 #undef PostMessage
144 #endif
145 
146 using base::StringPrintf;
147 using ppapi::InputEventData;
148 using ppapi::PpapiGlobals;
149 using ppapi::PPB_InputEvent_Shared;
150 using ppapi::PPB_View_Shared;
151 using ppapi::PPP_Instance_Combined;
152 using ppapi::Resource;
153 using ppapi::ScopedPPResource;
154 using ppapi::ScopedPPVar;
155 using ppapi::StringVar;
156 using ppapi::TrackedCallback;
157 using ppapi::thunk::EnterResourceNoLock;
158 using ppapi::thunk::PPB_Buffer_API;
159 using ppapi::thunk::PPB_Gamepad_API;
160 using ppapi::thunk::PPB_Graphics2D_API;
161 using ppapi::thunk::PPB_Graphics3D_API;
162 using ppapi::thunk::PPB_ImageData_API;
163 using ppapi::Var;
164 using ppapi::ArrayBufferVar;
165 using ppapi::ViewData;
166 using blink::WebDocument;
167 using blink::WebElement;
168 using blink::WebFrame;
169 using blink::WebInputEvent;
170 using blink::WebLocalFrame;
171 using blink::WebPlugin;
172 using blink::WebPluginContainer;
173 using blink::WebPrintParams;
174 using blink::WebString;
175 using blink::WebURLError;
176 using blink::WebAssociatedURLLoaderClient;
177 using blink::WebURLRequest;
178 using blink::WebURLResponse;
179 using blink::WebView;
180 using blink::WebWidget;
181 
182 namespace content {
183 
184 namespace {
185 
186 #ifndef STATIC_ASSERT_ENUM
187 #define STATIC_ASSERT_ENUM(a, b)                            \
188   static_assert(static_cast<int>(a) == static_cast<int>(b), \
189                 "mismatching enums: " #a)
190 #endif
191 
192 // Check PP_TextInput_Type and ui::TextInputType are kept in sync.
193 STATIC_ASSERT_ENUM(ui::TEXT_INPUT_TYPE_NONE, PP_TEXTINPUT_TYPE_NONE);
194 STATIC_ASSERT_ENUM(ui::TEXT_INPUT_TYPE_TEXT, PP_TEXTINPUT_TYPE_TEXT);
195 STATIC_ASSERT_ENUM(ui::TEXT_INPUT_TYPE_PASSWORD, PP_TEXTINPUT_TYPE_PASSWORD);
196 STATIC_ASSERT_ENUM(ui::TEXT_INPUT_TYPE_SEARCH, PP_TEXTINPUT_TYPE_SEARCH);
197 STATIC_ASSERT_ENUM(ui::TEXT_INPUT_TYPE_EMAIL, PP_TEXTINPUT_TYPE_EMAIL);
198 STATIC_ASSERT_ENUM(ui::TEXT_INPUT_TYPE_NUMBER, PP_TEXTINPUT_TYPE_NUMBER);
199 STATIC_ASSERT_ENUM(ui::TEXT_INPUT_TYPE_TELEPHONE, PP_TEXTINPUT_TYPE_TELEPHONE);
200 STATIC_ASSERT_ENUM(ui::TEXT_INPUT_TYPE_URL, PP_TEXTINPUT_TYPE_URL);
201 
202 // The default text input type is to regard the plugin always accept text input.
203 // This is for allowing users to use input methods even on completely-IME-
204 // unaware plugins (e.g., PDF plugin for M16).
205 // Plugins need to explicitly opt out the text input mode if they know
206 // that they don't accept texts.
207 const ui::TextInputType kPluginDefaultTextInputType = ui::TEXT_INPUT_TYPE_TEXT;
208 
209 // <embed>/<object> attributes.
210 const char kWidth[] = "width";
211 const char kHeight[] = "height";
212 const char kBorder[] = "border";  // According to w3c, deprecated.
213 const char kStyle[] = "style";
214 
215 #define STATIC_ASSERT_MATCHING_ENUM(webkit_name, np_name)               \
216   static_assert(static_cast<int>(ui::mojom::CursorType::webkit_name) == \
217                     static_cast<int>(np_name),                          \
218                 "mismatching enums: " #webkit_name)
219 
220 STATIC_ASSERT_MATCHING_ENUM(kPointer, PP_MOUSECURSOR_TYPE_POINTER);
221 STATIC_ASSERT_MATCHING_ENUM(kCross, PP_MOUSECURSOR_TYPE_CROSS);
222 STATIC_ASSERT_MATCHING_ENUM(kHand, PP_MOUSECURSOR_TYPE_HAND);
223 STATIC_ASSERT_MATCHING_ENUM(kIBeam, PP_MOUSECURSOR_TYPE_IBEAM);
224 STATIC_ASSERT_MATCHING_ENUM(kWait, PP_MOUSECURSOR_TYPE_WAIT);
225 STATIC_ASSERT_MATCHING_ENUM(kHelp, PP_MOUSECURSOR_TYPE_HELP);
226 STATIC_ASSERT_MATCHING_ENUM(kEastResize, PP_MOUSECURSOR_TYPE_EASTRESIZE);
227 STATIC_ASSERT_MATCHING_ENUM(kNorthResize, PP_MOUSECURSOR_TYPE_NORTHRESIZE);
228 STATIC_ASSERT_MATCHING_ENUM(kNorthEastResize,
229                             PP_MOUSECURSOR_TYPE_NORTHEASTRESIZE);
230 STATIC_ASSERT_MATCHING_ENUM(kNorthWestResize,
231                             PP_MOUSECURSOR_TYPE_NORTHWESTRESIZE);
232 STATIC_ASSERT_MATCHING_ENUM(kSouthResize, PP_MOUSECURSOR_TYPE_SOUTHRESIZE);
233 STATIC_ASSERT_MATCHING_ENUM(kSouthEastResize,
234                             PP_MOUSECURSOR_TYPE_SOUTHEASTRESIZE);
235 STATIC_ASSERT_MATCHING_ENUM(kSouthWestResize,
236                             PP_MOUSECURSOR_TYPE_SOUTHWESTRESIZE);
237 STATIC_ASSERT_MATCHING_ENUM(kWestResize, PP_MOUSECURSOR_TYPE_WESTRESIZE);
238 STATIC_ASSERT_MATCHING_ENUM(kNorthSouthResize,
239                             PP_MOUSECURSOR_TYPE_NORTHSOUTHRESIZE);
240 STATIC_ASSERT_MATCHING_ENUM(kEastWestResize,
241                             PP_MOUSECURSOR_TYPE_EASTWESTRESIZE);
242 STATIC_ASSERT_MATCHING_ENUM(kNorthEastSouthWestResize,
243                             PP_MOUSECURSOR_TYPE_NORTHEASTSOUTHWESTRESIZE);
244 STATIC_ASSERT_MATCHING_ENUM(kNorthWestSouthEastResize,
245                             PP_MOUSECURSOR_TYPE_NORTHWESTSOUTHEASTRESIZE);
246 STATIC_ASSERT_MATCHING_ENUM(kColumnResize, PP_MOUSECURSOR_TYPE_COLUMNRESIZE);
247 STATIC_ASSERT_MATCHING_ENUM(kRowResize, PP_MOUSECURSOR_TYPE_ROWRESIZE);
248 STATIC_ASSERT_MATCHING_ENUM(kMiddlePanning, PP_MOUSECURSOR_TYPE_MIDDLEPANNING);
249 STATIC_ASSERT_MATCHING_ENUM(kEastPanning, PP_MOUSECURSOR_TYPE_EASTPANNING);
250 STATIC_ASSERT_MATCHING_ENUM(kNorthPanning, PP_MOUSECURSOR_TYPE_NORTHPANNING);
251 STATIC_ASSERT_MATCHING_ENUM(kNorthEastPanning,
252                             PP_MOUSECURSOR_TYPE_NORTHEASTPANNING);
253 STATIC_ASSERT_MATCHING_ENUM(kNorthWestPanning,
254                             PP_MOUSECURSOR_TYPE_NORTHWESTPANNING);
255 STATIC_ASSERT_MATCHING_ENUM(kSouthPanning, PP_MOUSECURSOR_TYPE_SOUTHPANNING);
256 STATIC_ASSERT_MATCHING_ENUM(kSouthEastPanning,
257                             PP_MOUSECURSOR_TYPE_SOUTHEASTPANNING);
258 STATIC_ASSERT_MATCHING_ENUM(kSouthWestPanning,
259                             PP_MOUSECURSOR_TYPE_SOUTHWESTPANNING);
260 STATIC_ASSERT_MATCHING_ENUM(kWestPanning, PP_MOUSECURSOR_TYPE_WESTPANNING);
261 STATIC_ASSERT_MATCHING_ENUM(kMove, PP_MOUSECURSOR_TYPE_MOVE);
262 STATIC_ASSERT_MATCHING_ENUM(kVerticalText, PP_MOUSECURSOR_TYPE_VERTICALTEXT);
263 STATIC_ASSERT_MATCHING_ENUM(kCell, PP_MOUSECURSOR_TYPE_CELL);
264 STATIC_ASSERT_MATCHING_ENUM(kContextMenu, PP_MOUSECURSOR_TYPE_CONTEXTMENU);
265 STATIC_ASSERT_MATCHING_ENUM(kAlias, PP_MOUSECURSOR_TYPE_ALIAS);
266 STATIC_ASSERT_MATCHING_ENUM(kProgress, PP_MOUSECURSOR_TYPE_PROGRESS);
267 STATIC_ASSERT_MATCHING_ENUM(kNoDrop, PP_MOUSECURSOR_TYPE_NODROP);
268 STATIC_ASSERT_MATCHING_ENUM(kCopy, PP_MOUSECURSOR_TYPE_COPY);
269 STATIC_ASSERT_MATCHING_ENUM(kNone, PP_MOUSECURSOR_TYPE_NONE);
270 STATIC_ASSERT_MATCHING_ENUM(kNotAllowed, PP_MOUSECURSOR_TYPE_NOTALLOWED);
271 STATIC_ASSERT_MATCHING_ENUM(kZoomIn, PP_MOUSECURSOR_TYPE_ZOOMIN);
272 STATIC_ASSERT_MATCHING_ENUM(kZoomOut, PP_MOUSECURSOR_TYPE_ZOOMOUT);
273 STATIC_ASSERT_MATCHING_ENUM(kGrab, PP_MOUSECURSOR_TYPE_GRAB);
274 STATIC_ASSERT_MATCHING_ENUM(kGrabbing, PP_MOUSECURSOR_TYPE_GRABBING);
275 STATIC_ASSERT_MATCHING_ENUM(kMiddlePanningVertical,
276                             PP_MOUSECURSOR_TYPE_MIDDLEPANNINGVERTICAL);
277 STATIC_ASSERT_MATCHING_ENUM(kMiddlePanningHorizontal,
278                             PP_MOUSECURSOR_TYPE_MIDDLEPANNINGHORIZONTAL);
279 // Do not assert kCustom == PP_CURSORTYPE_CUSTOM;
280 // PP_CURSORTYPE_CUSTOM is pinned to allow new cursor types.
281 
282 #undef STATIC_ASSERT_MATCHING_ENUM
283 
284 STATIC_ASSERT_ENUM(printing::mojom::PrintScalingOption::kNone,
285                    PP_PRINTSCALINGOPTION_NONE);
286 STATIC_ASSERT_ENUM(printing::mojom::PrintScalingOption::kFitToPrintableArea,
287                    PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA);
288 STATIC_ASSERT_ENUM(printing::mojom::PrintScalingOption::kSourceSize,
289                    PP_PRINTSCALINGOPTION_SOURCE_SIZE);
290 STATIC_ASSERT_ENUM(printing::mojom::PrintScalingOption::kFitToPaper,
291                    PP_PRINTSCALINGOPTION_FIT_TO_PAPER);
292 
293 #undef STATIC_ASSERT_ENUM
294 
295 // Sets |*security_origin| to be the WebKit security origin associated with the
296 // document containing the given plugin instance. On success, returns true. If
297 // the instance is invalid, returns false and |*security_origin| will be
298 // unchanged.
SecurityOriginForInstance(PP_Instance instance_id,blink::WebSecurityOrigin * security_origin)299 bool SecurityOriginForInstance(PP_Instance instance_id,
300                                blink::WebSecurityOrigin* security_origin) {
301   PepperPluginInstanceImpl* instance =
302       HostGlobals::Get()->GetInstance(instance_id);
303   if (!instance)
304     return false;
305 
306   *security_origin = instance->container()->GetDocument().GetSecurityOrigin();
307   return true;
308 }
309 
310 // Convert the given vector to an array of C-strings. The strings in the
311 // returned vector are only guaranteed valid so long as the vector of strings
312 // is not modified.
StringVectorToArgArray(const std::vector<std::string> & vector)313 std::unique_ptr<const char* []> StringVectorToArgArray(
314     const std::vector<std::string>& vector) {
315   auto array = std::make_unique<const char* []>(vector.size());
316   for (size_t i = 0; i < vector.size(); ++i)
317     array[i] = vector[i].c_str();
318   return array;
319 }
320 
321 // Returns true if this is a "system reserved" key which should not be sent to
322 // a plugin. Some poorly behaving plugins incorrectly report that they handle
323 // all keys sent to them. This can prevent keystrokes from working for things
324 // like screen brightness and volume control.
IsReservedSystemInputEvent(const blink::WebInputEvent & event)325 bool IsReservedSystemInputEvent(const blink::WebInputEvent& event) {
326 #if defined(OS_CHROMEOS)
327   if (event.GetType() != WebInputEvent::Type::kKeyDown &&
328       event.GetType() != WebInputEvent::Type::kKeyUp)
329     return false;
330   const blink::WebKeyboardEvent& key_event =
331       static_cast<const blink::WebKeyboardEvent&>(event);
332   switch (key_event.windows_key_code) {
333     case ui::VKEY_BRIGHTNESS_DOWN:
334     case ui::VKEY_BRIGHTNESS_UP:
335     case ui::VKEY_KBD_BRIGHTNESS_DOWN:
336     case ui::VKEY_KBD_BRIGHTNESS_UP:
337     case ui::VKEY_VOLUME_MUTE:
338     case ui::VKEY_VOLUME_DOWN:
339     case ui::VKEY_VOLUME_UP:
340       return true;
341     default:
342       return false;
343   }
344 #endif  // defined(OS_CHROMEOS)
345   return false;
346 }
347 
PrintPDFOutput(PP_Resource print_output,printing::MetafileSkia * metafile)348 void PrintPDFOutput(PP_Resource print_output,
349                     printing::MetafileSkia* metafile) {
350 #if BUILDFLAG(ENABLE_PRINTING)
351   DCHECK(metafile);
352 
353   ppapi::thunk::EnterResourceNoLock<PPB_Buffer_API> enter(print_output, true);
354   if (enter.failed())
355     return;
356 
357   BufferAutoMapper mapper(enter.object());
358   if (!mapper.data() || !mapper.size()) {
359     NOTREACHED();
360     return;
361   }
362 
363   metafile->InitFromData(mapper);
364 #endif  // BUILDFLAG(ENABLE_PRINTING)
365 }
366 
367 constexpr char kChromePrint[] = "chrome://print/";
368 
IsPrintPreviewUrl(const GURL & document_url)369 bool IsPrintPreviewUrl(const GURL& document_url) {
370   return url::Origin::Create(document_url.GetOrigin()) ==
371          url::Origin::Create(GURL(kChromePrint));
372 }
373 
FindPdfViewerScroller(const WebLocalFrame * frame,const WebElement & plugin)374 WebElement FindPdfViewerScroller(const WebLocalFrame* frame,
375                                  const WebElement& plugin) {
376   if (!plugin.HasAttribute("pdf-viewer-update-enabled"))
377     return WebElement();
378 
379   WebElement viewer = frame->GetDocument().GetElementById("viewer");
380   if (viewer.IsNull())
381     return WebElement();
382 
383   blink::WebNode shadow_root = viewer.ShadowRoot();
384   if (shadow_root.IsNull())
385     return WebElement();
386 
387   return shadow_root.QuerySelector("#scroller");
388 }
389 
390 }  // namespace
391 
392 // static
Create(RenderFrameImpl * render_frame,PluginModule * module,WebPluginContainer * container,const GURL & plugin_url)393 PepperPluginInstanceImpl* PepperPluginInstanceImpl::Create(
394     RenderFrameImpl* render_frame,
395     PluginModule* module,
396     WebPluginContainer* container,
397     const GURL& plugin_url) {
398   base::RepeatingCallback<const void*(const char*)> get_plugin_interface_func =
399       base::BindRepeating(&PluginModule::GetPluginInterface, module);
400   PPP_Instance_Combined* ppp_instance_combined =
401       PPP_Instance_Combined::Create(std::move(get_plugin_interface_func));
402   if (!ppp_instance_combined)
403     return nullptr;
404 
405   return new PepperPluginInstanceImpl(render_frame,
406                                       module,
407                                       ppp_instance_combined,
408                                       container,
409                                       plugin_url);
410 }
411 
412 // static
Get(PP_Instance instance_id)413 PepperPluginInstance* PepperPluginInstance::Get(PP_Instance instance_id) {
414   PepperPluginInstanceImpl* instance =
415       PepperPluginInstanceImpl::GetForTesting(instance_id);
416   if (instance && !instance->is_deleted())
417     return instance;
418   return nullptr;
419 }
420 
421 // static
GetForTesting(PP_Instance instance_id)422 PepperPluginInstanceImpl* PepperPluginInstanceImpl::GetForTesting(
423     PP_Instance instance_id) {
424   PepperPluginInstanceImpl* instance =
425       HostGlobals::Get()->GetInstance(instance_id);
426   return instance;
427 }
428 
ExternalDocumentLoader()429 PepperPluginInstanceImpl::ExternalDocumentLoader::ExternalDocumentLoader()
430     : finished_loading_(false) {}
431 
~ExternalDocumentLoader()432 PepperPluginInstanceImpl::ExternalDocumentLoader::~ExternalDocumentLoader() {}
433 
ReplayReceivedData(WebAssociatedURLLoaderClient * document_loader)434 void PepperPluginInstanceImpl::ExternalDocumentLoader::ReplayReceivedData(
435     WebAssociatedURLLoaderClient* document_loader) {
436   for (auto it = data_.begin(); it != data_.end(); ++it) {
437     document_loader->DidReceiveData(it->c_str(), it->length());
438   }
439   if (finished_loading_) {
440     document_loader->DidFinishLoading();
441   } else if (error_.get()) {
442     DCHECK(!finished_loading_);
443     document_loader->DidFail(*error_);
444   }
445 }
446 
DidReceiveData(const char * data,int data_length)447 void PepperPluginInstanceImpl::ExternalDocumentLoader::DidReceiveData(
448     const char* data,
449     int data_length) {
450   data_.push_back(std::string(data, data_length));
451 }
452 
DidFinishLoading()453 void PepperPluginInstanceImpl::ExternalDocumentLoader::DidFinishLoading() {
454   DCHECK(!finished_loading_);
455 
456   if (error_.get())
457     return;
458 
459   finished_loading_ = true;
460 }
461 
DidFail(const WebURLError & error)462 void PepperPluginInstanceImpl::ExternalDocumentLoader::DidFail(
463     const WebURLError& error) {
464   DCHECK(!error_.get());
465 
466   if (finished_loading_)
467     return;
468 
469   error_ = std::make_unique<WebURLError>(error);
470 }
471 
GamepadImpl()472 PepperPluginInstanceImpl::GamepadImpl::GamepadImpl()
473     : Resource(ppapi::Resource::Untracked()) {}
474 
~GamepadImpl()475 PepperPluginInstanceImpl::GamepadImpl::~GamepadImpl() {}
476 
AsPPB_Gamepad_API()477 PPB_Gamepad_API* PepperPluginInstanceImpl::GamepadImpl::AsPPB_Gamepad_API() {
478   return this;
479 }
480 
Sample(PP_Instance instance,PP_GamepadsSampleData * data)481 void PepperPluginInstanceImpl::GamepadImpl::Sample(
482     PP_Instance instance,
483     PP_GamepadsSampleData* data) {
484   // This gamepad singleton resource method should not be called
485   NOTREACHED();
486 }
487 
PepperPluginInstanceImpl(RenderFrameImpl * render_frame,PluginModule * module,ppapi::PPP_Instance_Combined * instance_interface,WebPluginContainer * container,const GURL & plugin_url)488 PepperPluginInstanceImpl::PepperPluginInstanceImpl(
489     RenderFrameImpl* render_frame,
490     PluginModule* module,
491     ppapi::PPP_Instance_Combined* instance_interface,
492     WebPluginContainer* container,
493     const GURL& plugin_url)
494     : RenderFrameObserver(render_frame),
495       render_frame_(render_frame),
496       module_(module),
497       instance_interface_(instance_interface),
498       pp_instance_(0),
499       graphics2d_translation_(0, 0),
500       graphics2d_scale_(1.f),
501       container_(container),
502       layer_is_hardware_(false),
503       plugin_url_(plugin_url),
504       document_url_(container ? GURL(container->GetDocument().Url()) : GURL()),
505       has_been_clicked_(false),
506       full_frame_(false),
507       viewport_to_dip_scale_(1.0f),
508       sent_initial_did_change_view_(false),
509       bound_graphics_2d_platform_(nullptr),
510       has_webkit_focus_(false),
511       find_identifier_(-1),
512       plugin_find_interface_(nullptr),
513       plugin_input_event_interface_(nullptr),
514       plugin_mouse_lock_interface_(nullptr),
515       plugin_pdf_interface_(nullptr),
516       plugin_private_interface_(nullptr),
517       plugin_textinput_interface_(nullptr),
518       checked_for_plugin_input_event_interface_(false),
519       checked_for_plugin_pdf_interface_(false),
520       metafile_(nullptr),
521       gamepad_impl_(new GamepadImpl()),
522       uma_private_impl_(nullptr),
523       plugin_print_interface_(nullptr),
524       always_on_top_(false),
525       desired_fullscreen_state_(false),
526       message_channel_(nullptr),
527       input_event_mask_(0),
528       filtered_input_event_mask_(0),
529       text_input_type_(kPluginDefaultTextInputType),
530       selection_caret_(0),
531       selection_anchor_(0),
532       document_loader_(nullptr),
533       external_document_load_(false),
534       isolate_(v8::Isolate::GetCurrent()),
535       is_deleted_(false),
536       initialized_(false),
537       created_in_process_instance_(false),
538       audio_controller_(std::make_unique<PepperAudioController>(this)) {
539   pp_instance_ = HostGlobals::Get()->AddInstance(this);
540 
541   memset(&current_print_settings_, 0, sizeof(current_print_settings_));
542   module_->InstanceCreated(this);
543 
544   if (render_frame_) {  // NULL in tests or if the frame has been destroyed.
545     render_frame_->PepperInstanceCreated(this);
546     view_data_.is_page_visible =
547         !render_frame_->GetLocalRootRenderWidget()->GetWebWidget()->IsHidden();
548 
549     if (!module_->IsProxied()) {
550       created_in_process_instance_ = true;
551       PepperBrowserConnection* browser_connection =
552           PepperBrowserConnection::Get(render_frame_);
553       browser_connection->DidCreateInProcessInstance(
554           pp_instance(),
555           render_frame_->GetRoutingID(),
556           document_url_,
557           GetPluginURL());
558     }
559   }
560 
561   RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
562   resource_creation_ = host_impl->CreateInProcessResourceCreationAPI(this);
563 
564   if (GetContentClient()->renderer() &&  // NULL in unit tests.
565       GetContentClient()->renderer()->IsExternalPepperPlugin(module->name()))
566     external_document_load_ = true;
567 }
568 
~PepperPluginInstanceImpl()569 PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
570   // Notify all the plugin objects of deletion. This will prevent blink from
571   // calling into the plugin any more.
572   //
573   // Swap out the set so we can delete from it (the objects will try to
574   // unregister themselves inside the delete call).
575   PluginObjectSet plugin_object_copy;
576   live_plugin_objects_.swap(plugin_object_copy);
577   for (auto i = plugin_object_copy.begin(); i != plugin_object_copy.end();
578        ++i) {
579     (*i)->InstanceDeleted();
580   }
581 
582   if (message_channel_)
583     message_channel_->InstanceDeleted();
584   message_channel_object_.Reset();
585 
586   if (TrackedCallback::IsPending(lock_mouse_callback_))
587     lock_mouse_callback_->Abort();
588 
589   audio_controller_->OnPepperInstanceDeleted();
590 
591   if (render_frame_)
592     render_frame_->PepperInstanceDeleted(this);
593 
594   if (created_in_process_instance_) {
595     PepperBrowserConnection* browser_connection =
596         PepperBrowserConnection::Get(render_frame_);
597     browser_connection->DidDeleteInProcessInstance(pp_instance());
598   }
599 
600   module_->InstanceDeleted(this);
601   // If we switched from the NaCl plugin module, notify it too.
602   if (original_module_.get())
603     original_module_->InstanceDeleted(this);
604 
605   // This should be last since some of the above "instance deleted" calls will
606   // want to look up in the global map to get info off of our object.
607   HostGlobals::Get()->InstanceDeleted(pp_instance_);
608 
609 }
610 
611 // NOTE: Any of these methods that calls into the plugin needs to take into
612 // account that the plugin may use Var to remove the <embed> from the DOM, which
613 // will make the PepperWebPluginImpl drop its reference, usually the last one.
614 // If a method needs to access a member of the instance after the call has
615 // returned, then it needs to keep its own reference on the stack.
616 
GetMessageChannelObject()617 v8::Local<v8::Object> PepperPluginInstanceImpl::GetMessageChannelObject() {
618   return v8::Local<v8::Object>::New(isolate_, message_channel_object_);
619 }
620 
MessageChannelDestroyed()621 void PepperPluginInstanceImpl::MessageChannelDestroyed() {
622   message_channel_ = nullptr;
623   message_channel_object_.Reset();
624 }
625 
GetMainWorldContext()626 v8::Local<v8::Context> PepperPluginInstanceImpl::GetMainWorldContext() {
627   if (!container_)
628     return v8::Local<v8::Context>();
629 
630   WebLocalFrame* frame = container_->GetDocument().GetFrame();
631 
632   if (!frame)
633     return v8::Local<v8::Context>();
634 
635   v8::Local<v8::Context> context = frame->MainWorldScriptContext();
636   DCHECK(context->GetIsolate() == isolate_);
637   return context;
638 }
639 
Delete()640 void PepperPluginInstanceImpl::Delete() {
641   is_deleted_ = true;
642 
643   // Keep a reference on the stack. See NOTE above.
644   scoped_refptr<PepperPluginInstanceImpl> ref(this);
645 
646   // Force the MessageChannel to release its "passthrough object" which should
647   // release our last reference to the "InstanceObject" and will probably
648   // destroy it. We want to do this prior to calling DidDestroy in case the
649   // destructor of the instance object tries to use the instance.
650   if (message_channel_)
651     message_channel_->SetPassthroughObject(v8::Local<v8::Object>());
652   // If this is a NaCl plugin instance, shut down the NaCl plugin by calling
653   // its DidDestroy. Don't call DidDestroy on the untrusted plugin instance,
654   // since there is little that it can do at this point.
655   if (original_instance_interface_) {
656     base::TimeTicks start = base::TimeTicks::Now();
657     original_instance_interface_->DidDestroy(pp_instance());
658     UMA_HISTOGRAM_CUSTOM_TIMES("NaCl.Perf.ShutdownTime.Total",
659                                base::TimeTicks::Now() - start,
660                                base::TimeDelta::FromMilliseconds(1),
661                                base::TimeDelta::FromSeconds(20),
662                                100);
663   } else {
664     instance_interface_->DidDestroy(pp_instance());
665   }
666   // Ensure we don't attempt to call functions on the destroyed instance.
667   original_instance_interface_.reset();
668   instance_interface_.reset();
669 
670   // Force-unbind any Graphics. In the case of Graphics2D, if the plugin
671   // leaks the graphics 2D, it may actually get cleaned up after our
672   // destruction, so we need its pointers to be up to date.
673   BindGraphics(pp_instance(), 0);
674   container_ = nullptr;
675 }
676 
is_deleted() const677 bool PepperPluginInstanceImpl::is_deleted() const { return is_deleted_; }
678 
Paint(cc::PaintCanvas * canvas,const gfx::Rect & plugin_rect,const gfx::Rect & paint_rect)679 void PepperPluginInstanceImpl::Paint(cc::PaintCanvas* canvas,
680                                      const gfx::Rect& plugin_rect,
681                                      const gfx::Rect& paint_rect) {
682   TRACE_EVENT0("ppapi", "PluginInstance::Paint");
683   if (module()->is_crashed()) {
684     // Crashed plugin painting.
685     if (!sad_plugin_image_) {  // Lazily initialize bitmap.
686       if (SkBitmap* bitmap =
687               GetContentClient()->renderer()->GetSadPluginBitmap()) {
688         DCHECK(bitmap->isImmutable());
689         sad_plugin_image_ = cc::PaintImage::CreateFromBitmap(*bitmap);
690       }
691     }
692     if (sad_plugin_image_)
693       PaintSadPlugin(canvas, plugin_rect, sad_plugin_image_);
694     return;
695   }
696 
697   if (bound_graphics_2d_platform_)
698     bound_graphics_2d_platform_->Paint(canvas, plugin_rect, paint_rect);
699 }
700 
InvalidateRect(const gfx::Rect & rect)701 void PepperPluginInstanceImpl::InvalidateRect(const gfx::Rect& rect) {
702   if (!container_ || view_data_.rect.size.width == 0 ||
703       view_data_.rect.size.height == 0)
704     return;  // Nothing to do.
705   if (rect.IsEmpty())
706     container_->Invalidate();
707   else
708     container_->InvalidateRect(rect);
709 
710   if (texture_layer_) {
711     if (rect.IsEmpty()) {
712       texture_layer_->SetNeedsDisplay();
713     } else {
714       texture_layer_->SetNeedsDisplayRect(rect);
715     }
716   }
717 }
718 
CommitTransferableResource(const viz::TransferableResource & resource)719 void PepperPluginInstanceImpl::CommitTransferableResource(
720     const viz::TransferableResource& resource) {
721   if (!committed_texture_.mailbox_holder.mailbox.IsZero() &&
722       !IsTextureInUse(committed_texture_)) {
723     committed_texture_graphics_3d_->ReturnFrontBuffer(
724         committed_texture_.mailbox_holder.mailbox,
725         committed_texture_consumed_sync_token_, false);
726   }
727 
728   committed_texture_ = resource;
729   committed_texture_graphics_3d_ = bound_graphics_3d_;
730   committed_texture_consumed_sync_token_ = gpu::SyncToken();
731 
732   if (!texture_layer_) {
733     UpdateLayer(true);
734     return;
735   }
736 
737   PassCommittedTextureToTextureLayer();
738   texture_layer_->SetNeedsDisplay();
739 }
740 
PassCommittedTextureToTextureLayer()741 void PepperPluginInstanceImpl::PassCommittedTextureToTextureLayer() {
742   DCHECK(bound_graphics_3d_);
743 
744   if (committed_texture_.mailbox_holder.mailbox.IsZero())
745     return;
746 
747   std::unique_ptr<viz::SingleReleaseCallback> callback(
748       viz::SingleReleaseCallback::Create(base::BindOnce(
749           &PepperPluginInstanceImpl::FinishedConsumingCommittedTexture,
750           weak_factory_.GetWeakPtr(), committed_texture_,
751           committed_texture_graphics_3d_)));
752 
753   IncrementTextureReferenceCount(committed_texture_);
754   texture_layer_->SetTransferableResource(committed_texture_,
755                                           std::move(callback));
756 }
757 
FinishedConsumingCommittedTexture(const viz::TransferableResource & resource,scoped_refptr<PPB_Graphics3D_Impl> graphics_3d,const gpu::SyncToken & sync_token,bool is_lost)758 void PepperPluginInstanceImpl::FinishedConsumingCommittedTexture(
759     const viz::TransferableResource& resource,
760     scoped_refptr<PPB_Graphics3D_Impl> graphics_3d,
761     const gpu::SyncToken& sync_token,
762     bool is_lost) {
763   bool removed = DecrementTextureReferenceCount(resource);
764   bool is_committed_texture = committed_texture_.mailbox_holder.mailbox ==
765                               resource.mailbox_holder.mailbox;
766 
767   if (is_committed_texture && !is_lost) {
768     committed_texture_consumed_sync_token_ = sync_token;
769     return;
770   }
771 
772   if (removed && !is_committed_texture) {
773     graphics_3d->ReturnFrontBuffer(resource.mailbox_holder.mailbox, sync_token,
774                                    is_lost);
775   }
776 }
777 
InstanceCrashed()778 void PepperPluginInstanceImpl::InstanceCrashed() {
779   // Force free all resources and vars.
780   HostGlobals::Get()->InstanceCrashed(pp_instance());
781 
782   // Free any associated graphics.
783   SetFullscreen(false);
784   // Unbind current 2D or 3D graphics context.
785   BindGraphics(pp_instance(), 0);
786   InvalidateRect(gfx::Rect());
787 
788   if (render_frame_)
789     render_frame_->PluginCrashed(module_->path(), module_->GetPeerProcessId());
790 }
791 
Initialize(const std::vector<std::string> & arg_names,const std::vector<std::string> & arg_values,bool full_frame)792 bool PepperPluginInstanceImpl::Initialize(
793     const std::vector<std::string>& arg_names,
794     const std::vector<std::string>& arg_values,
795     bool full_frame) {
796   if (!render_frame_)
797     return false;
798 
799   message_channel_ = MessageChannel::Create(this, &message_channel_object_);
800   DCHECK(message_channel_);
801 
802   full_frame_ = full_frame;
803 
804   UpdateTouchEventRequest();
805   UpdateWheelEventRequest();
806 
807   argn_ = arg_names;
808   argv_ = arg_values;
809   std::unique_ptr<const char* []> argn_array(StringVectorToArgArray(argn_));
810   std::unique_ptr<const char* []> argv_array(StringVectorToArgArray(argv_));
811   auto weak_this = weak_factory_.GetWeakPtr();
812   bool success = PP_ToBool(instance_interface_->DidCreate(
813       pp_instance(), argn_.size(), argn_array.get(), argv_array.get()));
814   if (!weak_this) {
815     // The plugin may do synchronous scripting during "DidCreate", so |this|
816     // may be deleted. In that case, return failure and don't touch any
817     // member variables.
818     return false;
819   }
820   // If this is a plugin that hosts external plugins, we should delay messages
821   // so that the child plugin that's created later will receive all the
822   // messages. (E.g., NaCl trusted plugin starting a child NaCl app.)
823   //
824   // A host for external plugins will call ResetAsProxied later, at which point
825   // we can Start() the MessageChannel.
826   if (success && !module_->renderer_ppapi_host()->IsExternalPluginHost())
827     message_channel_->Start();
828 
829   if (success)
830     HandleAccessibilityChange();
831 
832   initialized_ = success;
833   return success;
834 }
835 
HandleDocumentLoad(const blink::WebURLResponse & response)836 bool PepperPluginInstanceImpl::HandleDocumentLoad(
837     const blink::WebURLResponse& response) {
838   DCHECK(!document_loader_);
839   if (external_document_load_) {
840     // The external proxy isn't available, so save the response and record
841     // document load notifications for later replay.
842     external_document_response_ = response;
843     external_document_loader_ = std::make_unique<ExternalDocumentLoader>();
844     document_loader_ = external_document_loader_.get();
845     return true;
846   }
847 
848   if (module()->is_crashed() || !render_frame_) {
849     // Don't create a resource for a crashed plugin.
850     container()->GetDocument().GetFrame()->DeprecatedStopLoading();
851     return false;
852   }
853 
854   DCHECK(!document_loader_);
855 
856   // Create a loader resource host for this load. Note that we have to set
857   // the document_loader before issuing the in-process
858   // PPP_Instance.HandleDocumentLoad call below, since this may reentrantly
859   // call into the instance and expect it to be valid.
860   RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
861   auto loader_host =
862       std::make_unique<PepperURLLoaderHost>(host_impl, true, pp_instance(), 0);
863   // TODO(teravest): Remove set_document_loader() from instance and clean up
864   // this relationship.
865   set_document_loader(loader_host.get());
866   loader_host->DidReceiveResponse(response);
867 
868   // This host will be pending until the resource object attaches to it.
869   int pending_host_id = host_impl->GetPpapiHost()->AddPendingResourceHost(
870       std::unique_ptr<ppapi::host::ResourceHost>(std::move(loader_host)));
871   DCHECK(pending_host_id);
872 
873   render_frame()
874       ->GetTaskRunner(blink::TaskType::kInternalLoading)
875       ->PostTask(
876           FROM_HERE,
877           base::BindOnce(&PepperPluginInstanceImpl::DidDataFromWebURLResponse,
878                          weak_factory_.GetWeakPtr(), response, pending_host_id,
879                          DataFromWebURLResponse(response)));
880 
881   // If the load was not abandoned, document_loader_ will now be set. It's
882   // possible that the load was canceled by now and document_loader_ was
883   // already nulled out.
884   return true;
885 }
886 
SendCompositionEventToPlugin(PP_InputEvent_Type type,const base::string16 & text)887 bool PepperPluginInstanceImpl::SendCompositionEventToPlugin(
888     PP_InputEvent_Type type,
889     const base::string16& text) {
890   std::vector<ui::ImeTextSpan> empty;
891   return SendCompositionEventWithImeTextSpanInformationToPlugin(
892       type, text, empty, static_cast<int>(text.size()),
893       static_cast<int>(text.size()));
894 }
895 
896 bool PepperPluginInstanceImpl::
SendCompositionEventWithImeTextSpanInformationToPlugin(PP_InputEvent_Type type,const base::string16 & text,const std::vector<ui::ImeTextSpan> & ime_text_spans,int selection_start,int selection_end)897     SendCompositionEventWithImeTextSpanInformationToPlugin(
898         PP_InputEvent_Type type,
899         const base::string16& text,
900         const std::vector<ui::ImeTextSpan>& ime_text_spans,
901         int selection_start,
902         int selection_end) {
903   // Keep a reference on the stack. See NOTE above.
904   scoped_refptr<PepperPluginInstanceImpl> ref(this);
905 
906   if (!LoadInputEventInterface())
907     return false;
908 
909   PP_InputEvent_Class event_class = PP_INPUTEVENT_CLASS_IME;
910   if (!(filtered_input_event_mask_ & event_class) &&
911       !(input_event_mask_ & event_class))
912     return false;
913 
914   ppapi::InputEventData event;
915   event.event_type = type;
916   event.event_time_stamp =
917       ppapi::TimeTicksToPPTimeTicks(base::TimeTicks::Now());
918 
919   // Convert UTF16 text to UTF8 with offset conversion.
920   std::vector<size_t> utf16_offsets;
921   utf16_offsets.push_back(selection_start);
922   utf16_offsets.push_back(selection_end);
923   for (size_t i = 0; i < ime_text_spans.size(); ++i) {
924     utf16_offsets.push_back(ime_text_spans[i].start_offset);
925     utf16_offsets.push_back(ime_text_spans[i].end_offset);
926   }
927   std::vector<size_t> utf8_offsets(utf16_offsets);
928   event.character_text = base::UTF16ToUTF8AndAdjustOffsets(text, &utf8_offsets);
929 
930   // Set the converted selection range.
931   event.composition_selection_start =
932       (utf8_offsets[0] == std::string::npos ? event.character_text.size()
933                                             : utf8_offsets[0]);
934   event.composition_selection_end =
935       (utf8_offsets[1] == std::string::npos ? event.character_text.size()
936                                             : utf8_offsets[1]);
937 
938   // Set the converted segmentation points.
939   // Be sure to add 0 and size(), and remove duplication or errors.
940   std::set<size_t> offset_set(utf8_offsets.begin() + 2, utf8_offsets.end());
941   offset_set.insert(0);
942   offset_set.insert(event.character_text.size());
943   offset_set.erase(std::string::npos);
944   event.composition_segment_offsets.assign(offset_set.begin(),
945                                            offset_set.end());
946 
947   // Set the composition target.
948   for (size_t i = 0; i < ime_text_spans.size(); ++i) {
949     if (ime_text_spans[i].thickness == ui::ImeTextSpan::Thickness::kThick) {
950       auto it = std::find(event.composition_segment_offsets.begin(),
951                           event.composition_segment_offsets.end(),
952                           utf8_offsets[2 * i + 2]);
953       if (it != event.composition_segment_offsets.end()) {
954         event.composition_target_segment =
955             it - event.composition_segment_offsets.begin();
956         break;
957       }
958     }
959   }
960 
961   // Send the event.
962   bool handled = false;
963   if (filtered_input_event_mask_ & event_class)
964     event.is_filtered = true;
965   else
966     handled = true;  // Unfiltered events are assumed to be handled.
967   scoped_refptr<PPB_InputEvent_Shared> event_resource(
968       new PPB_InputEvent_Shared(ppapi::OBJECT_IS_IMPL, pp_instance(), event));
969   handled |= PP_ToBool(plugin_input_event_interface_->HandleInputEvent(
970       pp_instance(), event_resource->pp_resource()));
971   return handled;
972 }
973 
RequestInputEventsHelper(uint32_t event_classes)974 void PepperPluginInstanceImpl::RequestInputEventsHelper(
975     uint32_t event_classes) {
976   if (event_classes & PP_INPUTEVENT_CLASS_TOUCH)
977     UpdateTouchEventRequest();
978   if (event_classes & PP_INPUTEVENT_CLASS_WHEEL)
979     UpdateWheelEventRequest();
980 }
981 
HandleCompositionStart(const base::string16 & text)982 bool PepperPluginInstanceImpl::HandleCompositionStart(
983     const base::string16& text) {
984   return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_COMPOSITION_START,
985                                       text);
986 }
987 
HandleCompositionUpdate(const base::string16 & text,const std::vector<ui::ImeTextSpan> & ime_text_spans,int selection_start,int selection_end)988 bool PepperPluginInstanceImpl::HandleCompositionUpdate(
989     const base::string16& text,
990     const std::vector<ui::ImeTextSpan>& ime_text_spans,
991     int selection_start,
992     int selection_end) {
993   return SendCompositionEventWithImeTextSpanInformationToPlugin(
994       PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE, text, ime_text_spans,
995       selection_start, selection_end);
996 }
997 
HandleCompositionEnd(const base::string16 & text)998 bool PepperPluginInstanceImpl::HandleCompositionEnd(
999     const base::string16& text) {
1000   return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_COMPOSITION_END,
1001                                       text);
1002 }
1003 
HandleTextInput(const base::string16 & text)1004 bool PepperPluginInstanceImpl::HandleTextInput(const base::string16& text) {
1005   return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_TEXT, text);
1006 }
1007 
GetSurroundingText(base::string16 * text,gfx::Range * range) const1008 void PepperPluginInstanceImpl::GetSurroundingText(base::string16* text,
1009                                                   gfx::Range* range) const {
1010   std::vector<size_t> offsets;
1011   offsets.push_back(selection_anchor_);
1012   offsets.push_back(selection_caret_);
1013   *text = base::UTF8ToUTF16AndAdjustOffsets(surrounding_text_, &offsets);
1014   range->set_start(offsets[0] == base::string16::npos ? text->size()
1015                                                       : offsets[0]);
1016   range->set_end(offsets[1] == base::string16::npos ? text->size()
1017                                                     : offsets[1]);
1018 }
1019 
IsPluginAcceptingCompositionEvents() const1020 bool PepperPluginInstanceImpl::IsPluginAcceptingCompositionEvents() const {
1021   return (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_IME) ||
1022          (input_event_mask_ & PP_INPUTEVENT_CLASS_IME);
1023 }
1024 
GetCaretBounds() const1025 gfx::Rect PepperPluginInstanceImpl::GetCaretBounds() const {
1026   if (!text_input_caret_info_) {
1027     // If it is never set by the plugin, use the bottom left corner.
1028     gfx::Rect rect(view_data_.rect.point.x,
1029                    view_data_.rect.point.y + view_data_.rect.size.height,
1030                    0, 0);
1031     ConvertDIPToViewport(&rect);
1032     return rect;
1033   }
1034 
1035   // TODO(kinaba) Take CSS transformation into account.
1036   // TODO(kinaba) Take |text_input_caret_info_->caret_bounds| into account. On
1037   // some platforms, an "exclude rectangle" where candidate window must avoid
1038   // the region can be passed to IME. Currently, we pass only the caret
1039   // rectangle because it is the only information supported uniformly in
1040   // Chromium.
1041   gfx::Rect caret = text_input_caret_info_->caret;
1042   caret.Offset(view_data_.rect.point.x, view_data_.rect.point.y);
1043   ConvertDIPToViewport(&caret);
1044   return caret;
1045 }
1046 
HandleCoalescedInputEvent(const blink::WebCoalescedInputEvent & event,ui::Cursor * cursor)1047 bool PepperPluginInstanceImpl::HandleCoalescedInputEvent(
1048     const blink::WebCoalescedInputEvent& event,
1049     ui::Cursor* cursor) {
1050   if (blink::WebInputEvent::IsTouchEventType(event.Event().GetType()) &&
1051       ((filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_COALESCED_TOUCH) ||
1052        (input_event_mask_ & PP_INPUTEVENT_CLASS_COALESCED_TOUCH))) {
1053     bool result = false;
1054     for (size_t i = 0; i < event.CoalescedEventSize(); ++i) {
1055       result |= HandleInputEvent(event.CoalescedEvent(i), cursor);
1056     }
1057     return result;
1058   }
1059   return HandleInputEvent(event.Event(), cursor);
1060 }
1061 
HandleInputEvent(const blink::WebInputEvent & event,ui::Cursor * cursor)1062 bool PepperPluginInstanceImpl::HandleInputEvent(
1063     const blink::WebInputEvent& event,
1064     ui::Cursor* cursor) {
1065   TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleInputEvent");
1066 
1067   if (!render_frame_)
1068     return false;
1069 
1070   // Don't dispatch input events to crashed plugins.
1071   if (module()->is_crashed())
1072     return false;
1073 
1074   // Don't send reserved system key events to plugins.
1075   if (IsReservedSystemInputEvent(event))
1076     return false;
1077 
1078   // Keep a reference on the stack. See NOTE above.
1079   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1080 
1081   bool rv = false;
1082   if (LoadInputEventInterface()) {
1083     PP_InputEvent_Class event_class = ClassifyInputEvent(event);
1084     if (!event_class)
1085       return false;
1086 
1087     if ((filtered_input_event_mask_ & event_class) ||
1088         (input_event_mask_ & event_class)) {
1089       // Actually send the event.
1090       std::vector<ppapi::InputEventData> events;
1091       std::unique_ptr<const WebInputEvent> event_in_dip(
1092           ui::ScaleWebInputEvent(event, viewport_to_dip_scale_));
1093       if (event_in_dip)
1094         CreateInputEventData(*event_in_dip.get(), &events);
1095       else
1096         CreateInputEventData(event, &events);
1097 
1098       // Each input event may generate more than one PP_InputEvent.
1099       for (size_t i = 0; i < events.size(); i++) {
1100         if (filtered_input_event_mask_ & event_class)
1101           events[i].is_filtered = true;
1102         else
1103           rv = true;  // Unfiltered events are assumed to be handled.
1104         scoped_refptr<PPB_InputEvent_Shared> event_resource(
1105             new PPB_InputEvent_Shared(
1106                 ppapi::OBJECT_IS_IMPL, pp_instance(), events[i]));
1107 
1108         rv |= PP_ToBool(plugin_input_event_interface_->HandleInputEvent(
1109             pp_instance(), event_resource->pp_resource()));
1110       }
1111     }
1112   }
1113 
1114   if (cursor_)
1115     *cursor = *cursor_;
1116   return rv;
1117 }
1118 
HandleMessage(ScopedPPVar message)1119 void PepperPluginInstanceImpl::HandleMessage(ScopedPPVar message) {
1120   TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleMessage");
1121   if (is_deleted_)
1122     return;
1123   ppapi::proxy::HostDispatcher* dispatcher =
1124       ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
1125   if (!dispatcher || (message.get().type == PP_VARTYPE_OBJECT)) {
1126     // The dispatcher should always be valid, and MessageChannel should never
1127     // send an 'object' var over PPP_Messaging.
1128     NOTREACHED();
1129     return;
1130   }
1131   dispatcher->Send(new PpapiMsg_PPPMessaging_HandleMessage(
1132       ppapi::API_ID_PPP_MESSAGING,
1133       pp_instance(),
1134       ppapi::proxy::SerializedVarSendInputShmem(dispatcher, message.get(),
1135                                                 pp_instance())));
1136 }
1137 
HandleBlockingMessage(ScopedPPVar message,ScopedPPVar * result)1138 bool PepperPluginInstanceImpl::HandleBlockingMessage(ScopedPPVar message,
1139                                                      ScopedPPVar* result) {
1140   TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleBlockingMessage");
1141   if (is_deleted_)
1142     return false;
1143   ppapi::proxy::HostDispatcher* dispatcher =
1144       ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
1145   if (!dispatcher || (message.get().type == PP_VARTYPE_OBJECT)) {
1146     // The dispatcher should always be valid, and MessageChannel should never
1147     // send an 'object' var over PPP_Messaging.
1148     NOTREACHED();
1149     return false;
1150   }
1151   ppapi::proxy::ReceiveSerializedVarReturnValue msg_reply;
1152   bool was_handled = false;
1153   dispatcher->Send(new PpapiMsg_PPPMessageHandler_HandleBlockingMessage(
1154       ppapi::API_ID_PPP_MESSAGING,
1155       pp_instance(),
1156       ppapi::proxy::SerializedVarSendInputShmem(dispatcher, message.get(),
1157                                                 pp_instance()),
1158       &msg_reply,
1159       &was_handled));
1160   *result = ScopedPPVar(ScopedPPVar::PassRef(), msg_reply.Return(dispatcher));
1161   TRACE_EVENT0("ppapi",
1162                "PepperPluginInstanceImpl::HandleBlockingMessage return.");
1163   return was_handled;
1164 }
1165 
GetInstanceObject(v8::Isolate * isolate)1166 PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) {
1167   // Keep a reference on the stack. See NOTE above.
1168   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1169 
1170   DCHECK_EQ(isolate, isolate_);
1171 
1172   // If the plugin supports the private instance interface, try to retrieve its
1173   // instance object.
1174   if (LoadPrivateInterface())
1175     return plugin_private_interface_->GetInstanceObject(pp_instance());
1176   return PP_MakeUndefined();
1177 }
1178 
ViewChanged(const gfx::Rect & window,const gfx::Rect & clip,const gfx::Rect & unobscured)1179 void PepperPluginInstanceImpl::ViewChanged(
1180     const gfx::Rect& window,
1181     const gfx::Rect& clip,
1182     const gfx::Rect& unobscured) {
1183   if (!render_frame_)
1184     return;
1185 
1186   // WebKit can give weird (x,y) positions for empty clip rects (since the
1187   // position technically doesn't matter). But we want to make these
1188   // consistent since this is given to the plugin, so force everything to 0
1189   // in the "everything is clipped" case.
1190   gfx::Rect new_clip;
1191   if (!clip.IsEmpty())
1192     new_clip = clip;
1193 
1194   unobscured_rect_ = unobscured;
1195 
1196   view_data_.rect = PP_FromGfxRect(window);
1197   view_data_.clip_rect = PP_FromGfxRect(new_clip);
1198   view_data_.device_scale = container_->DeviceScaleFactor();
1199   view_data_.css_scale =
1200       container_->PageZoomFactor() * container_->PageScaleFactor();
1201   if (IsUseZoomForDSFEnabled()) {
1202     WebWidget* widget =
1203         render_frame()->GetLocalRootRenderWidget()->GetWebWidget();
1204 
1205     viewport_to_dip_scale_ =
1206         1.0f / widget->GetOriginalScreenInfo().device_scale_factor;
1207   } else {
1208     viewport_to_dip_scale_ = 1.0f;
1209   }
1210   ConvertRectToDIP(&view_data_.rect);
1211   ConvertRectToDIP(&view_data_.clip_rect);
1212   view_data_.css_scale *= viewport_to_dip_scale_;
1213   view_data_.device_scale /= viewport_to_dip_scale_;
1214 
1215   gfx::Size scroll_offset = gfx::ScaleToRoundedSize(
1216       container_->GetDocument().GetFrame()->GetScrollOffset(),
1217       viewport_to_dip_scale_);
1218 
1219   view_data_.scroll_offset = PP_MakePoint(scroll_offset.width(),
1220                                           scroll_offset.height());
1221 
1222   // The view size may have changed and we might need to update
1223   // our registration of event listeners.
1224   UpdateTouchEventRequest();
1225   UpdateWheelEventRequest();
1226 
1227   if (desired_fullscreen_state_ || view_data_.is_fullscreen) {
1228     bool is_fullscreen_element = container_->IsFullscreenElement();
1229     if (!view_data_.is_fullscreen && desired_fullscreen_state_ &&
1230         is_fullscreen_element) {
1231       // Entered fullscreen. Only possible via SetFullscreen().
1232       view_data_.is_fullscreen = true;
1233     } else if (view_data_.is_fullscreen && !is_fullscreen_element) {
1234       // Exited fullscreen. Possible via SetFullscreen() or F11/link,
1235       // so desired_fullscreen_state might be out-of-date.
1236       desired_fullscreen_state_ = false;
1237       view_data_.is_fullscreen = false;
1238 
1239       // This operation will cause the plugin to re-layout which will send more
1240       // DidChangeView updates. Schedule an asynchronous update and suppress
1241       // notifications until that completes to avoid sending intermediate sizes
1242       // to the plugins.
1243       ScheduleAsyncDidChangeView();
1244 
1245       // Reset the size attributes that we hacked to fill in the screen and
1246       // retrigger ViewChanged. Make sure we don't forward duplicates of
1247       // this view to the plugin.
1248       ResetSizeAttributesAfterFullscreen();
1249       return;
1250     }
1251   }
1252 
1253   // During plugin initialization, there are often re-layouts. Avoid sending
1254   // intermediate sizes the plugin.
1255   if (sent_initial_did_change_view_)
1256     SendDidChangeView();
1257   else
1258     ScheduleAsyncDidChangeView();
1259 }
1260 
SetWebKitFocus(bool has_focus)1261 void PepperPluginInstanceImpl::SetWebKitFocus(bool has_focus) {
1262   if (has_webkit_focus_ == has_focus)
1263     return;
1264 
1265   bool old_plugin_focus = PluginHasFocus();
1266   has_webkit_focus_ = has_focus;
1267   if (PluginHasFocus() != old_plugin_focus)
1268     SendFocusChangeNotification();
1269 }
1270 
PageVisibilityChanged(bool is_visible)1271 void PepperPluginInstanceImpl::PageVisibilityChanged(bool is_visible) {
1272   if (is_visible == view_data_.is_page_visible)
1273     return;  // Nothing to do.
1274   view_data_.is_page_visible = is_visible;
1275 
1276   // If the initial DidChangeView notification hasn't been sent to the plugin,
1277   // let it pass the visibility state for us, instead of sending a notification
1278   // immediately. It is possible that PepperPluginInstanceImpl::ViewChanged()
1279   // hasn't been called for the first time. In that case, most of the fields in
1280   // |view_data_| haven't been properly initialized.
1281   if (sent_initial_did_change_view_)
1282     SendDidChangeView();
1283 }
1284 
ViewInitiatedPaint()1285 void PepperPluginInstanceImpl::ViewInitiatedPaint() {
1286   if (bound_graphics_2d_platform_)
1287     bound_graphics_2d_platform_->ViewInitiatedPaint();
1288   else if (bound_graphics_3d_.get())
1289     bound_graphics_3d_->ViewInitiatedPaint();
1290 }
1291 
SetSelectedText(const base::string16 & selected_text)1292 void PepperPluginInstanceImpl::SetSelectedText(
1293     const base::string16& selected_text) {
1294   if (!render_frame_)
1295     return;
1296 
1297   selected_text_ = selected_text;
1298   gfx::Range range(0, selected_text.length());
1299   render_frame_->SetSelectedText(selected_text, 0, range);
1300 }
1301 
SetLinkUnderCursor(const std::string & url)1302 void PepperPluginInstanceImpl::SetLinkUnderCursor(const std::string& url) {
1303   link_under_cursor_ = base::UTF8ToUTF16(url);
1304 }
1305 
SetTextInputType(ui::TextInputType type)1306 void PepperPluginInstanceImpl::SetTextInputType(ui::TextInputType type) {
1307   if (!render_frame_)
1308     return;
1309 
1310   text_input_type_ = type;
1311   render_frame_->PepperTextInputTypeChanged(this);
1312 }
1313 
PostMessageToJavaScript(PP_Var message)1314 void PepperPluginInstanceImpl::PostMessageToJavaScript(PP_Var message) {
1315   if (message_channel_)
1316     message_channel_->PostMessageToJavaScript(message);
1317 }
1318 
RegisterMessageHandler(PP_Instance instance,void * user_data,const PPP_MessageHandler_0_2 * handler,PP_Resource message_loop)1319 int32_t PepperPluginInstanceImpl::RegisterMessageHandler(
1320     PP_Instance instance,
1321     void* user_data,
1322     const PPP_MessageHandler_0_2* handler,
1323     PP_Resource message_loop) {
1324   // Not supported in-process.
1325   NOTIMPLEMENTED();
1326   return PP_ERROR_FAILED;
1327 }
1328 
UnregisterMessageHandler(PP_Instance instance)1329 void PepperPluginInstanceImpl::UnregisterMessageHandler(PP_Instance instance) {
1330   // Not supported in-process.
1331   NOTIMPLEMENTED();
1332 }
1333 
GetSelectedText(bool html)1334 base::string16 PepperPluginInstanceImpl::GetSelectedText(bool html) {
1335   return selected_text_;
1336 }
1337 
GetLinkAtPosition(const gfx::Point & point)1338 base::string16 PepperPluginInstanceImpl::GetLinkAtPosition(
1339     const gfx::Point& point) {
1340   // Keep a reference on the stack. See NOTE above.
1341   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1342   if (!LoadPdfInterface()) {
1343     // TODO(koz): Change the containing function to GetLinkUnderCursor(). We can
1344     // return |link_under_cursor_| here because this is only ever called with
1345     // the current mouse coordinates.
1346     return link_under_cursor_;
1347   }
1348 
1349   PP_Point p;
1350   p.x = point.x();
1351   p.y = point.y();
1352   PP_Var rv = plugin_pdf_interface_->GetLinkAtPosition(pp_instance(), p);
1353   // If the plugin returns undefined for this function it has switched to
1354   // providing us with the link under the cursor eagerly.
1355   if (rv.type == PP_VARTYPE_UNDEFINED)
1356     return link_under_cursor_;
1357   StringVar* string = StringVar::FromPPVar(rv);
1358   base::string16 link;
1359   if (string)
1360     link = base::UTF8ToUTF16(string->value());
1361   // Release the ref the plugin transfered to us.
1362   PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(rv);
1363   return link;
1364 }
1365 
SetCaretPosition(const gfx::PointF & position)1366 void PepperPluginInstanceImpl::SetCaretPosition(const gfx::PointF& position) {
1367   if (!LoadPdfInterface())
1368     return;
1369 
1370   PP_FloatPoint p;
1371   p.x = position.x();
1372   p.y = position.y();
1373   plugin_pdf_interface_->SetCaretPosition(pp_instance(), &p);
1374 }
1375 
MoveRangeSelectionExtent(const gfx::PointF & extent)1376 void PepperPluginInstanceImpl::MoveRangeSelectionExtent(
1377     const gfx::PointF& extent) {
1378   if (!LoadPdfInterface())
1379     return;
1380 
1381   PP_FloatPoint p;
1382   p.x = extent.x();
1383   p.y = extent.y();
1384   plugin_pdf_interface_->MoveRangeSelectionExtent(pp_instance(), &p);
1385 }
1386 
SetSelectionBounds(const gfx::PointF & base,const gfx::PointF & extent)1387 void PepperPluginInstanceImpl::SetSelectionBounds(const gfx::PointF& base,
1388                                                   const gfx::PointF& extent) {
1389   if (!LoadPdfInterface())
1390     return;
1391 
1392   PP_FloatPoint p_base;
1393   p_base.x = base.x();
1394   p_base.y = base.y();
1395 
1396   PP_FloatPoint p_extent;
1397   p_extent.x = extent.x();
1398   p_extent.y = extent.y();
1399   plugin_pdf_interface_->SetSelectionBounds(pp_instance(), &p_base, &p_extent);
1400 }
1401 
CanEditText()1402 bool PepperPluginInstanceImpl::CanEditText() {
1403   if (!LoadPdfInterface())
1404     return false;
1405   // No reference to |this| on the stack. Do not do any more work after this.
1406   // See NOTE above.
1407   return PP_ToBool(plugin_pdf_interface_->CanEditText(pp_instance()));
1408 }
1409 
HasEditableText()1410 bool PepperPluginInstanceImpl::HasEditableText() {
1411   if (!LoadPdfInterface())
1412     return false;
1413 
1414   // No reference to |this| on the stack. Do not do any more work after this.
1415   // See NOTE above.
1416   return PP_ToBool(plugin_pdf_interface_->HasEditableText(pp_instance()));
1417 }
1418 
ReplaceSelection(const std::string & text)1419 void PepperPluginInstanceImpl::ReplaceSelection(const std::string& text) {
1420   if (!LoadPdfInterface())
1421     return;
1422 
1423   // No reference to |this| on the stack. Do not do any more work after this.
1424   // See NOTE above.
1425   plugin_pdf_interface_->ReplaceSelection(pp_instance(), text.c_str());
1426 }
1427 
SelectAll()1428 void PepperPluginInstanceImpl::SelectAll() {
1429   if (!LoadPdfInterface())
1430     return;
1431 
1432   // Keep a reference on the stack. See NOTE above.
1433   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1434 
1435   // TODO(https://crbug.com/836074) |kPlatformModifier| should be
1436   // |ui::EF_PLATFORM_ACCELERATOR| (|ui::EF_COMMAND_DOWN| on Mac).
1437   static const ui::EventFlags kPlatformModifier = ui::EF_CONTROL_DOWN;
1438   // Synthesize a ctrl + a key event to send to the plugin and let it sort out
1439   // the event. See also https://crbug.com/739529.
1440   ui::KeyEvent char_event(L'A', ui::VKEY_A, ui::DomCode::NONE,
1441                           kPlatformModifier);
1442 
1443   // Also synthesize a key up event to look more like a real key press.
1444   // Otherwise the plugin will not do all the required work to keep the renderer
1445   // in sync.
1446   ui::KeyEvent keyup_event(ui::ET_KEY_RELEASED, ui::VKEY_A, kPlatformModifier);
1447 
1448   ui::Cursor dummy_cursor_info;
1449   HandleInputEvent(MakeWebKeyboardEvent(char_event), &dummy_cursor_info);
1450   HandleInputEvent(MakeWebKeyboardEvent(keyup_event), &dummy_cursor_info);
1451 }
1452 
CanUndo()1453 bool PepperPluginInstanceImpl::CanUndo() {
1454   if (!LoadPdfInterface())
1455     return false;
1456 
1457   // No reference to |this| on the stack. Do not do any more work after this.
1458   // See NOTE above.
1459   return PP_ToBool(plugin_pdf_interface_->CanUndo(pp_instance()));
1460 }
1461 
CanRedo()1462 bool PepperPluginInstanceImpl::CanRedo() {
1463   if (!LoadPdfInterface())
1464     return false;
1465 
1466   // No reference to |this| on the stack. Do not do any more work after this.
1467   // See NOTE above.
1468   return PP_ToBool(plugin_pdf_interface_->CanRedo(pp_instance()));
1469 }
1470 
Undo()1471 void PepperPluginInstanceImpl::Undo() {
1472   if (!LoadPdfInterface())
1473     return;
1474 
1475   // No reference to |this| on the stack. Do not do any more work after this.
1476   // See NOTE above.
1477   plugin_pdf_interface_->Undo(pp_instance());
1478 }
1479 
Redo()1480 void PepperPluginInstanceImpl::Redo() {
1481   if (!LoadPdfInterface())
1482     return;
1483 
1484   plugin_pdf_interface_->Redo(pp_instance());
1485 }
1486 
HandleAccessibilityAction(const PP_PdfAccessibilityActionData & action_data)1487 void PepperPluginInstanceImpl::HandleAccessibilityAction(
1488     const PP_PdfAccessibilityActionData& action_data) {
1489   if (!LoadPdfInterface())
1490     return;
1491 
1492   plugin_pdf_interface_->HandleAccessibilityAction(pp_instance(), action_data);
1493 }
1494 
RequestSurroundingText(size_t desired_number_of_characters)1495 void PepperPluginInstanceImpl::RequestSurroundingText(
1496     size_t desired_number_of_characters) {
1497   // Keep a reference on the stack. See NOTE above.
1498   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1499   if (!LoadTextInputInterface())
1500     return;
1501   plugin_textinput_interface_->RequestSurroundingText(
1502       pp_instance(), desired_number_of_characters);
1503 }
1504 
StartFind(const std::string & search_text,bool case_sensitive,int identifier)1505 bool PepperPluginInstanceImpl::StartFind(const std::string& search_text,
1506                                          bool case_sensitive,
1507                                          int identifier) {
1508   // Keep a reference on the stack. See NOTE above.
1509   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1510   if (!LoadFindInterface())
1511     return false;
1512   find_identifier_ = identifier;
1513   return PP_ToBool(plugin_find_interface_->StartFind(
1514       pp_instance(), search_text.c_str(), PP_FromBool(case_sensitive)));
1515 }
1516 
SelectFindResult(bool forward,int identifier)1517 void PepperPluginInstanceImpl::SelectFindResult(bool forward, int identifier) {
1518   // Keep a reference on the stack. See NOTE above.
1519   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1520   if (!LoadFindInterface())
1521     return;
1522   find_identifier_ = identifier;
1523   plugin_find_interface_->SelectFindResult(pp_instance(), PP_FromBool(forward));
1524 }
1525 
StopFind()1526 void PepperPluginInstanceImpl::StopFind() {
1527   // Keep a reference on the stack. See NOTE above.
1528   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1529   if (!LoadFindInterface())
1530     return;
1531   find_identifier_ = -1;
1532   plugin_find_interface_->StopFind(pp_instance());
1533 }
1534 
LoadFindInterface()1535 bool PepperPluginInstanceImpl::LoadFindInterface() {
1536   if (!module_->permissions().HasPermission(ppapi::PERMISSION_PDF))
1537     return false;
1538   if (!plugin_find_interface_) {
1539     plugin_find_interface_ = static_cast<const PPP_Find_Private*>(
1540         module_->GetPluginInterface(PPP_FIND_PRIVATE_INTERFACE));
1541   }
1542 
1543   return !!plugin_find_interface_;
1544 }
1545 
LoadInputEventInterface()1546 bool PepperPluginInstanceImpl::LoadInputEventInterface() {
1547   if (!checked_for_plugin_input_event_interface_) {
1548     checked_for_plugin_input_event_interface_ = true;
1549     plugin_input_event_interface_ = static_cast<const PPP_InputEvent*>(
1550         module_->GetPluginInterface(PPP_INPUT_EVENT_INTERFACE));
1551   }
1552   return !!plugin_input_event_interface_;
1553 }
1554 
LoadMouseLockInterface()1555 bool PepperPluginInstanceImpl::LoadMouseLockInterface() {
1556   if (!plugin_mouse_lock_interface_) {
1557     plugin_mouse_lock_interface_ = static_cast<const PPP_MouseLock*>(
1558         module_->GetPluginInterface(PPP_MOUSELOCK_INTERFACE));
1559   }
1560 
1561   return !!plugin_mouse_lock_interface_;
1562 }
1563 
LoadPdfInterface()1564 bool PepperPluginInstanceImpl::LoadPdfInterface() {
1565   if (!checked_for_plugin_pdf_interface_) {
1566     checked_for_plugin_pdf_interface_ = true;
1567     plugin_pdf_interface_ = static_cast<const PPP_Pdf*>(
1568         module_->GetPluginInterface(PPP_PDF_INTERFACE_1));
1569   }
1570 
1571   return !!plugin_pdf_interface_;
1572 }
1573 
LoadPrintInterface()1574 bool PepperPluginInstanceImpl::LoadPrintInterface() {
1575   // Only check for the interface if the plugin has dev permission.
1576   if (!module_->permissions().HasPermission(ppapi::PERMISSION_DEV))
1577     return false;
1578   if (!plugin_print_interface_) {
1579     plugin_print_interface_ = static_cast<const PPP_Printing_Dev*>(
1580         module_->GetPluginInterface(PPP_PRINTING_DEV_INTERFACE));
1581   }
1582   return !!plugin_print_interface_;
1583 }
1584 
LoadPrivateInterface()1585 bool PepperPluginInstanceImpl::LoadPrivateInterface() {
1586   // If this is a NaCl app, we want to talk to the trusted NaCl plugin to
1587   // call GetInstanceObject. This is necessary to ensure that the properties
1588   // the trusted plugin exposes (readyState and lastError) work properly. Note
1589   // that untrusted NaCl apps are not allowed to provide PPP_InstancePrivate,
1590   // so it's correct to never look up PPP_InstancePrivate for them.
1591   //
1592   // If this is *not* a NaCl plugin, original_module_ will never be set; we talk
1593   // to the "real" module.
1594   scoped_refptr<PluginModule> module =
1595       original_module_.get() ? original_module_ : module_;
1596   // Only check for the interface if the plugin has private permission.
1597   if (!module->permissions().HasPermission(ppapi::PERMISSION_PRIVATE))
1598     return false;
1599   if (!plugin_private_interface_) {
1600     plugin_private_interface_ = static_cast<const PPP_Instance_Private*>(
1601         module->GetPluginInterface(PPP_INSTANCE_PRIVATE_INTERFACE));
1602   }
1603 
1604   return !!plugin_private_interface_;
1605 }
1606 
LoadTextInputInterface()1607 bool PepperPluginInstanceImpl::LoadTextInputInterface() {
1608   if (!plugin_textinput_interface_) {
1609     plugin_textinput_interface_ = static_cast<const PPP_TextInput_Dev*>(
1610         module_->GetPluginInterface(PPP_TEXTINPUT_DEV_INTERFACE));
1611   }
1612 
1613   return !!plugin_textinput_interface_;
1614 }
1615 
SetGraphics2DTransform(const float & scale,const gfx::PointF & translation)1616 void PepperPluginInstanceImpl::SetGraphics2DTransform(
1617     const float& scale,
1618     const gfx::PointF& translation) {
1619   graphics2d_scale_ = scale;
1620   graphics2d_translation_ = translation;
1621 
1622   UpdateLayerTransform();
1623 }
1624 
UpdateLayerTransform()1625 void PepperPluginInstanceImpl::UpdateLayerTransform() {
1626   if (!bound_graphics_2d_platform_ || !texture_layer_) {
1627     // Currently the transform is only applied for Graphics2D.
1628     return;
1629   }
1630   // Set the UV coordinates of the texture based on the size of the Graphics2D
1631   // context. By default a texture gets scaled to the size of the layer. But
1632   // if the size of the Graphics2D context doesn't match the size of the plugin
1633   // then it will be incorrectly stretched. This also affects how the plugin
1634   // is painted when it is being resized. If the Graphics2D contents are
1635   // stretched when a plugin is resized while waiting for a new frame from the
1636   // plugin to be rendered, then flickering behavior occurs as in
1637   // crbug.com/353453.
1638   gfx::SizeF graphics_2d_size_in_dip =
1639       gfx::ScaleSize(gfx::SizeF(bound_graphics_2d_platform_->Size()),
1640                      bound_graphics_2d_platform_->GetScale());
1641   gfx::Size plugin_size_in_dip(view_data_.rect.size.width,
1642                                view_data_.rect.size.height);
1643 
1644   // Adding the SetLayerTransform from Graphics2D to the UV.
1645   // If graphics2d_scale_ is 1.f and graphics2d_translation_ is 0 then UV will
1646   // be top_left (0,0) and lower_right (plugin_size_in_dip.width() /
1647   // graphics_2d_size_in_dip.width(), plugin_size_in_dip.height() /
1648   // graphics_2d_size_in_dip.height())
1649   gfx::PointF top_left =
1650       gfx::PointF(-graphics2d_translation_.x() / graphics2d_scale_,
1651                   -graphics2d_translation_.y() / graphics2d_scale_);
1652   gfx::PointF lower_right =
1653       gfx::PointF((1 / graphics2d_scale_) * plugin_size_in_dip.width() -
1654                       graphics2d_translation_.x() / graphics2d_scale_,
1655                   (1 / graphics2d_scale_) * plugin_size_in_dip.height() -
1656                       graphics2d_translation_.y() / graphics2d_scale_);
1657   texture_layer_->SetUV(
1658       gfx::PointF(top_left.x() / graphics_2d_size_in_dip.width(),
1659                   top_left.y() / graphics_2d_size_in_dip.height()),
1660       gfx::PointF(lower_right.x() / graphics_2d_size_in_dip.width(),
1661                   lower_right.y() / graphics_2d_size_in_dip.height()));
1662 }
1663 
PluginHasFocus() const1664 bool PepperPluginInstanceImpl::PluginHasFocus() const {
1665   return has_webkit_focus_;
1666 }
1667 
SendFocusChangeNotification()1668 void PepperPluginInstanceImpl::SendFocusChangeNotification() {
1669   // Keep a reference on the stack. RenderFrameImpl::PepperFocusChanged may
1670   // remove the <embed> from the DOM, which will make the PepperWebPluginImpl
1671   // drop its reference, usually the last one. This is similar to possible
1672   // plugin behavior described at the NOTE above Delete().
1673   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1674 
1675   if (!render_frame_)
1676     return;
1677 
1678   bool has_focus = PluginHasFocus();
1679   render_frame_->PepperFocusChanged(this, has_focus);
1680 
1681   // instance_interface_ may have been cleared in Delete() if the
1682   // PepperWebPluginImpl is destroyed.
1683   if (instance_interface_)
1684     instance_interface_->DidChangeFocus(pp_instance(), PP_FromBool(has_focus));
1685 }
1686 
UpdateTouchEventRequest()1687 void PepperPluginInstanceImpl::UpdateTouchEventRequest() {
1688   // If the view has 0 area don't request touch events.
1689   if (view_data_.rect.size.width == 0 || view_data_.rect.size.height == 0) {
1690     container_->RequestTouchEventType(
1691         blink::WebPluginContainer::kTouchEventRequestTypeNone);
1692     return;
1693   }
1694   blink::WebPluginContainer::TouchEventRequestType request_type =
1695       blink::WebPluginContainer::kTouchEventRequestTypeSynthesizedMouse;
1696   if ((filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_COALESCED_TOUCH) ||
1697       (input_event_mask_ & PP_INPUTEVENT_CLASS_COALESCED_TOUCH)) {
1698     request_type =
1699         blink::WebPluginContainer::kTouchEventRequestTypeRawLowLatency;
1700   } else if ((filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_TOUCH) ||
1701              (input_event_mask_ & PP_INPUTEVENT_CLASS_TOUCH)) {
1702     request_type = blink::WebPluginContainer::kTouchEventRequestTypeRaw;
1703   }
1704 
1705   container_->RequestTouchEventType(request_type);
1706 }
1707 
UpdateWheelEventRequest()1708 void PepperPluginInstanceImpl::UpdateWheelEventRequest() {
1709   // If the view has 0 area don't request wheel events.
1710   if (view_data_.rect.size.width == 0 || view_data_.rect.size.height == 0) {
1711     container_->SetWantsWheelEvents(false);
1712     return;
1713   }
1714 
1715   bool hasWheelMask =
1716       (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_WHEEL) ||
1717       (input_event_mask_ & PP_INPUTEVENT_CLASS_WHEEL);
1718   container_->SetWantsWheelEvents(hasWheelMask);
1719 }
1720 
ScheduleAsyncDidChangeView()1721 void PepperPluginInstanceImpl::ScheduleAsyncDidChangeView() {
1722   if (view_change_weak_ptr_factory_.HasWeakPtrs())
1723     return;  // Already scheduled.
1724   base::ThreadTaskRunnerHandle::Get()->PostTask(
1725       FROM_HERE,
1726       base::BindOnce(&PepperPluginInstanceImpl::SendAsyncDidChangeView,
1727                      view_change_weak_ptr_factory_.GetWeakPtr()));
1728 }
1729 
SendAsyncDidChangeView()1730 void PepperPluginInstanceImpl::SendAsyncDidChangeView() {
1731   // The bound callback that owns the weak pointer is still valid until after
1732   // this function returns. SendDidChangeView checks HasWeakPtrs, so we need to
1733   // invalidate them here.
1734   // NOTE: If we ever want to have more than one pending callback, it should
1735   // use a different factory, or we should have a different strategy here.
1736   view_change_weak_ptr_factory_.InvalidateWeakPtrs();
1737   SendDidChangeView();
1738 }
1739 
SendDidChangeView()1740 void PepperPluginInstanceImpl::SendDidChangeView() {
1741   if (!render_frame_)
1742     return;
1743 
1744   // An asynchronous view update is scheduled. Skip sending this update.
1745   if (view_change_weak_ptr_factory_.HasWeakPtrs())
1746     return;
1747 
1748   // Don't send DidChangeView to crashed plugins.
1749   if (module()->is_crashed())
1750     return;
1751 
1752   if (bound_graphics_2d_platform_)
1753     bound_graphics_2d_platform_->set_viewport_to_dip_scale(
1754         viewport_to_dip_scale_);
1755 
1756   module_->renderer_ppapi_host()->set_viewport_to_dip_scale(
1757       viewport_to_dip_scale_);
1758 
1759   ppapi::ViewData view_data = view_data_;
1760 
1761   if (sent_initial_did_change_view_ && last_sent_view_data_.Equals(view_data))
1762     return;  // Nothing to update.
1763 
1764   sent_initial_did_change_view_ = true;
1765   last_sent_view_data_ = view_data;
1766   ScopedPPResource resource(
1767       ScopedPPResource::PassRef(),
1768       (new PPB_View_Shared(ppapi::OBJECT_IS_IMPL, pp_instance(), view_data))
1769           ->GetReference());
1770 
1771   UpdateLayerTransform();
1772 
1773   if (bound_graphics_2d_platform_ &&
1774       (!view_data.is_page_visible ||
1775        PP_ToGfxRect(view_data.clip_rect).IsEmpty())) {
1776     bound_graphics_2d_platform_->ClearCache();
1777   }
1778 
1779   // It's possible that Delete() has been called but the renderer hasn't
1780   // released its reference to this object yet.
1781   if (instance_interface_) {
1782     instance_interface_->DidChangeView(
1783         pp_instance(), resource, &view_data.rect, &view_data.clip_rect);
1784   }
1785 }
1786 
ReportGeometry()1787 void PepperPluginInstanceImpl::ReportGeometry() {
1788   // If this call was delayed, we may have transitioned back to fullscreen in
1789   // the mean time, so only report the geometry if we are actually in normal
1790   // mode.
1791   if (container_)
1792     container_->ReportGeometry();
1793 }
1794 
GetPreferredPrintOutputFormat(PP_PrintOutputFormat_Dev * format,const WebPrintParams & print_params)1795 bool PepperPluginInstanceImpl::GetPreferredPrintOutputFormat(
1796     PP_PrintOutputFormat_Dev* format,
1797     const WebPrintParams& print_params) {
1798   // Keep a reference on the stack. See NOTE above.
1799   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1800   if (!LoadPrintInterface())
1801     return false;
1802   uint32_t supported_formats =
1803       plugin_print_interface_->QuerySupportedFormats(pp_instance());
1804   if ((supported_formats & PP_PRINTOUTPUTFORMAT_PDF) &&
1805       !print_params.rasterize_pdf) {
1806     *format = PP_PRINTOUTPUTFORMAT_PDF;
1807     return true;
1808   }
1809   if (supported_formats & PP_PRINTOUTPUTFORMAT_RASTER) {
1810     *format = PP_PRINTOUTPUTFORMAT_RASTER;
1811     return true;
1812   }
1813   return false;
1814 }
1815 
SupportsPrintInterface()1816 bool PepperPluginInstanceImpl::SupportsPrintInterface() {
1817   PP_PrintOutputFormat_Dev format;
1818   WebPrintParams params;
1819   params.rasterize_pdf = false;
1820   return GetPreferredPrintOutputFormat(&format, params);
1821 }
1822 
PrintBegin(const WebPrintParams & print_params)1823 int PepperPluginInstanceImpl::PrintBegin(const WebPrintParams& print_params) {
1824   // Keep a reference on the stack. See NOTE above.
1825   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1826   PP_PrintOutputFormat_Dev format;
1827   if (!GetPreferredPrintOutputFormat(&format, print_params)) {
1828     // PrintBegin should not have been called since SupportsPrintInterface
1829     // would have returned false;
1830     NOTREACHED();
1831     return 0;
1832   }
1833 
1834   int num_pages;
1835   PP_PrintSettings_Dev print_settings;
1836   print_settings.printable_area = PP_FromGfxRect(print_params.printable_area);
1837   print_settings.content_area = PP_FromGfxRect(print_params.print_content_area);
1838   print_settings.paper_size = PP_FromGfxSize(print_params.paper_size);
1839   print_settings.dpi = print_params.printer_dpi;
1840   print_settings.orientation = PP_PRINTORIENTATION_NORMAL;
1841   print_settings.grayscale = PP_FALSE;
1842   print_settings.print_scaling_option =
1843       static_cast<PP_PrintScalingOption_Dev>(print_params.print_scaling_option);
1844   print_settings.format = format;
1845 
1846   if (LoadPdfInterface()) {
1847     PP_PdfPrintSettings_Dev pdf_print_settings;
1848     pdf_print_settings.pages_per_sheet = print_params.pages_per_sheet;
1849     pdf_print_settings.scale_factor = print_params.scale_factor;
1850 
1851     num_pages = plugin_pdf_interface_->PrintBegin(
1852         pp_instance(), &print_settings, &pdf_print_settings);
1853   } else {
1854     // If the content is not from the PDF plugin, "fit to paper" should have
1855     // never been a scaling option for the user to begin with.
1856     DCHECK_NE(print_settings.print_scaling_option,
1857               PP_PRINTSCALINGOPTION_FIT_TO_PAPER);
1858 
1859     num_pages = plugin_print_interface_->Begin(pp_instance(), &print_settings);
1860   }
1861   if (!num_pages)
1862     return 0;
1863 
1864   current_print_settings_ = print_settings;
1865   metafile_ = nullptr;
1866   ranges_.clear();
1867   ranges_.reserve(num_pages);
1868   return num_pages;
1869 }
1870 
PrintPage(int page_number,cc::PaintCanvas * canvas)1871 void PepperPluginInstanceImpl::PrintPage(int page_number,
1872                                          cc::PaintCanvas* canvas) {
1873 #if BUILDFLAG(ENABLE_PRINTING)
1874   DCHECK(plugin_print_interface_);
1875 
1876   // |canvas| should always have an associated metafile.
1877   auto* metafile = canvas->GetPrintingMetafile();
1878   DCHECK(metafile);
1879 
1880   // |ranges_| should be empty IFF |metafile_| is not set.
1881   DCHECK_EQ(ranges_.empty(), !metafile_);
1882   if (metafile_) {
1883     // The metafile should be the same across all calls for a given print job.
1884     DCHECK_EQ(metafile_, metafile);
1885   } else {
1886     // Store |metafile| on the first call.
1887     metafile_ = metafile;
1888   }
1889 
1890   PP_PrintPageNumberRange_Dev page_range = {page_number, page_number};
1891   ranges_.push_back(page_range);
1892 #endif
1893 }
1894 
PrintEnd()1895 void PepperPluginInstanceImpl::PrintEnd() {
1896   // Keep a reference on the stack. See NOTE above.
1897   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1898   DCHECK(plugin_print_interface_);
1899 
1900   if (!ranges_.empty()) {
1901     PP_Resource print_output = plugin_print_interface_->PrintPages(
1902         pp_instance(), ranges_.data(), ranges_.size());
1903     if (print_output) {
1904       if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF ||
1905           current_print_settings_.format == PP_PRINTOUTPUTFORMAT_RASTER) {
1906         PrintPDFOutput(print_output, metafile_);
1907       }
1908 
1909       // Now release the print output resource.
1910       PluginModule::GetCore()->ReleaseResource(print_output);
1911     }
1912 
1913     ranges_.clear();
1914     metafile_ = nullptr;
1915   }
1916 
1917   plugin_print_interface_->End(pp_instance());
1918   memset(&current_print_settings_, 0, sizeof(current_print_settings_));
1919 }
1920 
GetPrintPresetOptionsFromDocument(blink::WebPrintPresetOptions * preset_options)1921 bool PepperPluginInstanceImpl::GetPrintPresetOptionsFromDocument(
1922     blink::WebPrintPresetOptions* preset_options) {
1923   // Keep a reference on the stack. See NOTE above.
1924   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1925   if (!LoadPdfInterface())
1926     return false;
1927 
1928   PP_PdfPrintPresetOptions_Dev options;
1929   if (!plugin_pdf_interface_->GetPrintPresetOptionsFromDocument(pp_instance(),
1930                                                                 &options)) {
1931     return false;
1932   }
1933 
1934   preset_options->is_scaling_disabled = PP_ToBool(options.is_scaling_disabled);
1935   switch (options.duplex) {
1936     case PP_PRIVATEDUPLEXMODE_SIMPLEX:
1937       preset_options->duplex_mode = printing::mojom::DuplexMode::kSimplex;
1938       break;
1939     case PP_PRIVATEDUPLEXMODE_SHORT_EDGE:
1940       preset_options->duplex_mode = printing::mojom::DuplexMode::kShortEdge;
1941       break;
1942     case PP_PRIVATEDUPLEXMODE_LONG_EDGE:
1943       preset_options->duplex_mode = printing::mojom::DuplexMode::kLongEdge;
1944       break;
1945     default:
1946       preset_options->duplex_mode =
1947           printing::mojom::DuplexMode::kUnknownDuplexMode;
1948       break;
1949   }
1950   preset_options->copies = options.copies;
1951   preset_options->is_page_size_uniform =
1952       PP_ToBool(options.is_page_size_uniform);
1953   preset_options->uniform_page_size = blink::WebSize(
1954       options.uniform_page_size.width, options.uniform_page_size.height);
1955 
1956   return true;
1957 }
1958 
IsPdfPlugin()1959 bool PepperPluginInstanceImpl::IsPdfPlugin() {
1960   return LoadPdfInterface();
1961 }
1962 
CanRotateView()1963 bool PepperPluginInstanceImpl::CanRotateView() {
1964   return LoadPdfInterface() && !module()->is_crashed() &&
1965          !IsPrintPreviewUrl(document_url_);
1966 }
1967 
RotateView(WebPlugin::RotationType type)1968 void PepperPluginInstanceImpl::RotateView(WebPlugin::RotationType type) {
1969   if (!LoadPdfInterface())
1970     return;
1971   PP_PrivatePageTransformType transform_type =
1972       type == WebPlugin::kRotationType90Clockwise
1973           ? PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CW
1974           : PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CCW;
1975   plugin_pdf_interface_->Transform(pp_instance(), transform_type);
1976   // NOTE: plugin instance may have been deleted.
1977 }
1978 
IsFullscreenOrPending()1979 bool PepperPluginInstanceImpl::IsFullscreenOrPending() {
1980   return desired_fullscreen_state_;
1981 }
1982 
SetFullscreen(bool fullscreen)1983 bool PepperPluginInstanceImpl::SetFullscreen(bool fullscreen) {
1984   // Keep a reference on the stack. See NOTE above.
1985   scoped_refptr<PepperPluginInstanceImpl> ref(this);
1986 
1987   // Check whether we are trying to switch to the state we're already going
1988   // to (i.e. if we're already switching to fullscreen but the fullscreen
1989   // container isn't ready yet, don't do anything more).
1990   if (fullscreen == IsFullscreenOrPending())
1991     return false;
1992 
1993   if (!render_frame_)
1994     return false;
1995 
1996   if (fullscreen) {
1997     if (!render_frame_->render_view()
1998              ->GetRendererPreferences()
1999              .plugin_fullscreen_allowed) {
2000       return false;
2001     }
2002 
2003     if (!HasTransientUserActivation())
2004       return false;
2005   }
2006 
2007   // Check whether we are trying to switch while the state is in transition.
2008   // The 2nd request gets dropped while messing up the internal state, so
2009   // disallow this.
2010   if (view_data_.is_fullscreen != desired_fullscreen_state_)
2011     return false;
2012 
2013   DVLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
2014   desired_fullscreen_state_ = fullscreen;
2015 
2016   if (fullscreen) {
2017     // WebKit does not resize the plugin to fill the screen in fullscreen mode,
2018     // so we will tweak plugin's attributes to support the expected behavior.
2019     KeepSizeAttributesBeforeFullscreen();
2020     SetSizeAttributesForFullscreen();
2021     container_->RequestFullscreen();
2022   } else {
2023     container_->CancelFullscreen();
2024   }
2025   return true;
2026 }
2027 
UpdateLayer(bool force_creation)2028 void PepperPluginInstanceImpl::UpdateLayer(bool force_creation) {
2029   if (!container_)
2030     return;
2031 
2032   bool want_3d_layer = !!bound_graphics_3d_.get();
2033   bool want_2d_layer = !!bound_graphics_2d_platform_;
2034   bool want_texture_layer = want_3d_layer || want_2d_layer;
2035 
2036   if (!force_creation && (want_texture_layer == !!texture_layer_) &&
2037       (want_3d_layer == layer_is_hardware_)) {
2038     UpdateLayerTransform();
2039     return;
2040   }
2041 
2042   if (texture_layer_) {
2043     container_->SetCcLayer(nullptr, false);
2044     texture_layer_->ClearClient();
2045     texture_layer_ = nullptr;
2046   }
2047 
2048   if (want_texture_layer) {
2049     bool opaque = false;
2050     if (want_3d_layer) {
2051       DCHECK(bound_graphics_3d_.get());
2052       texture_layer_ = cc::TextureLayer::CreateForMailbox(nullptr);
2053       opaque = bound_graphics_3d_->IsOpaque();
2054 
2055       PassCommittedTextureToTextureLayer();
2056     } else {
2057       DCHECK(bound_graphics_2d_platform_);
2058       texture_layer_ = cc::TextureLayer::CreateForMailbox(this);
2059       bound_graphics_2d_platform_->AttachedToNewLayer();
2060       opaque = bound_graphics_2d_platform_->IsAlwaysOpaque();
2061       texture_layer_->SetFlipped(false);
2062     }
2063 
2064     // Ignore transparency in fullscreen.
2065     texture_layer_->SetContentsOpaque(opaque);
2066   }
2067 
2068   if (texture_layer_) {
2069     container_->SetCcLayer(texture_layer_.get(), true);
2070   }
2071 
2072   layer_is_hardware_ = want_3d_layer;
2073   UpdateLayerTransform();
2074 }
2075 
PrepareTransferableResource(cc::SharedBitmapIdRegistrar * bitmap_registrar,viz::TransferableResource * transferable_resource,std::unique_ptr<viz::SingleReleaseCallback> * release_callback)2076 bool PepperPluginInstanceImpl::PrepareTransferableResource(
2077     cc::SharedBitmapIdRegistrar* bitmap_registrar,
2078     viz::TransferableResource* transferable_resource,
2079     std::unique_ptr<viz::SingleReleaseCallback>* release_callback) {
2080   if (!bound_graphics_2d_platform_)
2081     return false;
2082   return bound_graphics_2d_platform_->PrepareTransferableResource(
2083       bitmap_registrar, transferable_resource, release_callback);
2084 }
2085 
AccessibilityModeChanged(const ui::AXMode & mode)2086 void PepperPluginInstanceImpl::AccessibilityModeChanged(
2087     const ui::AXMode& mode) {
2088   HandleAccessibilityChange();
2089 }
2090 
OnDestruct()2091 void PepperPluginInstanceImpl::OnDestruct() {
2092   render_frame_ = nullptr;
2093 }
2094 
SupportsKeyboardFocus()2095 bool PepperPluginInstanceImpl::SupportsKeyboardFocus() {
2096   // Only PDF plugin supports keyboard focus. PDF plugin shouldn't be focusable
2097   // if it's embedded in Print Preview.
2098   return LoadPdfInterface() && !IsPrintPreviewUrl(document_url_);
2099 }
2100 
AddPluginObject(PluginObject * plugin_object)2101 void PepperPluginInstanceImpl::AddPluginObject(PluginObject* plugin_object) {
2102   DCHECK(live_plugin_objects_.find(plugin_object) ==
2103          live_plugin_objects_.end());
2104   live_plugin_objects_.insert(plugin_object);
2105 }
2106 
RemovePluginObject(PluginObject * plugin_object)2107 void PepperPluginInstanceImpl::RemovePluginObject(PluginObject* plugin_object) {
2108   // Don't actually verify that the object is in the set since during module
2109   // deletion we'll be in the process of freeing them.
2110   live_plugin_objects_.erase(plugin_object);
2111 }
2112 
HasTransientUserActivation() const2113 bool PepperPluginInstanceImpl::HasTransientUserActivation() const {
2114   return render_frame_->GetWebFrame()->HasTransientUserActivation();
2115 }
2116 
OnLockMouseACK(bool succeeded)2117 void PepperPluginInstanceImpl::OnLockMouseACK(bool succeeded) {
2118   if (TrackedCallback::IsPending(lock_mouse_callback_))
2119     lock_mouse_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
2120 }
2121 
OnMouseLockLost()2122 void PepperPluginInstanceImpl::OnMouseLockLost() {
2123   if (LoadMouseLockInterface())
2124     plugin_mouse_lock_interface_->MouseLockLost(pp_instance());
2125 }
2126 
HandleMouseLockedInputEvent(const blink::WebMouseEvent & event)2127 void PepperPluginInstanceImpl::HandleMouseLockedInputEvent(
2128     const blink::WebMouseEvent& event) {
2129   // |cursor| is ignored since it is hidden when the mouse is locked.
2130   ui::Cursor cursor;
2131   HandleInputEvent(event, &cursor);
2132 }
2133 
SimulateInputEvent(const InputEventData & input_event)2134 void PepperPluginInstanceImpl::SimulateInputEvent(
2135     const InputEventData& input_event) {
2136   WebWidget* widget =
2137       container()->GetDocument().GetFrame()->LocalRoot()->FrameWidget();
2138   if (!widget) {
2139     NOTREACHED();
2140     return;
2141   }
2142 
2143   bool handled = SimulateIMEEvent(input_event);
2144   if (handled)
2145     return;
2146 
2147   std::vector<std::unique_ptr<WebInputEvent>> events =
2148       CreateSimulatedWebInputEvents(
2149           input_event, view_data_.rect.point.x + view_data_.rect.size.width / 2,
2150           view_data_.rect.point.y + view_data_.rect.size.height / 2);
2151   for (auto& event : events) {
2152     widget->HandleInputEvent(
2153         blink::WebCoalescedInputEvent(std::move(event), ui::LatencyInfo()));
2154   }
2155   if (input_event.event_type == PP_INPUTEVENT_TYPE_TOUCHSTART ||
2156       input_event.event_type == PP_INPUTEVENT_TYPE_TOUCHMOVE ||
2157       input_event.event_type == PP_INPUTEVENT_TYPE_TOUCHEND ||
2158       input_event.event_type == PP_INPUTEVENT_TYPE_TOUCHCANCEL)
2159     widget->DispatchBufferedTouchEvents();
2160 }
2161 
SimulateIMEEvent(const InputEventData & input_event)2162 bool PepperPluginInstanceImpl::SimulateIMEEvent(
2163     const InputEventData& input_event) {
2164   switch (input_event.event_type) {
2165     case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
2166     case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
2167       SimulateImeSetCompositionEvent(input_event);
2168       break;
2169     case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
2170       DCHECK(input_event.character_text.empty());
2171       SimulateImeSetCompositionEvent(input_event);
2172       break;
2173     case PP_INPUTEVENT_TYPE_IME_TEXT:
2174       OnImeCommitText(base::UTF8ToUTF16(input_event.character_text),
2175                       gfx::Range(), 0);
2176       break;
2177     default:
2178       return false;
2179   }
2180   return true;
2181 }
2182 
SimulateImeSetCompositionEvent(const InputEventData & input_event)2183 void PepperPluginInstanceImpl::SimulateImeSetCompositionEvent(
2184     const InputEventData& input_event) {
2185   std::vector<size_t> offsets;
2186   offsets.push_back(input_event.composition_selection_start);
2187   offsets.push_back(input_event.composition_selection_end);
2188   offsets.insert(offsets.end(),
2189                  input_event.composition_segment_offsets.begin(),
2190                  input_event.composition_segment_offsets.end());
2191 
2192   base::string16 utf16_text =
2193       base::UTF8ToUTF16AndAdjustOffsets(input_event.character_text, &offsets);
2194 
2195   std::vector<ui::ImeTextSpan> ime_text_spans;
2196   for (size_t i = 2; i + 1 < offsets.size(); ++i) {
2197     ui::ImeTextSpan ime_text_span;
2198     ime_text_span.start_offset = offsets[i];
2199     ime_text_span.end_offset = offsets[i + 1];
2200     if (input_event.composition_target_segment == static_cast<int32_t>(i - 2))
2201       ime_text_span.thickness = ui::ImeTextSpan::Thickness::kThick;
2202     ime_text_spans.push_back(ime_text_span);
2203   }
2204 
2205   OnImeSetComposition(utf16_text, ime_text_spans, offsets[0], offsets[1]);
2206 }
2207 
BindGraphics(PP_Instance instance,PP_Resource device)2208 PP_Bool PepperPluginInstanceImpl::BindGraphics(PP_Instance instance,
2209                                                PP_Resource device) {
2210   TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::BindGraphics");
2211   // The Graphics3D instance can't be destroyed until we call
2212   // UpdateLayer().
2213   scoped_refptr<ppapi::Resource> old_graphics = bound_graphics_3d_.get();
2214   if (bound_graphics_3d_.get()) {
2215     bound_graphics_3d_->BindToInstance(false);
2216     bound_graphics_3d_ = nullptr;
2217   }
2218   if (bound_graphics_2d_platform_) {
2219     bound_graphics_2d_platform_->BindToInstance(nullptr);
2220     bound_graphics_2d_platform_ = nullptr;
2221   }
2222 
2223   // Special-case clearing the current device.
2224   if (!device) {
2225     UpdateLayer(true);
2226     InvalidateRect(gfx::Rect());
2227     return PP_TRUE;
2228   }
2229 
2230   // Refuse to bind if in transition to/from fullscreen with PPB_Fullscreen.
2231   if (desired_fullscreen_state_ != view_data_.is_fullscreen)
2232     return PP_FALSE;
2233 
2234   const ppapi::host::PpapiHost* ppapi_host =
2235       RendererPpapiHost::GetForPPInstance(instance)->GetPpapiHost();
2236   ppapi::host::ResourceHost* host = ppapi_host->GetResourceHost(device);
2237   PepperGraphics2DHost* graphics_2d = nullptr;
2238   if (host) {
2239     if (host->IsGraphics2DHost()) {
2240       graphics_2d = static_cast<PepperGraphics2DHost*>(host);
2241     } else {
2242       DLOG(ERROR) <<
2243           "Resource is not PepperCompositorHost or PepperGraphics2DHost.";
2244     }
2245   }
2246 
2247   EnterResourceNoLock<PPB_Graphics3D_API> enter_3d(device, false);
2248   PPB_Graphics3D_Impl* graphics_3d =
2249       enter_3d.succeeded()
2250           ? static_cast<PPB_Graphics3D_Impl*>(enter_3d.object())
2251           : nullptr;
2252 
2253   if (graphics_2d) {
2254     if (graphics_2d->BindToInstance(this)) {
2255       bound_graphics_2d_platform_ = graphics_2d;
2256       bound_graphics_2d_platform_->set_viewport_to_dip_scale(
2257           viewport_to_dip_scale_);
2258       UpdateLayer(true);
2259       return PP_TRUE;
2260     }
2261   } else if (graphics_3d) {
2262     // Make sure graphics can only be bound to the instance it is
2263     // associated with.
2264     if (graphics_3d->pp_instance() == pp_instance() &&
2265         graphics_3d->BindToInstance(true)) {
2266       bound_graphics_3d_ = graphics_3d;
2267       UpdateLayer(true);
2268       return PP_TRUE;
2269     }
2270   }
2271 
2272   // The instance cannot be bound or the device is not a valid resource type.
2273   return PP_FALSE;
2274 }
2275 
IsFullFrame(PP_Instance instance)2276 PP_Bool PepperPluginInstanceImpl::IsFullFrame(PP_Instance instance) {
2277   return PP_FromBool(full_frame());
2278 }
2279 
GetViewData(PP_Instance instance)2280 const ViewData* PepperPluginInstanceImpl::GetViewData(PP_Instance instance) {
2281   return &view_data_;
2282 }
2283 
GetWindowObject(PP_Instance instance)2284 PP_Var PepperPluginInstanceImpl::GetWindowObject(PP_Instance instance) {
2285   if (!container_)
2286     return PP_MakeUndefined();
2287   V8VarConverter converter(pp_instance_, V8VarConverter::kAllowObjectVars);
2288   PepperTryCatchVar try_catch(this, &converter, nullptr);
2289   WebLocalFrame* frame = container_->GetDocument().GetFrame();
2290   if (!frame) {
2291     try_catch.SetException("No frame exists for window object.");
2292     return PP_MakeUndefined();
2293   }
2294 
2295   ScopedPPVar result =
2296       try_catch.FromV8(frame->MainWorldScriptContext()->Global());
2297   DCHECK(!try_catch.HasException());
2298   return result.Release();
2299 }
2300 
GetOwnerElementObject(PP_Instance instance)2301 PP_Var PepperPluginInstanceImpl::GetOwnerElementObject(PP_Instance instance) {
2302   if (!container_)
2303     return PP_MakeUndefined();
2304   V8VarConverter converter(pp_instance_, V8VarConverter::kAllowObjectVars);
2305   PepperTryCatchVar try_catch(this, &converter, nullptr);
2306   ScopedPPVar result = try_catch.FromV8(container_->V8ObjectForElement());
2307   DCHECK(!try_catch.HasException());
2308   return result.Release();
2309 }
2310 
ExecuteScript(PP_Instance instance,PP_Var script_var,PP_Var * exception)2311 PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance,
2312                                                PP_Var script_var,
2313                                                PP_Var* exception) {
2314   if (!container_)
2315     return PP_MakeUndefined();
2316   if (is_deleted_ && blink::WebPluginScriptForbiddenScope::IsForbidden())
2317     return PP_MakeUndefined();
2318 
2319   // Executing the script may remove the plugin from the DOM, so we need to keep
2320   // a reference to ourselves so that we can still process the result after
2321   // running the script below.
2322   scoped_refptr<PepperPluginInstanceImpl> ref(this);
2323   V8VarConverter converter(pp_instance_, V8VarConverter::kAllowObjectVars);
2324   PepperTryCatchVar try_catch(this, &converter, exception);
2325 
2326   // Check for an exception due to the context being destroyed.
2327   if (try_catch.HasException())
2328     return PP_MakeUndefined();
2329 
2330   WebLocalFrame* frame = container_->GetDocument().GetFrame();
2331   if (!frame) {
2332     try_catch.SetException("No frame to execute script in.");
2333     return PP_MakeUndefined();
2334   }
2335 
2336   StringVar* script_string_var = StringVar::FromPPVar(script_var);
2337   if (!script_string_var) {
2338     try_catch.SetException("Script param to ExecuteScript must be a string.");
2339     return PP_MakeUndefined();
2340   }
2341 
2342   std::string script_string = script_string_var->value();
2343   blink::WebScriptSource script(
2344       blink::WebString::FromUTF8(script_string.c_str()));
2345   v8::Local<v8::Value> result;
2346   if (HasTransientUserActivation()) {
2347     result = frame->ExecuteScriptAndReturnValue(script);
2348   } else {
2349     result = frame->ExecuteScriptAndReturnValue(script);
2350   }
2351 
2352   ScopedPPVar var_result = try_catch.FromV8(result);
2353   if (try_catch.HasException())
2354     return PP_MakeUndefined();
2355 
2356   return var_result.Release();
2357 }
2358 
GetAudioHardwareOutputSampleRate(PP_Instance instance)2359 uint32_t PepperPluginInstanceImpl::GetAudioHardwareOutputSampleRate(
2360     PP_Instance instance) {
2361   return render_frame()
2362              ? blink::WebAudioDeviceFactory::GetOutputDeviceInfo(
2363                    render_frame()->GetWebFrame()->GetLocalFrameToken(),
2364                    media::AudioSinkParameters())
2365                    .output_params()
2366                    .sample_rate()
2367              : 0;
2368 }
2369 
GetAudioHardwareOutputBufferSize(PP_Instance instance)2370 uint32_t PepperPluginInstanceImpl::GetAudioHardwareOutputBufferSize(
2371     PP_Instance instance) {
2372   return render_frame()
2373              ? blink::WebAudioDeviceFactory::GetOutputDeviceInfo(
2374                    render_frame()->GetWebFrame()->GetLocalFrameToken(),
2375                    media::AudioSinkParameters())
2376                    .output_params()
2377                    .frames_per_buffer()
2378              : 0;
2379 }
2380 
GetDefaultCharSet(PP_Instance instance)2381 PP_Var PepperPluginInstanceImpl::GetDefaultCharSet(PP_Instance instance) {
2382   if (!render_frame_)
2383     return PP_MakeUndefined();
2384   return StringVar::StringToPPVar(
2385       render_frame_->render_view()->GetBlinkPreferences().default_encoding);
2386 }
2387 
SetPluginToHandleFindRequests(PP_Instance instance)2388 void PepperPluginInstanceImpl::SetPluginToHandleFindRequests(
2389     PP_Instance instance) {
2390   if (!LoadFindInterface())
2391     return;
2392   bool is_main_frame =
2393       render_frame_ &&
2394       render_frame_->GetRenderView()->GetMainRenderFrame() == render_frame_;
2395   if (!is_main_frame)
2396     return;
2397   container_->UsePluginAsFindHandler();
2398 }
2399 
NumberOfFindResultsChanged(PP_Instance instance,int32_t total,PP_Bool final_result)2400 void PepperPluginInstanceImpl::NumberOfFindResultsChanged(
2401     PP_Instance instance,
2402     int32_t total,
2403     PP_Bool final_result) {
2404   // After stopping search and setting find_identifier_ to -1 there still may be
2405   // a NumberOfFindResultsChanged notification pending from plug-in. Just ignore
2406   // them.
2407   if (find_identifier_ == -1)
2408     return;
2409   if (!container_)
2410     return;
2411   container_->ReportFindInPageMatchCount(find_identifier_, total,
2412                                          PP_ToBool(final_result));
2413 }
2414 
SelectedFindResultChanged(PP_Instance instance,int32_t index)2415 void PepperPluginInstanceImpl::SelectedFindResultChanged(PP_Instance instance,
2416                                                          int32_t index) {
2417   if (find_identifier_ == -1)
2418     return;
2419   if (!container_)
2420     return;
2421   container_->ReportFindInPageSelection(find_identifier_, index + 1);
2422 }
2423 
SetTickmarks(PP_Instance instance,const PP_Rect * tickmarks,uint32_t count)2424 void PepperPluginInstanceImpl::SetTickmarks(PP_Instance instance,
2425                                             const PP_Rect* tickmarks,
2426                                             uint32_t count) {
2427   if (!render_frame_ || !render_frame_->GetWebFrame())
2428     return;
2429 
2430   blink::WebVector<blink::WebRect> tickmarks_converted(
2431       static_cast<size_t>(count));
2432   for (uint32_t i = 0; i < count; ++i) {
2433     gfx::RectF tickmark(tickmarks[i].point.x,
2434                         tickmarks[i].point.y,
2435                         tickmarks[i].size.width,
2436                         tickmarks[i].size.height);
2437     tickmark.Scale(1 / viewport_to_dip_scale_);
2438     tickmarks_converted[i] = blink::WebRect(gfx::ToEnclosedRect(tickmark));
2439   }
2440 
2441   WebLocalFrame* frame = render_frame_->GetWebFrame();
2442   WebElement target;
2443   if (LoadPdfInterface())
2444     target = FindPdfViewerScroller(frame, container_->GetElement());
2445   frame->SetTickmarks(target, tickmarks_converted);
2446 }
2447 
IsFullscreen(PP_Instance instance)2448 PP_Bool PepperPluginInstanceImpl::IsFullscreen(PP_Instance instance) {
2449   return PP_FromBool(view_data_.is_fullscreen);
2450 }
2451 
SetFullscreen(PP_Instance instance,PP_Bool fullscreen)2452 PP_Bool PepperPluginInstanceImpl::SetFullscreen(PP_Instance instance,
2453                                                 PP_Bool fullscreen) {
2454   return PP_FromBool(SetFullscreen(PP_ToBool(fullscreen)));
2455 }
2456 
GetScreenSize(PP_Instance instance,PP_Size * size)2457 PP_Bool PepperPluginInstanceImpl::GetScreenSize(PP_Instance instance,
2458                                                 PP_Size* size) {
2459   // All other cases: Report the screen size.
2460   if (!render_frame_)
2461     return PP_FALSE;
2462   blink::ScreenInfo info = render_frame_->GetLocalRootRenderWidget()
2463                                ->GetWebWidget()
2464                                ->GetScreenInfo();
2465   *size = PP_MakeSize(info.rect.width(), info.rect.height());
2466   return PP_TRUE;
2467 }
2468 
GetSingletonResource(PP_Instance instance,ppapi::SingletonResourceID id)2469 ppapi::Resource* PepperPluginInstanceImpl::GetSingletonResource(
2470     PP_Instance instance,
2471     ppapi::SingletonResourceID id) {
2472   // Some APIs aren't implemented in-process.
2473   switch (id) {
2474     case ppapi::BROWSER_FONT_SINGLETON_ID:
2475     case ppapi::FLASH_FULLSCREEN_SINGLETON_ID:
2476     case ppapi::ISOLATED_FILESYSTEM_SINGLETON_ID:
2477     case ppapi::NETWORK_PROXY_SINGLETON_ID:
2478     case ppapi::PDF_SINGLETON_ID:
2479       NOTIMPLEMENTED();
2480       return nullptr;
2481     case ppapi::GAMEPAD_SINGLETON_ID:
2482       return gamepad_impl_.get();
2483     case ppapi::UMA_SINGLETON_ID: {
2484       if (!uma_private_impl_.get()) {
2485         RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
2486         if (host_impl->in_process_router()) {
2487           uma_private_impl_ = new ppapi::proxy::UMAPrivateResource(
2488               host_impl->in_process_router()->GetPluginConnection(instance),
2489               instance);
2490         }
2491       }
2492       return uma_private_impl_.get();
2493     }
2494   }
2495 
2496   NOTREACHED();
2497   return nullptr;
2498 }
2499 
RequestInputEvents(PP_Instance instance,uint32_t event_classes)2500 int32_t PepperPluginInstanceImpl::RequestInputEvents(PP_Instance instance,
2501                                                      uint32_t event_classes) {
2502   input_event_mask_ |= event_classes;
2503   filtered_input_event_mask_ &= ~(event_classes);
2504   RequestInputEventsHelper(event_classes);
2505   return ValidateRequestInputEvents(false, event_classes);
2506 }
2507 
RequestFilteringInputEvents(PP_Instance instance,uint32_t event_classes)2508 int32_t PepperPluginInstanceImpl::RequestFilteringInputEvents(
2509     PP_Instance instance,
2510     uint32_t event_classes) {
2511   filtered_input_event_mask_ |= event_classes;
2512   input_event_mask_ &= ~(event_classes);
2513   RequestInputEventsHelper(event_classes);
2514   return ValidateRequestInputEvents(true, event_classes);
2515 }
2516 
ClearInputEventRequest(PP_Instance instance,uint32_t event_classes)2517 void PepperPluginInstanceImpl::ClearInputEventRequest(PP_Instance instance,
2518                                                       uint32_t event_classes) {
2519   input_event_mask_ &= ~(event_classes);
2520   filtered_input_event_mask_ &= ~(event_classes);
2521   RequestInputEventsHelper(event_classes);
2522 }
2523 
PostMessage(PP_Instance instance,PP_Var message)2524 void PepperPluginInstanceImpl::PostMessage(PP_Instance instance,
2525                                            PP_Var message) {
2526   PostMessageToJavaScript(message);
2527 }
2528 
SetCursor(PP_Instance instance,PP_MouseCursor_Type type,PP_Resource image,const PP_Point * hot_spot)2529 PP_Bool PepperPluginInstanceImpl::SetCursor(PP_Instance instance,
2530                                             PP_MouseCursor_Type type,
2531                                             PP_Resource image,
2532                                             const PP_Point* hot_spot) {
2533   if (!ValidateSetCursorParams(type, image, hot_spot))
2534     return PP_FALSE;
2535 
2536   if (type != PP_MOUSECURSOR_TYPE_CUSTOM) {
2537     DoSetCursor(
2538         std::make_unique<ui::Cursor>(static_cast<ui::mojom::CursorType>(type)));
2539     return PP_TRUE;
2540   }
2541 
2542   EnterResourceNoLock<PPB_ImageData_API> enter(image, true);
2543   if (enter.failed())
2544     return PP_FALSE;
2545   PPB_ImageData_Impl* image_data =
2546       static_cast<PPB_ImageData_Impl*>(enter.object());
2547 
2548   ImageDataAutoMapper auto_mapper(image_data);
2549   if (!auto_mapper.is_valid())
2550     return PP_FALSE;
2551 
2552   auto custom_cursor =
2553       std::make_unique<ui::Cursor>(ui::mojom::CursorType::kCustom);
2554   custom_cursor->set_custom_hotspot(gfx::Point(hot_spot->x, hot_spot->y));
2555 
2556   SkBitmap bitmap(image_data->GetMappedBitmap());
2557   // Make a deep copy, so that the cursor remains valid even after the original
2558   // image data gets freed.
2559   SkBitmap dst = custom_cursor->custom_bitmap();
2560   if (!dst.tryAllocPixels(bitmap.info()) ||
2561       !bitmap.readPixels(dst.info(), dst.getPixels(), dst.rowBytes(), 0, 0)) {
2562     return PP_FALSE;
2563   }
2564   custom_cursor->set_custom_bitmap(dst);
2565 
2566   DoSetCursor(std::move(custom_cursor));
2567   return PP_TRUE;
2568 }
2569 
LockMouse(PP_Instance instance,scoped_refptr<TrackedCallback> callback)2570 int32_t PepperPluginInstanceImpl::LockMouse(
2571     PP_Instance instance,
2572     scoped_refptr<TrackedCallback> callback) {
2573   if (TrackedCallback::IsPending(lock_mouse_callback_))
2574     return PP_ERROR_INPROGRESS;
2575 
2576   if (IsMouseLocked())
2577     return PP_OK;
2578 
2579   if (!CanAccessMainFrame())
2580     return PP_ERROR_NOACCESS;
2581 
2582   if (!HasTransientUserActivation())
2583     return PP_ERROR_NO_USER_GESTURE;
2584 
2585   if (!LockMouse(false))
2586     return PP_ERROR_FAILED;
2587 
2588   lock_mouse_callback_ = callback;
2589   return PP_OK_COMPLETIONPENDING;
2590 }
2591 
UnlockMouse(PP_Instance instance)2592 void PepperPluginInstanceImpl::UnlockMouse(PP_Instance instance) {
2593   container_->UnlockMouse();
2594 }
2595 
SetTextInputType(PP_Instance instance,PP_TextInput_Type type)2596 void PepperPluginInstanceImpl::SetTextInputType(PP_Instance instance,
2597                                                 PP_TextInput_Type type) {
2598   if (!render_frame_)
2599     return;
2600   int itype = type;
2601   if (itype < 0 || itype > ui::TEXT_INPUT_TYPE_URL)
2602     itype = ui::TEXT_INPUT_TYPE_NONE;
2603   SetTextInputType(static_cast<ui::TextInputType>(itype));
2604 }
2605 
UpdateCaretPosition(PP_Instance instance,const PP_Rect & caret,const PP_Rect & bounding_box)2606 void PepperPluginInstanceImpl::UpdateCaretPosition(
2607     PP_Instance instance,
2608     const PP_Rect& caret,
2609     const PP_Rect& bounding_box) {
2610   if (!render_frame_)
2611     return;
2612   TextInputCaretInfo info = {PP_ToGfxRect(caret), PP_ToGfxRect(bounding_box)};
2613   text_input_caret_info_ = std::move(info);
2614   render_frame_->PepperCaretPositionChanged(this);
2615 }
2616 
CancelCompositionText(PP_Instance instance)2617 void PepperPluginInstanceImpl::CancelCompositionText(PP_Instance instance) {
2618   if (render_frame_)
2619     render_frame_->PepperCancelComposition(this);
2620 }
2621 
SelectionChanged(PP_Instance instance)2622 void PepperPluginInstanceImpl::SelectionChanged(PP_Instance instance) {
2623   // TODO(kinaba): currently the browser always calls RequestSurroundingText.
2624   // It can be optimized so that it won't call it back until the information
2625   // is really needed.
2626 
2627   // Avoid calling in nested context or else this will reenter the plugin. This
2628   // uses a weak pointer rather than exploiting the fact that this class is
2629   // refcounted because we don't actually want this operation to affect the
2630   // lifetime of the instance.
2631   base::ThreadTaskRunnerHandle::Get()->PostTask(
2632       FROM_HERE,
2633       base::BindOnce(&PepperPluginInstanceImpl::RequestSurroundingText,
2634                      weak_factory_.GetWeakPtr(),
2635                      static_cast<size_t>(kExtraCharsForTextInput)));
2636 }
2637 
UpdateSurroundingText(PP_Instance instance,const char * text,uint32_t caret,uint32_t anchor)2638 void PepperPluginInstanceImpl::UpdateSurroundingText(PP_Instance instance,
2639                                                      const char* text,
2640                                                      uint32_t caret,
2641                                                      uint32_t anchor) {
2642   if (!render_frame_)
2643     return;
2644   surrounding_text_ = text;
2645   selection_caret_ = caret;
2646   selection_anchor_ = anchor;
2647   render_frame_->PepperSelectionChanged(this);
2648 }
2649 
ResolveRelativeToDocument(PP_Instance instance,PP_Var relative,PP_URLComponents_Dev * components)2650 PP_Var PepperPluginInstanceImpl::ResolveRelativeToDocument(
2651     PP_Instance instance,
2652     PP_Var relative,
2653     PP_URLComponents_Dev* components) {
2654   StringVar* relative_string = StringVar::FromPPVar(relative);
2655   if (!relative_string)
2656     return PP_MakeNull();
2657 
2658   GURL document_url = container()->GetDocument().BaseURL();
2659   return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(
2660       document_url.Resolve(relative_string->value()), components);
2661 }
2662 
DocumentCanRequest(PP_Instance instance,PP_Var url)2663 PP_Bool PepperPluginInstanceImpl::DocumentCanRequest(PP_Instance instance,
2664                                                      PP_Var url) {
2665   StringVar* url_string = StringVar::FromPPVar(url);
2666   if (!url_string)
2667     return PP_FALSE;
2668 
2669   blink::WebSecurityOrigin security_origin;
2670   if (!SecurityOriginForInstance(instance, &security_origin))
2671     return PP_FALSE;
2672 
2673   GURL gurl(url_string->value());
2674   if (!gurl.is_valid())
2675     return PP_FALSE;
2676 
2677   return PP_FromBool(security_origin.CanRequest(gurl));
2678 }
2679 
DocumentCanAccessDocument(PP_Instance instance,PP_Instance target)2680 PP_Bool PepperPluginInstanceImpl::DocumentCanAccessDocument(
2681     PP_Instance instance,
2682     PP_Instance target) {
2683   blink::WebSecurityOrigin our_origin;
2684   if (!SecurityOriginForInstance(instance, &our_origin))
2685     return PP_FALSE;
2686 
2687   blink::WebSecurityOrigin target_origin;
2688   if (!SecurityOriginForInstance(instance, &target_origin))
2689     return PP_FALSE;
2690 
2691   return PP_FromBool(our_origin.CanAccess(target_origin));
2692 }
2693 
GetDocumentURL(PP_Instance instance,PP_URLComponents_Dev * components)2694 PP_Var PepperPluginInstanceImpl::GetDocumentURL(
2695     PP_Instance instance,
2696     PP_URLComponents_Dev* components) {
2697   blink::WebDocument document = container()->GetDocument();
2698   return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(document.Url(),
2699                                                       components);
2700 }
2701 
GetPluginInstanceURL(PP_Instance instance,PP_URLComponents_Dev * components)2702 PP_Var PepperPluginInstanceImpl::GetPluginInstanceURL(
2703     PP_Instance instance,
2704     PP_URLComponents_Dev* components) {
2705   return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(plugin_url_, components);
2706 }
2707 
GetPluginReferrerURL(PP_Instance instance,PP_URLComponents_Dev * components)2708 PP_Var PepperPluginInstanceImpl::GetPluginReferrerURL(
2709     PP_Instance instance,
2710     PP_URLComponents_Dev* components) {
2711   blink::WebDocument document = container()->GetDocument();
2712   if (!full_frame_)
2713     return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(document.Url(),
2714                                                         components);
2715   WebLocalFrame* frame = document.GetFrame();
2716   if (!frame)
2717     return PP_MakeUndefined();
2718   WebString referer = frame->GetDocumentLoader()->OriginalReferrer();
2719   if (referer.IsEmpty())
2720     return PP_MakeUndefined();
2721   return ppapi::PPB_URLUtil_Shared::GenerateURLReturn(
2722       blink::WebStringToGURL(referer), components);
2723 }
2724 
ResetAsProxied(scoped_refptr<PluginModule> module)2725 PP_ExternalPluginResult PepperPluginInstanceImpl::ResetAsProxied(
2726     scoped_refptr<PluginModule> module) {
2727   // Save the original module and switch over to the new one now that this
2728   // plugin is using the IPC-based proxy.
2729   original_module_ = module_;
2730   module_ = module;
2731 
2732   // For NaCl instances, remember the NaCl plugin instance interface, so we
2733   // can shut it down by calling its DidDestroy in our Delete() method.
2734   original_instance_interface_ = std::move(instance_interface_);
2735 
2736   base::RepeatingCallback<const void*(const char*)> get_plugin_interface_func =
2737       base::BindRepeating(&PluginModule::GetPluginInterface, module_);
2738   PPP_Instance_Combined* ppp_instance_combined =
2739       PPP_Instance_Combined::Create(std::move(get_plugin_interface_func));
2740   if (!ppp_instance_combined) {
2741     // The proxy must support at least one usable PPP_Instance interface.
2742     // While this could be a failure to implement the interface in the NaCl
2743     // module, it is more likely that the NaCl process has crashed. Either
2744     // way, report that module initialization failed.
2745     return PP_EXTERNAL_PLUGIN_ERROR_MODULE;
2746   }
2747 
2748   instance_interface_.reset(ppp_instance_combined);
2749   // Clear all PPP interfaces we may have cached.
2750   plugin_find_interface_ = nullptr;
2751   plugin_input_event_interface_ = nullptr;
2752   checked_for_plugin_input_event_interface_ = false;
2753   plugin_mouse_lock_interface_ = nullptr;
2754   plugin_pdf_interface_ = nullptr;
2755   checked_for_plugin_pdf_interface_ = false;
2756   plugin_private_interface_ = nullptr;
2757   plugin_textinput_interface_ = nullptr;
2758 
2759   // Re-send the DidCreate event via the proxy.
2760   std::unique_ptr<const char* []> argn_array(StringVectorToArgArray(argn_));
2761   std::unique_ptr<const char* []> argv_array(StringVectorToArgArray(argv_));
2762   if (!instance_interface_->DidCreate(
2763           pp_instance(), argn_.size(), argn_array.get(), argv_array.get()))
2764     return PP_EXTERNAL_PLUGIN_ERROR_INSTANCE;
2765   if (message_channel_)
2766     message_channel_->Start();
2767 
2768   // Clear sent_initial_did_change_view_ and cancel any pending DidChangeView
2769   // event. This way, SendDidChangeView will send the "current" view
2770   // immediately (before other events like HandleDocumentLoad).
2771   sent_initial_did_change_view_ = false;
2772   view_change_weak_ptr_factory_.InvalidateWeakPtrs();
2773   SendDidChangeView();
2774 
2775   DCHECK(external_document_load_);
2776   external_document_load_ = false;
2777   if (!external_document_response_.IsNull()) {
2778     document_loader_ = nullptr;
2779     // Pass the response to the new proxy.
2780     HandleDocumentLoad(external_document_response_);
2781     external_document_response_ = blink::WebURLResponse();
2782     // Replay any document load events we've received to the real loader.
2783     external_document_loader_->ReplayReceivedData(document_loader_);
2784     external_document_loader_.reset();
2785   }
2786 
2787   return PP_EXTERNAL_PLUGIN_OK;
2788 }
2789 
IsValidInstanceOf(PluginModule * module)2790 bool PepperPluginInstanceImpl::IsValidInstanceOf(PluginModule* module) {
2791   DCHECK(module);
2792   return module == module_.get() || module == original_module_.get();
2793 }
2794 
GetRenderFrame()2795 RenderFrame* PepperPluginInstanceImpl::GetRenderFrame() {
2796   return render_frame_;
2797 }
2798 
GetContainer()2799 blink::WebPluginContainer* PepperPluginInstanceImpl::GetContainer() {
2800   return container_;
2801 }
2802 
GetIsolate()2803 v8::Isolate* PepperPluginInstanceImpl::GetIsolate() {
2804   return isolate_;
2805 }
2806 
GetVarTracker()2807 ppapi::VarTracker* PepperPluginInstanceImpl::GetVarTracker() {
2808   return HostGlobals::Get()->GetVarTracker();
2809 }
2810 
GetPluginURL()2811 const GURL& PepperPluginInstanceImpl::GetPluginURL() { return plugin_url_; }
2812 
GetModulePath()2813 base::FilePath PepperPluginInstanceImpl::GetModulePath() {
2814   return module_->path();
2815 }
2816 
CreateImage(gfx::ImageSkia * source_image,float scale)2817 PP_Resource PepperPluginInstanceImpl::CreateImage(gfx::ImageSkia* source_image,
2818                                                   float scale) {
2819   gfx::ImageSkiaRep image_skia_rep = source_image->GetRepresentation(scale);
2820 
2821   if (image_skia_rep.is_null() || image_skia_rep.scale() != scale)
2822     return 0;
2823 
2824   scoped_refptr<PPB_ImageData_Impl> image_data(
2825       new PPB_ImageData_Impl(pp_instance(), PPB_ImageData_Impl::PLATFORM));
2826   if (!image_data->Init(PPB_ImageData_Impl::GetNativeImageDataFormat(),
2827                         image_skia_rep.pixel_width(),
2828                         image_skia_rep.pixel_height(),
2829                         false)) {
2830     return 0;
2831   }
2832 
2833   ImageDataAutoMapper mapper(image_data.get());
2834   if (!mapper.is_valid())
2835     return 0;
2836 
2837   SkCanvas* canvas = image_data->GetCanvas();
2838   // Note: Do not SkBitmap::copyTo the canvas bitmap directly because it will
2839   // ignore the allocated pixels in shared memory and re-allocate a new buffer.
2840   canvas->writePixels(image_skia_rep.GetBitmap(), 0, 0);
2841 
2842   return image_data->GetReference();
2843 }
2844 
SwitchToOutOfProcessProxy(const base::FilePath & file_path,ppapi::PpapiPermissions permissions,const IPC::ChannelHandle & channel_handle,base::ProcessId plugin_pid,int plugin_child_id)2845 PP_ExternalPluginResult PepperPluginInstanceImpl::SwitchToOutOfProcessProxy(
2846     const base::FilePath& file_path,
2847     ppapi::PpapiPermissions permissions,
2848     const IPC::ChannelHandle& channel_handle,
2849     base::ProcessId plugin_pid,
2850     int plugin_child_id) {
2851   // Create a new module for each instance of the external plugin that is using
2852   // the IPC based out-of-process proxy. We can't use the existing module,
2853   // because it is configured for the in-process plugin, and we must keep it
2854   // that way to allow the page to create other instances.
2855   scoped_refptr<PluginModule> external_plugin_module(
2856       module_->CreateModuleForExternalPluginInstance());
2857 
2858   RendererPpapiHostImpl* renderer_ppapi_host =
2859       external_plugin_module->CreateOutOfProcessModule(
2860           render_frame_, file_path, permissions, channel_handle, plugin_pid,
2861           plugin_child_id, true,
2862           render_frame_->GetTaskRunner(blink::TaskType::kInternalDefault));
2863   if (!renderer_ppapi_host) {
2864     DLOG(ERROR) << "CreateExternalPluginModule() failed";
2865     return PP_EXTERNAL_PLUGIN_ERROR_MODULE;
2866   }
2867 
2868   // Finally, switch the instance to the proxy.
2869   return external_plugin_module->InitAsProxiedExternalPlugin(this);
2870 }
2871 
SetAlwaysOnTop(bool on_top)2872 void PepperPluginInstanceImpl::SetAlwaysOnTop(bool on_top) {
2873   always_on_top_ = on_top;
2874 }
2875 
DoSetCursor(std::unique_ptr<ui::Cursor> cursor)2876 void PepperPluginInstanceImpl::DoSetCursor(std::unique_ptr<ui::Cursor> cursor) {
2877   if (is_deleted_)
2878     return;
2879 
2880   cursor_ = std::move(cursor);
2881   if (render_frame_) {
2882     // Update the cursor appearance immediately if the requesting plugin is the
2883     // one which receives the last mouse event. Otherwise, the new cursor won't
2884     // be picked up until the plugin gets the next input event. That is bad if,
2885     // e.g., the plugin would like to set an invisible cursor when there isn't
2886     // any user input for a while.
2887     if (container()->WasTargetForLastMouseEvent()) {
2888       render_frame_->GetLocalRootRenderWidget()->GetWebWidget()->SetCursor(
2889           *cursor_);
2890     }
2891   }
2892 }
2893 
IsFullPagePlugin()2894 bool PepperPluginInstanceImpl::IsFullPagePlugin() {
2895   WebLocalFrame* frame = container()->GetDocument().GetFrame();
2896   return frame->View()->MainFrame()->IsWebLocalFrame() &&
2897          frame->View()
2898              ->MainFrame()
2899              ->ToWebLocalFrame()
2900              ->GetDocument()
2901              .IsPluginDocument();
2902 }
2903 
IsRectTopmost(const gfx::Rect & rect)2904 bool PepperPluginInstanceImpl::IsRectTopmost(const gfx::Rect& rect) {
2905   return container_->IsRectTopmost(rect);
2906 }
2907 
MakePendingFileRefRendererHost(const base::FilePath & path)2908 int PepperPluginInstanceImpl::MakePendingFileRefRendererHost(
2909     const base::FilePath& path) {
2910   RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
2911   PepperFileRefRendererHost* file_ref_host(
2912       new PepperFileRefRendererHost(host_impl, pp_instance(), 0, path));
2913   return host_impl->GetPpapiHost()->AddPendingResourceHost(
2914       std::unique_ptr<ppapi::host::ResourceHost>(file_ref_host));
2915 }
2916 
SetEmbedProperty(PP_Var key,PP_Var value)2917 void PepperPluginInstanceImpl::SetEmbedProperty(PP_Var key, PP_Var value) {
2918   if (message_channel_)
2919     message_channel_->SetReadOnlyProperty(key, value);
2920 }
2921 
CanAccessMainFrame() const2922 bool PepperPluginInstanceImpl::CanAccessMainFrame() const {
2923   if (!container_)
2924     return false;
2925   blink::WebDocument containing_document = container_->GetDocument();
2926 
2927   if (!containing_document.GetFrame() ||
2928       !containing_document.GetFrame()->View() ||
2929       !containing_document.GetFrame()->View()->MainFrame()) {
2930     return false;
2931   }
2932   blink::WebFrame* main_frame =
2933       containing_document.GetFrame()->View()->MainFrame();
2934 
2935   return containing_document.GetSecurityOrigin().CanAccess(
2936       main_frame->GetSecurityOrigin());
2937 }
2938 
KeepSizeAttributesBeforeFullscreen()2939 void PepperPluginInstanceImpl::KeepSizeAttributesBeforeFullscreen() {
2940   WebElement element = container_->GetElement();
2941   width_before_fullscreen_ = element.GetAttribute(WebString::FromUTF8(kWidth));
2942   height_before_fullscreen_ =
2943       element.GetAttribute(WebString::FromUTF8(kHeight));
2944   border_before_fullscreen_ =
2945       element.GetAttribute(WebString::FromUTF8(kBorder));
2946   style_before_fullscreen_ = element.GetAttribute(WebString::FromUTF8(kStyle));
2947 }
2948 
SetSizeAttributesForFullscreen()2949 void PepperPluginInstanceImpl::SetSizeAttributesForFullscreen() {
2950   if (!render_frame_)
2951     return;
2952 
2953   // TODO(miu): Revisit this logic.  If the style must be modified for correct
2954   // behavior, the width and height should probably be set to 100%, rather than
2955   // a fixed screen size.
2956 
2957   blink::ScreenInfo info = render_frame_->GetLocalRootRenderWidget()
2958                                ->GetWebWidget()
2959                                ->GetScreenInfo();
2960   screen_size_for_fullscreen_ = info.rect.size();
2961   std::string width = base::NumberToString(screen_size_for_fullscreen_.width());
2962   std::string height =
2963       base::NumberToString(screen_size_for_fullscreen_.height());
2964 
2965   WebElement element = container_->GetElement();
2966   element.SetAttribute(WebString::FromUTF8(kWidth), WebString::FromUTF8(width));
2967   element.SetAttribute(WebString::FromUTF8(kHeight),
2968                        WebString::FromUTF8(height));
2969   element.SetAttribute(WebString::FromUTF8(kBorder), WebString::FromUTF8("0"));
2970 
2971   // There should be no style settings that matter in fullscreen mode,
2972   // so just replace them instead of appending.
2973   // NOTE: "position: fixed" and "display: block" reset the plugin and
2974   // using %% settings might not work without them (e.g. if the plugin is a
2975   // child of a container element).
2976   std::string style;
2977   style += StringPrintf("width: %s !important; ", width.c_str());
2978   style += StringPrintf("height: %s !important; ", height.c_str());
2979   style += "margin: 0 !important; padding: 0 !important; border: 0 !important";
2980   container_->GetElement().SetAttribute(kStyle, WebString::FromUTF8(style));
2981 }
2982 
ResetSizeAttributesAfterFullscreen()2983 void PepperPluginInstanceImpl::ResetSizeAttributesAfterFullscreen() {
2984   screen_size_for_fullscreen_ = gfx::Size();
2985   WebElement element = container_->GetElement();
2986   element.SetAttribute(WebString::FromUTF8(kWidth), width_before_fullscreen_);
2987   element.SetAttribute(WebString::FromUTF8(kHeight), height_before_fullscreen_);
2988   element.SetAttribute(WebString::FromUTF8(kBorder), border_before_fullscreen_);
2989   element.SetAttribute(WebString::FromUTF8(kStyle), style_before_fullscreen_);
2990 }
2991 
IsMouseLocked()2992 bool PepperPluginInstanceImpl::IsMouseLocked() {
2993   return container_->IsMouseLocked();
2994 }
2995 
LockMouse(bool request_unadjusted_movement)2996 bool PepperPluginInstanceImpl::LockMouse(bool request_unadjusted_movement) {
2997   return container_->LockMouse(request_unadjusted_movement);
2998 }
2999 
DidDataFromWebURLResponse(const blink::WebURLResponse & response,int pending_host_id,const ppapi::URLResponseInfoData & data)3000 void PepperPluginInstanceImpl::DidDataFromWebURLResponse(
3001     const blink::WebURLResponse& response,
3002     int pending_host_id,
3003     const ppapi::URLResponseInfoData& data) {
3004   if (is_deleted_)
3005     return;
3006 
3007   RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();
3008 
3009   if (host_impl->in_process_router()) {
3010     // Running in-process, we can just create the resource and call the
3011     // PPP_Instance function directly.
3012     scoped_refptr<ppapi::proxy::URLLoaderResource> loader_resource(
3013         new ppapi::proxy::URLLoaderResource(
3014             host_impl->in_process_router()->GetPluginConnection(pp_instance()),
3015             pp_instance(),
3016             pending_host_id,
3017             data));
3018 
3019     PP_Resource loader_pp_resource = loader_resource->GetReference();
3020     if (!instance_interface_->HandleDocumentLoad(pp_instance(),
3021                                                  loader_pp_resource))
3022       loader_resource->Close();
3023     // We don't pass a ref into the plugin, if it wants one, it will have taken
3024     // an additional one.
3025     ppapi::PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(
3026         loader_pp_resource);
3027   } else {
3028     // Running out-of-process. Initiate an IPC call to notify the plugin
3029     // process.
3030     ppapi::proxy::HostDispatcher* dispatcher =
3031         ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
3032     dispatcher->Send(new PpapiMsg_PPPInstance_HandleDocumentLoad(
3033         ppapi::API_ID_PPP_INSTANCE, pp_instance(), pending_host_id, data));
3034   }
3035 }
3036 
ConvertRectToDIP(PP_Rect * rect) const3037 void PepperPluginInstanceImpl::ConvertRectToDIP(PP_Rect* rect) const {
3038   rect->point.x *= viewport_to_dip_scale_;
3039   rect->point.y *= viewport_to_dip_scale_;
3040   rect->size.width *= viewport_to_dip_scale_;
3041   rect->size.height *= viewport_to_dip_scale_;
3042 }
3043 
ConvertDIPToViewport(gfx::Rect * rect) const3044 void PepperPluginInstanceImpl::ConvertDIPToViewport(gfx::Rect* rect) const {
3045   rect->set_x(rect->x() / viewport_to_dip_scale_);
3046   rect->set_y(rect->y() / viewport_to_dip_scale_);
3047   rect->set_width(rect->width() / viewport_to_dip_scale_);
3048   rect->set_height(rect->height() / viewport_to_dip_scale_);
3049 }
3050 
IncrementTextureReferenceCount(const viz::TransferableResource & resource)3051 void PepperPluginInstanceImpl::IncrementTextureReferenceCount(
3052     const viz::TransferableResource& resource) {
3053   auto it =
3054       std::find_if(texture_ref_counts_.begin(), texture_ref_counts_.end(),
3055                    [&resource](const MailboxRefCount& ref_count) {
3056                      return ref_count.first == resource.mailbox_holder.mailbox;
3057                    });
3058   if (it == texture_ref_counts_.end()) {
3059     texture_ref_counts_.emplace_back(resource.mailbox_holder.mailbox, 1);
3060     return;
3061   }
3062 
3063   it->second++;
3064 }
3065 
DecrementTextureReferenceCount(const viz::TransferableResource & resource)3066 bool PepperPluginInstanceImpl::DecrementTextureReferenceCount(
3067     const viz::TransferableResource& resource) {
3068   auto it =
3069       std::find_if(texture_ref_counts_.begin(), texture_ref_counts_.end(),
3070                    [&resource](const MailboxRefCount& ref_count) {
3071                      return ref_count.first == resource.mailbox_holder.mailbox;
3072                    });
3073   DCHECK(it != texture_ref_counts_.end());
3074 
3075   if (it->second == 1) {
3076     texture_ref_counts_.erase(it);
3077     return true;
3078   }
3079 
3080   it->second--;
3081   return false;
3082 }
3083 
IsTextureInUse(const viz::TransferableResource & resource) const3084 bool PepperPluginInstanceImpl::IsTextureInUse(
3085     const viz::TransferableResource& resource) const {
3086   auto it =
3087       std::find_if(texture_ref_counts_.begin(), texture_ref_counts_.end(),
3088                    [&resource](const MailboxRefCount& ref_count) {
3089                      return ref_count.first == resource.mailbox_holder.mailbox;
3090                    });
3091   return it != texture_ref_counts_.end();
3092 }
3093 
HandleAccessibilityChange()3094 void PepperPluginInstanceImpl::HandleAccessibilityChange() {
3095   if (render_frame_ && render_frame_->GetRenderAccessibility() &&
3096       LoadPdfInterface()) {
3097     plugin_pdf_interface_->EnableAccessibility(pp_instance());
3098   }
3099 }
3100 
OnImeSetComposition(const base::string16 & text,const std::vector<ui::ImeTextSpan> & ime_text_spans,int selection_start,int selection_end)3101 void PepperPluginInstanceImpl::OnImeSetComposition(
3102     const base::string16& text,
3103     const std::vector<ui::ImeTextSpan>& ime_text_spans,
3104     int selection_start,
3105     int selection_end) {
3106   // When a PPAPI plugin has focus, we bypass blink core editing composition
3107   // events.
3108   if (!IsPluginAcceptingCompositionEvents()) {
3109     composition_text_ = text;
3110   } else {
3111     // TODO(kinaba) currently all composition events are sent directly to
3112     // plugins. Use DOM event mechanism after blink is made aware about
3113     // plugins that support composition.
3114     // The code below mimics the behavior of blink::Editor::setComposition.
3115 
3116     // Empty -> nonempty: composition started.
3117     if (composition_text_.empty() && !text.empty()) {
3118       HandleCompositionStart(base::string16());
3119     }
3120     // Nonempty -> empty: composition canceled.
3121     if (!composition_text_.empty() && text.empty()) {
3122       HandleCompositionEnd(base::string16());
3123     }
3124     composition_text_ = text;
3125     // Nonempty: composition is ongoing.
3126     if (!composition_text_.empty()) {
3127       HandleCompositionUpdate(composition_text_, ime_text_spans,
3128                               selection_start, selection_end);
3129     }
3130   }
3131 }
3132 
OnImeCommitText(const base::string16 & text,const gfx::Range & replacement_range,int relative_cursor_pos)3133 void PepperPluginInstanceImpl::OnImeCommitText(
3134     const base::string16& text,
3135     const gfx::Range& replacement_range,
3136     int relative_cursor_pos) {
3137   HandlePepperImeCommit(text);
3138 }
3139 
OnImeFinishComposingText(bool keep_selection)3140 void PepperPluginInstanceImpl::OnImeFinishComposingText(bool keep_selection) {
3141   const base::string16& text = composition_text_;
3142   HandlePepperImeCommit(text);
3143 }
3144 
HandlePepperImeCommit(const base::string16 & text)3145 void PepperPluginInstanceImpl::HandlePepperImeCommit(
3146     const base::string16& text) {
3147   if (text.empty())
3148     return;
3149 
3150   if (!IsPluginAcceptingCompositionEvents()) {
3151     // For pepper plugins unable to handle IME events, send the plugin a
3152     // sequence of characters instead.
3153     size_t i = 0;
3154     for (base::i18n::UTF16CharIterator iterator(text); iterator.Advance();) {
3155       blink::WebKeyboardEvent char_event(blink::WebInputEvent::Type::kChar,
3156                                          blink::WebInputEvent::kNoModifiers,
3157                                          ui::EventTimeForNow());
3158       char_event.windows_key_code = text[i];
3159       char_event.native_key_code = text[i];
3160 
3161       for (const size_t char_start = i; i < iterator.array_pos(); ++i) {
3162         char_event.text[i - char_start] = text[i];
3163         char_event.unmodified_text[i - char_start] = text[i];
3164       }
3165 
3166       ui::Cursor dummy_cursor_info;
3167       HandleInputEvent(char_event, &dummy_cursor_info);
3168     }
3169   } else {
3170     // Mimics the order of events sent by blink.
3171     // See blink::Editor::setComposition() for the corresponding code.
3172     HandleCompositionEnd(text);
3173     HandleTextInput(text);
3174   }
3175   composition_text_.clear();
3176 }
3177 
3178 }  // namespace content
3179