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(¤t_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(¤t_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