Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: content/renderer/browser_plugin/browser_plugin.cc

Issue 11826005: Browser Plugin: Implement BrowserPluginObserver. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Clean up bindings API Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/browser_plugin/browser_plugin.h"
6
7 #include "base/json/json_string_value_serializer.h"
8 #include "base/message_loop.h"
9 #include "base/string_number_conversions.h"
10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h"
12 #include "content/common/browser_plugin_messages.h"
13 #include "content/common/view_messages.h"
14 #include "content/public/common/content_client.h"
15 #include "content/public/renderer/content_renderer_client.h"
16 #include "content/renderer/browser_plugin/browser_plugin_bindings.h"
17 #include "content/renderer/browser_plugin/browser_plugin_compositing_helper.h"
18 #include "content/renderer/browser_plugin/browser_plugin_constants.h"
19 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
20 #include "content/renderer/render_process_impl.h"
21 #include "content/renderer/render_thread_impl.h"
22 #include "content/renderer/v8_value_converter_impl.h"
23 #include "skia/ext/platform_canvas.h"
24 #include "third_party/WebKit/Source/Platform/chromium/public/WebRect.h"
25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMCustomEvent.h"
27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
31 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginParams.h"
33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h"
34 #include "webkit/plugins/sad_plugin.h"
35
36 #if defined (OS_WIN)
37 #include "base/sys_info.h"
38 #endif
39
40 using WebKit::WebCanvas;
41 using WebKit::WebPluginContainer;
42 using WebKit::WebPluginParams;
43 using WebKit::WebPoint;
44 using WebKit::WebRect;
45 using WebKit::WebURL;
46 using WebKit::WebVector;
47
48 namespace content {
49
50 namespace {
51
52 static std::string TerminationStatusToString(base::TerminationStatus status) {
53 switch (status) {
54 case base::TERMINATION_STATUS_NORMAL_TERMINATION:
55 return "normal";
56 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
57 return "abnormal";
58 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
59 return "killed";
60 case base::TERMINATION_STATUS_PROCESS_CRASHED:
61 return "crashed";
62 case base::TERMINATION_STATUS_STILL_RUNNING:
63 case base::TERMINATION_STATUS_MAX_ENUM:
64 break;
65 }
66 NOTREACHED() << "Unknown Termination Status.";
67 return "unknown";
68 }
69
70 static std::string GetInternalEventName(const char* event_name) {
71 return base::StringPrintf("-internal-%s", event_name);
72 }
73 } // namespace
74
75 BrowserPlugin::BrowserPlugin(
76 RenderViewImpl* render_view,
77 WebKit::WebFrame* frame,
78 const WebPluginParams& params)
79 : instance_id_(browser_plugin::kInstanceIDNone),
80 render_view_(render_view->AsWeakPtr()),
81 render_view_routing_id_(render_view->GetRoutingID()),
82 container_(NULL),
83 damage_buffer_sequence_id_(0),
84 resize_ack_received_(true),
85 sad_guest_(NULL),
86 guest_crashed_(false),
87 navigate_src_sent_(false),
88 auto_size_ack_pending_(false),
89 guest_process_id_(-1),
90 guest_route_id_(-1),
91 persist_storage_(false),
92 valid_partition_id_(true),
93 content_window_routing_id_(MSG_ROUTING_NONE),
94 plugin_focused_(false),
95 visible_(true),
96 size_changed_in_flight_(false),
97 allocate_instance_id_sent_(false),
98 browser_plugin_manager_(render_view->browser_plugin_manager()),
99 current_nav_entry_index_(0),
100 nav_entry_count_(0),
101 compositing_enabled_(false) {
102 bindings_.reset(new BrowserPluginBindings(this));
103 }
104
105 BrowserPlugin::~BrowserPlugin() {
106 // If the BrowserPlugin has never navigated then the browser process and
107 // BrowserPluginManager don't know about it and so there is nothing to do
108 // here.
109 if (!navigate_src_sent_)
110 return;
111 browser_plugin_manager()->RemoveBrowserPlugin(instance_id_);
112 browser_plugin_manager()->Send(
113 new BrowserPluginHostMsg_PluginDestroyed(render_view_routing_id_,
114 instance_id_));
115 }
116
117 bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
118 bool handled = true;
119 IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
120 IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
121 IPC_MESSAGE_HANDLER(BrowserPluginMsg_BuffersSwapped, OnBuffersSwapped)
122 IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestContentWindowReady,
123 OnGuestContentWindowReady)
124 IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
125 IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestResponsive, OnGuestResponsive)
126 IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestUnresponsive, OnGuestUnresponsive)
127 IPC_MESSAGE_HANDLER(BrowserPluginMsg_LoadAbort, OnLoadAbort)
128 IPC_MESSAGE_HANDLER(BrowserPluginMsg_LoadCommit, OnLoadCommit)
129 IPC_MESSAGE_HANDLER(BrowserPluginMsg_LoadRedirect, OnLoadRedirect)
130 IPC_MESSAGE_HANDLER(BrowserPluginMsg_LoadStart, OnLoadStart)
131 IPC_MESSAGE_HANDLER(BrowserPluginMsg_LoadStop, OnLoadStop)
132 IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
133 IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
134 OnShouldAcceptTouchEvents)
135 IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdatedName, OnUpdatedName)
136 IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdateRect, OnUpdateRect)
137 IPC_MESSAGE_UNHANDLED(handled = false)
138 IPC_END_MESSAGE_MAP()
139 return handled;
140 }
141
142 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
143 const std::string& attribute_value) {
144 if (!container())
145 return;
146
147 WebKit::WebElement element = container()->element();
148 WebKit::WebString web_attribute_name =
149 WebKit::WebString::fromUTF8(attribute_name);
150 if (!HasDOMAttribute(attribute_name) ||
151 (std::string(element.getAttribute(web_attribute_name).utf8()) !=
152 attribute_value)) {
153 element.setAttribute(web_attribute_name,
154 WebKit::WebString::fromUTF8(attribute_value));
155 }
156 }
157
158 void BrowserPlugin::RemoveDOMAttribute(const std::string& attribute_name) {
159 if (!container())
160 return;
161
162 container()->element().removeAttribute(
163 WebKit::WebString::fromUTF8(attribute_name));
164 }
165
166 std::string BrowserPlugin::GetDOMAttributeValue(
167 const std::string& attribute_name) const {
168 if (!container())
169 return "";
170
171 return container()->element().getAttribute(
172 WebKit::WebString::fromUTF8(attribute_name)).utf8();
173 }
174
175 bool BrowserPlugin::HasDOMAttribute(const std::string& attribute_name) const {
176 if (!container())
177 return false;
178
179 return container()->element().hasAttribute(
180 WebKit::WebString::fromUTF8(attribute_name));
181 }
182
183 std::string BrowserPlugin::GetNameAttribute() const {
184 return GetDOMAttributeValue(browser_plugin::kAttributeName);
185 }
186
187 std::string BrowserPlugin::GetSrcAttribute() const {
188 return GetDOMAttributeValue(browser_plugin::kAttributeSrc);
189 }
190
191 bool BrowserPlugin::GetAutoSizeAttribute() const {
192 return HasDOMAttribute(browser_plugin::kAttributeAutoSize);
193 }
194
195 int BrowserPlugin::GetMaxHeightAttribute() const {
196 int max_height;
197 base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxHeight),
198 &max_height);
199 return max_height;
200 }
201
202 int BrowserPlugin::GetMaxWidthAttribute() const {
203 int max_width;
204 base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxWidth),
205 &max_width);
206 return max_width;
207 }
208
209 int BrowserPlugin::GetMinHeightAttribute() const {
210 int min_height;
211 base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinHeight),
212 &min_height);
213 return min_height;
214 }
215
216 int BrowserPlugin::GetMinWidthAttribute() const {
217 int min_width;
218 base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinWidth),
219 &min_width);
220 return min_width;
221 }
222
223 int BrowserPlugin::GetAdjustedMaxHeight() const {
224 int max_height = GetMaxHeightAttribute();
225 return max_height ? max_height : height();
226 }
227
228 int BrowserPlugin::GetAdjustedMaxWidth() const {
229 int max_width = GetMaxWidthAttribute();
230 return max_width ? max_width : width();
231 }
232
233 int BrowserPlugin::GetAdjustedMinHeight() const {
234 int min_height = GetMinHeightAttribute();
235 // FrameView.cpp does not allow this value to be <= 0, so when the value is
236 // unset (or set to 0), we set it to the container size.
237 min_height = min_height ? min_height : height();
238 // For autosize, minHeight should not be bigger than maxHeight.
239 return std::min(min_height, GetAdjustedMaxHeight());
240 }
241
242 int BrowserPlugin::GetAdjustedMinWidth() const {
243 int min_width = GetMinWidthAttribute();
244 // FrameView.cpp does not allow this value to be <= 0, so when the value is
245 // unset (or set to 0), we set it to the container size.
246 min_width = min_width ? min_width : width();
247 // For autosize, minWidth should not be bigger than maxWidth.
248 return std::min(min_width, GetAdjustedMaxWidth());
249 }
250
251 std::string BrowserPlugin::GetPartitionAttribute() const {
252 return GetDOMAttributeValue(browser_plugin::kAttributePartition);
253 }
254
255 void BrowserPlugin::ParseNameAttribute() {
256 if (!navigate_src_sent_)
257 return;
258 browser_plugin_manager()->Send(
259 new BrowserPluginHostMsg_SetName(render_view_routing_id_,
260 instance_id_,
261 GetNameAttribute()));
262 }
263
264 bool BrowserPlugin::ParseSrcAttribute(std::string* error_message) {
265 if (!valid_partition_id_) {
266 *error_message = browser_plugin::kErrorInvalidPartition;
267 return false;
268 }
269 std::string src = GetSrcAttribute();
270 if (src.empty())
271 return true;
272
273 // If we haven't created the guest yet, do so now. We will navigate it right
274 // after creation. If |src| is empty, we can delay the creation until we
275 // actually need it.
276 if (!navigate_src_sent_) {
277 // On initial navigation, we request an instance ID from the browser
278 // process. We essentially ignore all subsequent calls to SetSrcAttribute
279 // until we receive an instance ID. |allocate_instance_id_sent_|
280 // prevents BrowserPlugin from allocating more than one instance ID.
281 // Upon receiving an instance ID from the browser process, we continue
282 // the process of navigation by populating the
283 // BrowserPluginHostMsg_CreateGuest_Params with the current state of
284 // BrowserPlugin and sending a BrowserPluginHostMsg_CreateGuest to the
285 // browser process in order to create a new guest.
286 if (!allocate_instance_id_sent_) {
287 browser_plugin_manager()->AllocateInstanceID(this);
288 allocate_instance_id_sent_ = true;
289 }
290 return true;
291 }
292
293 browser_plugin_manager()->Send(
294 new BrowserPluginHostMsg_NavigateGuest(render_view_routing_id_,
295 instance_id_,
296 src));
297 return true;
298 }
299
300 void BrowserPlugin::ParseAutoSizeAttribute() {
301 auto_size_ack_pending_ = true;
302 last_view_size_ = plugin_rect_.size();
303 UpdateGuestAutoSizeState(GetAutoSizeAttribute());
304 }
305
306 void BrowserPlugin::PopulateAutoSizeParameters(
307 BrowserPluginHostMsg_AutoSize_Params* params, bool current_auto_size) {
308 params->enable = current_auto_size;
309 // No need to populate the params if autosize is off.
310 if (current_auto_size) {
311 params->max_size = gfx::Size(GetAdjustedMaxWidth(), GetAdjustedMaxHeight());
312 params->min_size = gfx::Size(GetAdjustedMinWidth(), GetAdjustedMinHeight());
313 }
314 }
315
316 void BrowserPlugin::UpdateGuestAutoSizeState(bool current_auto_size) {
317 // If we haven't yet heard back from the guest about the last resize request,
318 // then we don't issue another request until we do in
319 // BrowserPlugin::UpdateRect.
320 if (!navigate_src_sent_ || !resize_ack_received_)
321 return;
322 BrowserPluginHostMsg_AutoSize_Params auto_size_params;
323 BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
324 if (current_auto_size) {
325 GetDamageBufferWithSizeParams(&auto_size_params, &resize_guest_params);
326 } else {
327 GetDamageBufferWithSizeParams(NULL, &resize_guest_params);
328 }
329 resize_ack_received_ = false;
330 browser_plugin_manager()->Send(
331 new BrowserPluginHostMsg_SetAutoSize(render_view_routing_id_,
332 instance_id_,
333 auto_size_params,
334 resize_guest_params));
335 }
336
337 void BrowserPlugin::SizeChangedDueToAutoSize(const gfx::Size& old_view_size) {
338 size_changed_in_flight_ = false;
339
340 std::map<std::string, base::Value*> props;
341 props[browser_plugin::kOldHeight] =
342 new base::FundamentalValue(old_view_size.height());
343 props[browser_plugin::kOldWidth] =
344 new base::FundamentalValue(old_view_size.width());
345 props[browser_plugin::kNewHeight] =
346 new base::FundamentalValue(last_view_size_.height());
347 props[browser_plugin::kNewWidth] =
348 new base::FundamentalValue(last_view_size_.width());
349 TriggerEvent(browser_plugin::kEventSizeChanged, &props);
350 }
351
352 // static
353 bool BrowserPlugin::UsesDamageBuffer(
354 const BrowserPluginMsg_UpdateRect_Params& params) {
355 return params.damage_buffer_sequence_id != 0 || params.needs_ack;
356 }
357
358 bool BrowserPlugin::UsesPendingDamageBuffer(
359 const BrowserPluginMsg_UpdateRect_Params& params) {
360 if (!pending_damage_buffer_.get())
361 return false;
362 return damage_buffer_sequence_id_ == params.damage_buffer_sequence_id;
363 }
364
365 void BrowserPlugin::SetInstanceID(int instance_id) {
366 CHECK(instance_id != browser_plugin::kInstanceIDNone);
367 instance_id_ = instance_id;
368 browser_plugin_manager()->AddBrowserPlugin(instance_id, this);
369
370 BrowserPluginHostMsg_CreateGuest_Params create_guest_params;
371 create_guest_params.storage_partition_id = storage_partition_id_;
372 create_guest_params.persist_storage = persist_storage_;
373 create_guest_params.focused = ShouldGuestBeFocused();
374 create_guest_params.visible = visible_;
375 create_guest_params.name = GetNameAttribute();
376 create_guest_params.src = GetSrcAttribute();
377 GetDamageBufferWithSizeParams(&create_guest_params.auto_size_params,
378 &create_guest_params.resize_guest_params);
379 browser_plugin_manager()->Send(
380 new BrowserPluginHostMsg_CreateGuest(render_view_routing_id_,
381 instance_id_,
382 create_guest_params));
383
384 // Record that we sent a navigation request to the browser process.
385 // Once this instance has navigated, the storage partition cannot be changed,
386 // so this value is used for enforcing this.
387 navigate_src_sent_ = true;
388 }
389
390 void BrowserPlugin::OnAdvanceFocus(int instance_id, bool reverse) {
391 DCHECK(render_view_);
392 render_view_->GetWebView()->advanceFocus(reverse);
393 }
394
395 void BrowserPlugin::OnBuffersSwapped(int instance_id,
396 const gfx::Size& size,
397 std::string mailbox_name,
398 int gpu_route_id,
399 int gpu_host_id) {
400 DCHECK(instance_id == instance_id_);
401 EnableCompositing(true);
402
403 compositing_helper_->OnBuffersSwapped(size,
404 mailbox_name,
405 gpu_route_id,
406 gpu_host_id);
407 }
408
409 void BrowserPlugin::OnGuestContentWindowReady(int instance_id,
410 int content_window_routing_id) {
411 DCHECK(content_window_routing_id != MSG_ROUTING_NONE);
412 content_window_routing_id_ = content_window_routing_id;
413 }
414
415 void BrowserPlugin::OnGuestGone(int instance_id, int process_id, int status) {
416 // Set the BrowserPlugin in a crashed state before firing event listeners so
417 // that operations on the BrowserPlugin within listeners are aware that
418 // BrowserPlugin is in a crashed state.
419 guest_crashed_ = true;
420
421 // We fire the event listeners before painting the sad graphic to give the
422 // developer an opportunity to display an alternative overlay image on crash.
423 std::string termination_status = TerminationStatusToString(
424 static_cast<base::TerminationStatus>(status));
425 std::map<std::string, base::Value*> props;
426 props[browser_plugin::kProcessId] = new base::FundamentalValue(process_id);
427 props[browser_plugin::kReason] = new base::StringValue(termination_status);
428
429 // Event listeners may remove the BrowserPlugin from the document. If that
430 // happens, the BrowserPlugin will be scheduled for later deletion (see
431 // BrowserPlugin::destroy()). That will clear the container_ reference,
432 // but leave other member variables valid below.
433 TriggerEvent(browser_plugin::kEventExit, &props);
434
435 // We won't paint the contents of the current backing store again so we might
436 // as well toss it out and save memory.
437 backing_store_.reset();
438 // If the BrowserPlugin is scheduled to be deleted, then container_ will be
439 // NULL so we shouldn't attempt to access it.
440 if (container_)
441 container_->invalidate();
442 // Turn off compositing so we can display the sad graphic.
443 EnableCompositing(false);
444 }
445
446 void BrowserPlugin::OnGuestResponsive(int instance_id, int process_id) {
447 std::map<std::string, base::Value*> props;
448 props[browser_plugin::kProcessId] = new base::FundamentalValue(process_id);
449 TriggerEvent(browser_plugin::kEventResponsive, &props);
450 }
451
452 void BrowserPlugin::OnGuestUnresponsive(int instance_id, int process_id) {
453 std::map<std::string, base::Value*> props;
454 props[browser_plugin::kProcessId] = new base::FundamentalValue(process_id);
455 TriggerEvent(browser_plugin::kEventUnresponsive, &props);
456 }
457
458 void BrowserPlugin::OnLoadAbort(int instance_id,
459 const GURL& url,
460 bool is_top_level,
461 const std::string& type) {
462 std::map<std::string, base::Value*> props;
463 props[browser_plugin::kURL] = new base::StringValue(url.spec());
464 props[browser_plugin::kIsTopLevel] = new base::FundamentalValue(is_top_level);
465 props[browser_plugin::kReason] = new base::StringValue(type);
466 TriggerEvent(browser_plugin::kEventLoadAbort, &props);
467 }
468
469 void BrowserPlugin::OnLoadCommit(
470 int instance_id,
471 const BrowserPluginMsg_LoadCommit_Params& params) {
472 // If the guest has just committed a new navigation then it is no longer
473 // crashed.
474 guest_crashed_ = false;
475 if (params.is_top_level)
476 UpdateDOMAttribute(browser_plugin::kAttributeSrc, params.url.spec());
477
478 guest_process_id_ = params.process_id;
479 guest_route_id_ = params.route_id;
480 current_nav_entry_index_ = params.current_entry_index;
481 nav_entry_count_ = params.entry_count;
482
483 std::map<std::string, base::Value*> props;
484 props[browser_plugin::kURL] = new base::StringValue(params.url.spec());
485 props[browser_plugin::kIsTopLevel] =
486 new base::FundamentalValue(params.is_top_level);
487 TriggerEvent(browser_plugin::kEventLoadCommit, &props);
488 }
489
490 void BrowserPlugin::OnLoadRedirect(int instance_id,
491 const GURL& old_url,
492 const GURL& new_url,
493 bool is_top_level) {
494 std::map<std::string, base::Value*> props;
495 props[browser_plugin::kOldURL] = new base::StringValue(old_url.spec());
496 props[browser_plugin::kNewURL] = new base::StringValue(new_url.spec());
497 props[browser_plugin::kIsTopLevel] = new base::FundamentalValue(is_top_level);
498 TriggerEvent(browser_plugin::kEventLoadRedirect, &props);
499 }
500
501 void BrowserPlugin::OnLoadStart(int instance_id,
502 const GURL& url,
503 bool is_top_level) {
504 std::map<std::string, base::Value*> props;
505 props[browser_plugin::kURL] = new base::StringValue(url.spec());
506 props[browser_plugin::kIsTopLevel] = new base::FundamentalValue(is_top_level);
507
508 TriggerEvent(browser_plugin::kEventLoadStart, &props);
509 }
510
511 void BrowserPlugin::OnLoadStop(int instance_id) {
512 TriggerEvent(browser_plugin::kEventLoadStop, NULL);
513 }
514
515 void BrowserPlugin::OnSetCursor(int instance_id, const WebCursor& cursor) {
516 cursor_ = cursor;
517 }
518
519 void BrowserPlugin::OnShouldAcceptTouchEvents(int instance_id, bool accept) {
520 if (container()) {
521 container()->requestTouchEventType(accept ?
522 WebKit::WebPluginContainer::TouchEventRequestTypeRaw :
523 WebKit::WebPluginContainer::TouchEventRequestTypeNone);
524 }
525 }
526
527 void BrowserPlugin::OnUpdatedName(int instance_id, const std::string& name) {
528 UpdateDOMAttribute(browser_plugin::kAttributeName, name);
529 }
530
531 void BrowserPlugin::OnUpdateRect(
532 int instance_id,
533 const BrowserPluginMsg_UpdateRect_Params& params) {
534 bool use_new_damage_buffer = !backing_store_;
535 BrowserPluginHostMsg_AutoSize_Params auto_size_params;
536 BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
537 // If we have a pending damage buffer, and the guest has begun to use the
538 // damage buffer then we know the guest will no longer use the current
539 // damage buffer. At this point, we drop the current damage buffer, and
540 // mark the pending damage buffer as the current damage buffer.
541 if (UsesPendingDamageBuffer(params)) {
542 SwapDamageBuffers();
543 use_new_damage_buffer = true;
544 }
545
546 bool auto_size = GetAutoSizeAttribute();
547 // We receive a resize ACK in regular mode, but not in autosize.
548 // In SW, |resize_ack_received_| is reset in SwapDamageBuffers().
549 // In HW mode, we need to do it here so we can continue sending
550 // resize messages when needed.
551 if (params.is_resize_ack ||
552 (!params.needs_ack && (auto_size || auto_size_ack_pending_)))
553 resize_ack_received_ = true;
554
555 auto_size_ack_pending_ = false;
556
557 if ((!auto_size && (width() != params.view_size.width() ||
558 height() != params.view_size.height())) ||
559 (auto_size && (!InAutoSizeBounds(params.view_size)))) {
560 // We are HW accelerated, render widget does not expect an ack,
561 // but we still need to update the size.
562 if (!params.needs_ack) {
563 UpdateGuestAutoSizeState(auto_size);
564 return;
565 }
566
567 if (!resize_ack_received_) {
568 // The guest has not yet responded to the last resize request, and
569 // so we don't want to do anything at this point other than ACK the guest.
570 if (auto_size)
571 PopulateAutoSizeParameters(&auto_size_params, auto_size);
572 } else {
573 // If we have no pending damage buffer, then the guest has not caught up
574 // with the BrowserPlugin container. We now tell the guest about the new
575 // container size.
576 if (auto_size) {
577 GetDamageBufferWithSizeParams(&auto_size_params,
578 &resize_guest_params);
579 } else {
580 GetDamageBufferWithSizeParams(NULL, &resize_guest_params);
581 }
582 }
583 browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateRect_ACK(
584 render_view_routing_id_,
585 instance_id_,
586 auto_size_params,
587 resize_guest_params));
588 return;
589 }
590
591 if (auto_size && (params.view_size != last_view_size_)) {
592 if (backing_store_)
593 backing_store_->Clear(SK_ColorWHITE);
594 gfx::Size old_view_size = last_view_size_;
595 last_view_size_ = params.view_size;
596 // Schedule a SizeChanged instead of calling it directly to ensure that
597 // the backing store has been updated before the developer attempts to
598 // resize to avoid flicker. |size_changed_in_flight_| acts as a form of
599 // flow control for SizeChanged events. If the guest's view size is changing
600 // rapidly before a SizeChanged event fires, then we avoid scheduling
601 // another SizeChanged event. SizeChanged reads the new size from
602 // |last_view_size_| so we can be sure that it always fires an event
603 // with the last seen view size.
604 if (container_ && !size_changed_in_flight_) {
605 size_changed_in_flight_ = true;
606 MessageLoop::current()->PostTask(
607 FROM_HERE,
608 base::Bind(&BrowserPlugin::SizeChangedDueToAutoSize,
609 base::Unretained(this),
610 old_view_size));
611 }
612 }
613
614 // No more work to do since the guest is no longer using a damage buffer.
615 if (!UsesDamageBuffer(params))
616 return;
617
618 // If we are seeing damage buffers, HW compositing should be turned off.
619 EnableCompositing(false);
620
621 // If we are now using a new damage buffer, then that means that the guest
622 // has updated its size state in response to a resize request. We change
623 // the backing store's size to accomodate the new damage buffer size.
624 if (use_new_damage_buffer) {
625 int backing_store_width = auto_size ? GetAdjustedMaxWidth() : width();
626 int backing_store_height = auto_size ? GetAdjustedMaxHeight(): height();
627 backing_store_.reset(
628 new BrowserPluginBackingStore(
629 gfx::Size(backing_store_width, backing_store_height),
630 params.scale_factor));
631 }
632
633 // Update the backing store.
634 if (!params.scroll_rect.IsEmpty()) {
635 backing_store_->ScrollBackingStore(params.scroll_delta,
636 params.scroll_rect,
637 params.view_size);
638 }
639 for (unsigned i = 0; i < params.copy_rects.size(); i++) {
640 backing_store_->PaintToBackingStore(params.bitmap_rect,
641 params.copy_rects,
642 current_damage_buffer_->memory());
643 }
644
645 // Invalidate the container.
646 // If the BrowserPlugin is scheduled to be deleted, then container_ will be
647 // NULL so we shouldn't attempt to access it.
648 if (container_)
649 container_->invalidate();
650 if (auto_size)
651 PopulateAutoSizeParameters(&auto_size_params, auto_size);
652 browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateRect_ACK(
653 render_view_routing_id_,
654 instance_id_,
655 auto_size_params,
656 resize_guest_params));
657 }
658
659 void BrowserPlugin::ParseSizeContraintsChanged() {
660 bool auto_size = GetAutoSizeAttribute();
661 if (auto_size)
662 UpdateGuestAutoSizeState(true);
663 }
664
665 bool BrowserPlugin::InAutoSizeBounds(const gfx::Size& size) const {
666 return size.width() <= GetAdjustedMaxWidth() &&
667 size.height() <= GetAdjustedMaxHeight();
668 }
669
670 NPObject* BrowserPlugin::GetContentWindow() const {
671 if (content_window_routing_id_ == MSG_ROUTING_NONE)
672 return NULL;
673 RenderViewImpl* guest_render_view = static_cast<RenderViewImpl*>(
674 ChildThread::current()->ResolveRoute(content_window_routing_id_));
675 if (!guest_render_view)
676 return NULL;
677 WebKit::WebFrame* guest_frame = guest_render_view->GetWebView()->mainFrame();
678 return guest_frame->windowObject();
679 }
680
681 bool BrowserPlugin::CanGoBack() const {
682 return nav_entry_count_ > 1 && current_nav_entry_index_ > 0;
683 }
684
685 bool BrowserPlugin::CanGoForward() const {
686 return current_nav_entry_index_ >= 0 &&
687 current_nav_entry_index_ < (nav_entry_count_ - 1);
688 }
689
690 bool BrowserPlugin::ParsePartitionAttribute(std::string* error_message) {
691 if (allocate_instance_id_sent_) {
692 *error_message = browser_plugin::kErrorAlreadyNavigated;
693 return false;
694 }
695
696 std::string input = GetPartitionAttribute();
697
698 // Since the "persist:" prefix is in ASCII, StartsWith will work fine on
699 // UTF-8 encoded |partition_id|. If the prefix is a match, we can safely
700 // remove the prefix without splicing in the middle of a multi-byte codepoint.
701 // We can use the rest of the string as UTF-8 encoded one.
702 if (StartsWithASCII(input, browser_plugin::kPersistPrefix, true)) {
703 size_t index = input.find(":");
704 CHECK(index != std::string::npos);
705 // It is safe to do index + 1, since we tested for the full prefix above.
706 input = input.substr(index + 1);
707 if (input.empty()) {
708 valid_partition_id_ = false;
709 *error_message = browser_plugin::kErrorInvalidPartition;
710 return false;
711 }
712 persist_storage_ = true;
713 } else {
714 persist_storage_ = false;
715 }
716
717 valid_partition_id_ = true;
718 storage_partition_id_ = input;
719 return true;
720 }
721
722 bool BrowserPlugin::CanRemovePartitionAttribute(std::string* error_message) {
723 if (navigate_src_sent_)
724 *error_message = browser_plugin::kErrorCannotRemovePartition;
725 return !navigate_src_sent_;
726 }
727
728 void BrowserPlugin::ParseAttributes() {
729 // TODO(mthiesse): Handle errors here?
730 std::string error;
731 ParsePartitionAttribute(&error);
732
733 // Parse the 'src' attribute last, as it will set the has_navigated_ flag to
734 // true, which prevents changing the 'partition' attribute.
735 ParseSrcAttribute(&error);
736 }
737
738 float BrowserPlugin::GetDeviceScaleFactor() const {
739 if (!render_view_)
740 return 1.0f;
741 return render_view_->GetWebView()->deviceScaleFactor();
742 }
743
744 void BrowserPlugin::TriggerEvent(const std::string& event_name,
745 std::map<std::string, base::Value*>* props) {
746 if (!container() || !container()->element().document().frame())
747 return;
748 v8::HandleScope handle_scope;
749 std::string json_string;
750 if (props) {
751 base::DictionaryValue dict;
752 for (std::map<std::string, base::Value*>::iterator iter = props->begin(),
753 end = props->end(); iter != end; ++iter) {
754 dict.Set(iter->first, iter->second);
755 }
756
757 JSONStringValueSerializer serializer(&json_string);
758 if (!serializer.Serialize(dict))
759 return;
760 }
761
762 WebKit::WebFrame* frame = container()->element().document().frame();
763 WebKit::WebDOMEvent dom_event = frame->document().createEvent("CustomEvent");
764 WebKit::WebDOMCustomEvent event = dom_event.to<WebKit::WebDOMCustomEvent>();
765
766 // The events triggered directly from the plugin <object> are internal events
767 // whose implementation details can (and likely will) change over time. The
768 // wrapper/shim (e.g. <webview> tag) should receive these events, and expose a
769 // more appropriate (and stable) event to the consumers as part of the API.
770 event.initCustomEvent(
771 WebKit::WebString::fromUTF8(GetInternalEventName(event_name.c_str())),
772 false, false,
773 WebKit::WebSerializedScriptValue::serialize(
774 v8::String::New(json_string.c_str(), json_string.size())));
775 container()->element().dispatchEvent(event);
776 }
777
778 void BrowserPlugin::Back() {
779 if (!navigate_src_sent_)
780 return;
781 browser_plugin_manager()->Send(
782 new BrowserPluginHostMsg_Go(render_view_routing_id_,
783 instance_id_, -1));
784 }
785
786 void BrowserPlugin::Forward() {
787 if (!navigate_src_sent_)
788 return;
789 browser_plugin_manager()->Send(
790 new BrowserPluginHostMsg_Go(render_view_routing_id_,
791 instance_id_, 1));
792 }
793
794 void BrowserPlugin::Go(int relative_index) {
795 if (!navigate_src_sent_)
796 return;
797 browser_plugin_manager()->Send(
798 new BrowserPluginHostMsg_Go(render_view_routing_id_,
799 instance_id_,
800 relative_index));
801 }
802
803 void BrowserPlugin::TerminateGuest() {
804 if (!navigate_src_sent_ || guest_crashed_)
805 return;
806 browser_plugin_manager()->Send(
807 new BrowserPluginHostMsg_TerminateGuest(render_view_routing_id_,
808 instance_id_));
809 }
810
811 void BrowserPlugin::Stop() {
812 if (!navigate_src_sent_)
813 return;
814 browser_plugin_manager()->Send(
815 new BrowserPluginHostMsg_Stop(render_view_routing_id_,
816 instance_id_));
817 }
818
819 void BrowserPlugin::Reload() {
820 if (!navigate_src_sent_)
821 return;
822 browser_plugin_manager()->Send(
823 new BrowserPluginHostMsg_Reload(render_view_routing_id_,
824 instance_id_));
825 }
826
827 void BrowserPlugin::UpdateGuestFocusState() {
828 if (!navigate_src_sent_)
829 return;
830 bool should_be_focused = ShouldGuestBeFocused();
831 browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
832 render_view_routing_id_,
833 instance_id_,
834 should_be_focused));
835 }
836
837 bool BrowserPlugin::ShouldGuestBeFocused() const {
838 bool embedder_focused = false;
839 if (render_view_)
840 embedder_focused = render_view_->has_focus();
841 return plugin_focused_ && embedder_focused;
842 }
843
844 WebKit::WebPluginContainer* BrowserPlugin::container() const {
845 return container_;
846 }
847
848 bool BrowserPlugin::initialize(WebPluginContainer* container) {
849 container_ = container;
850 container_->setWantsWheelEvents(true);
851 ParseAttributes();
852 return true;
853 }
854
855 void BrowserPlugin::EnableCompositing(bool enable) {
856 if (compositing_enabled_ == enable)
857 return;
858
859 compositing_enabled_ = enable;
860 if (enable) {
861 // No need to keep the backing store and damage buffer around if we're now
862 // compositing.
863 backing_store_.reset();
864 current_damage_buffer_.reset();
865 if (!compositing_helper_) {
866 compositing_helper_ = new BrowserPluginCompositingHelper(
867 container_,
868 browser_plugin_manager(),
869 instance_id_,
870 render_view_routing_id_);
871 }
872 } else {
873 // We're switching back to the software path. We create a new damage
874 // buffer that can accommodate the current size of the container.
875 BrowserPluginHostMsg_ResizeGuest_Params params;
876 PopulateResizeGuestParameters(&params, gfx::Size(width(), height()));
877 // Request a full repaint from the guest even if its size is not actually
878 // changing.
879 params.repaint = true;
880 resize_ack_received_ = false;
881 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
882 render_view_routing_id_,
883 instance_id_,
884 params));
885 }
886 compositing_helper_->EnableCompositing(enable);
887 }
888
889 void BrowserPlugin::destroy() {
890 // The BrowserPlugin's WebPluginContainer is deleted immediately after this
891 // call returns, so let's not keep a reference to it around.
892 container_ = NULL;
893 if (compositing_helper_)
894 compositing_helper_->OnContainerDestroy();
895 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
896 }
897
898 NPObject* BrowserPlugin::scriptableObject() {
899 NPObject* browser_plugin_np_object(bindings_->np_object());
900 // The object is expected to be retained before it is returned.
901 WebKit::WebBindings::retainObject(browser_plugin_np_object);
902 return browser_plugin_np_object;
903 }
904
905 bool BrowserPlugin::supportsKeyboardFocus() const {
906 return true;
907 }
908
909 bool BrowserPlugin::canProcessDrag() const {
910 return true;
911 }
912
913 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
914 if (guest_crashed_) {
915 if (!sad_guest_) // Lazily initialize bitmap.
916 sad_guest_ = content::GetContentClient()->renderer()->
917 GetSadWebViewBitmap();
918 // content_shell does not have the sad plugin bitmap, so we'll paint black
919 // instead to make it clear that something went wrong.
920 if (sad_guest_) {
921 webkit::PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
922 return;
923 }
924 }
925 SkAutoCanvasRestore auto_restore(canvas, true);
926 canvas->translate(plugin_rect_.x(), plugin_rect_.y());
927 SkRect image_data_rect = SkRect::MakeXYWH(
928 SkIntToScalar(0),
929 SkIntToScalar(0),
930 SkIntToScalar(plugin_rect_.width()),
931 SkIntToScalar(plugin_rect_.height()));
932 canvas->clipRect(image_data_rect);
933 // Paint black or white in case we have nothing in our backing store or we
934 // need to show a gutter.
935 SkPaint paint;
936 paint.setStyle(SkPaint::kFill_Style);
937 paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
938 canvas->drawRect(image_data_rect, paint);
939 // Stay a solid color if we have never set a non-empty src, or we don't have a
940 // backing store.
941 if (!backing_store_.get() || !navigate_src_sent_)
942 return;
943 float inverse_scale_factor = 1.0f / backing_store_->GetScaleFactor();
944 canvas->scale(inverse_scale_factor, inverse_scale_factor);
945 canvas->drawBitmap(backing_store_->GetBitmap(), 0, 0);
946 }
947
948 bool BrowserPlugin::InBounds(const gfx::Point& position) const {
949 // Note that even for plugins that are rotated using rotate transformations,
950 // we use the the |plugin_rect_| provided by updateGeometry, which means we
951 // will be off if |position| is within the plugin rect but does not fall
952 // within the actual plugin boundary. Not supporting such edge case is OK
953 // since this function should not be used for making security-sensitive
954 // decisions.
955 // This also does not take overlapping plugins into account.
956 bool result = position.x() >= plugin_rect_.x() &&
957 position.x() < plugin_rect_.x() + plugin_rect_.width() &&
958 position.y() >= plugin_rect_.y() &&
959 position.y() < plugin_rect_.y() + plugin_rect_.height();
960 return result;
961 }
962
963 gfx::Point BrowserPlugin::ToLocalCoordinates(const gfx::Point& point) const {
964 if (container_)
965 return container_->windowToLocalPoint(WebKit::WebPoint(point));
966 return gfx::Point(point.x() - plugin_rect_.x(), point.y() - plugin_rect_.y());
967 }
968
969 void BrowserPlugin::updateGeometry(
970 const WebRect& window_rect,
971 const WebRect& clip_rect,
972 const WebVector<WebRect>& cut_outs_rects,
973 bool is_visible) {
974 int old_width = width();
975 int old_height = height();
976 plugin_rect_ = window_rect;
977 // In AutoSize mode, guests don't care when the BrowserPlugin container is
978 // resized. If |!resize_ack_received_|, then we are still waiting on a
979 // previous resize to be ACK'ed and so we don't issue additional resizes
980 // until the previous one is ACK'ed.
981 // TODO(mthiesse): Assess the performance of calling GetAutoSizeAttribute() on
982 // resize.
983 if (!navigate_src_sent_ ||
984 !resize_ack_received_ ||
985 (old_width == window_rect.width && old_height == window_rect.height) ||
986 GetAutoSizeAttribute()) {
987 return;
988 }
989
990 BrowserPluginHostMsg_ResizeGuest_Params params;
991 PopulateResizeGuestParameters(&params, gfx::Size(width(), height()));
992 resize_ack_received_ = false;
993 browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
994 render_view_routing_id_,
995 instance_id_,
996 params));
997 }
998
999 void BrowserPlugin::SwapDamageBuffers() {
1000 current_damage_buffer_.reset(pending_damage_buffer_.release());
1001 resize_ack_received_ = true;
1002 }
1003
1004 void BrowserPlugin::PopulateResizeGuestParameters(
1005 BrowserPluginHostMsg_ResizeGuest_Params* params,
1006 const gfx::Size& view_size) {
1007 params->view_size = view_size;
1008 params->scale_factor = GetDeviceScaleFactor();
1009
1010 // In HW compositing mode, we do not need a damage buffer.
1011 if (compositing_enabled_)
1012 return;
1013
1014 const size_t stride = skia::PlatformCanvasStrideForWidth(view_size.width());
1015 // Make sure the size of the damage buffer is at least four bytes so that we
1016 // can fit in a magic word to verify that the memory is shared correctly.
1017 size_t size =
1018 std::max(sizeof(unsigned int),
1019 static_cast<size_t>(view_size.height() *
1020 stride *
1021 GetDeviceScaleFactor() *
1022 GetDeviceScaleFactor()));
1023
1024 params->damage_buffer_size = size;
1025 pending_damage_buffer_.reset(
1026 CreateDamageBuffer(size, &params->damage_buffer_handle));
1027 if (!pending_damage_buffer_.get())
1028 NOTREACHED();
1029 params->damage_buffer_sequence_id = ++damage_buffer_sequence_id_;
1030 }
1031
1032 void BrowserPlugin::GetDamageBufferWithSizeParams(
1033 BrowserPluginHostMsg_AutoSize_Params* auto_size_params,
1034 BrowserPluginHostMsg_ResizeGuest_Params* resize_guest_params) {
1035 if (auto_size_params)
1036 PopulateAutoSizeParameters(auto_size_params, GetAutoSizeAttribute());
1037 gfx::Size view_size = (auto_size_params && auto_size_params->enable) ?
1038 auto_size_params->max_size : gfx::Size(width(), height());
1039 if (view_size.IsEmpty())
1040 return;
1041 resize_ack_received_ = false;
1042 PopulateResizeGuestParameters(resize_guest_params, view_size);
1043 }
1044
1045 #if defined(OS_POSIX)
1046 base::SharedMemory* BrowserPlugin::CreateDamageBuffer(
1047 const size_t size,
1048 base::SharedMemoryHandle* damage_buffer_handle) {
1049 scoped_ptr<base::SharedMemory> shared_buf(
1050 content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
1051 size).release());
1052
1053 if (shared_buf.get()) {
1054 if (shared_buf->Map(size)) {
1055 // Insert the magic word.
1056 *static_cast<unsigned int*>(shared_buf->memory()) = 0xdeadbeef;
1057 shared_buf->ShareToProcess(base::GetCurrentProcessHandle(),
1058 damage_buffer_handle);
1059 return shared_buf.release();
1060 }
1061 }
1062 NOTREACHED();
1063 return NULL;
1064 }
1065 #elif defined(OS_WIN)
1066 base::SharedMemory* BrowserPlugin::CreateDamageBuffer(
1067 const size_t size,
1068 base::SharedMemoryHandle* damage_buffer_handle) {
1069 scoped_ptr<base::SharedMemory> shared_buf(new base::SharedMemory());
1070
1071 if (!shared_buf->CreateAndMapAnonymous(size)) {
1072 NOTREACHED() << "Buffer allocation failed";
1073 return NULL;
1074 }
1075
1076 // Insert the magic word.
1077 *static_cast<unsigned int*>(shared_buf->memory()) = 0xdeadbeef;
1078 if (shared_buf->ShareToProcess(base::GetCurrentProcessHandle(),
1079 damage_buffer_handle))
1080 return shared_buf.release();
1081 NOTREACHED();
1082 return NULL;
1083 }
1084 #endif
1085
1086 void BrowserPlugin::updateFocus(bool focused) {
1087 if (plugin_focused_ == focused)
1088 return;
1089
1090 bool old_guest_focus_state = ShouldGuestBeFocused();
1091 plugin_focused_ = focused;
1092
1093 if (ShouldGuestBeFocused() != old_guest_focus_state)
1094 UpdateGuestFocusState();
1095 }
1096
1097 void BrowserPlugin::updateVisibility(bool visible) {
1098 if (visible_ == visible)
1099 return;
1100
1101 visible_ = visible;
1102 if (!navigate_src_sent_)
1103 return;
1104
1105 if (compositing_helper_)
1106 compositing_helper_->UpdateVisibility(visible);
1107
1108 browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
1109 render_view_routing_id_,
1110 instance_id_,
1111 visible));
1112 }
1113
1114 bool BrowserPlugin::acceptsInputEvents() {
1115 return true;
1116 }
1117
1118 bool BrowserPlugin::handleInputEvent(const WebKit::WebInputEvent& event,
1119 WebKit::WebCursorInfo& cursor_info) {
1120 if (guest_crashed_ || !navigate_src_sent_ ||
1121 event.type == WebKit::WebInputEvent::ContextMenu)
1122 return false;
1123 browser_plugin_manager()->Send(
1124 new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
1125 instance_id_,
1126 plugin_rect_,
1127 &event));
1128 cursor_.GetCursorInfo(&cursor_info);
1129 return true;
1130 }
1131
1132 bool BrowserPlugin::handleDragStatusUpdate(WebKit::WebDragStatus drag_status,
1133 const WebKit::WebDragData& drag_data,
1134 WebKit::WebDragOperationsMask mask,
1135 const WebKit::WebPoint& position,
1136 const WebKit::WebPoint& screen) {
1137 if (guest_crashed_ || !navigate_src_sent_)
1138 return false;
1139 browser_plugin_manager()->Send(
1140 new BrowserPluginHostMsg_DragStatusUpdate(
1141 render_view_routing_id_,
1142 instance_id_,
1143 drag_status,
1144 WebDropData(drag_data),
1145 mask,
1146 position));
1147 return false;
1148 }
1149
1150 void BrowserPlugin::didReceiveResponse(
1151 const WebKit::WebURLResponse& response) {
1152 }
1153
1154 void BrowserPlugin::didReceiveData(const char* data, int data_length) {
1155 }
1156
1157 void BrowserPlugin::didFinishLoading() {
1158 }
1159
1160 void BrowserPlugin::didFailLoading(const WebKit::WebURLError& error) {
1161 }
1162
1163 void BrowserPlugin::didFinishLoadingFrameRequest(const WebKit::WebURL& url,
1164 void* notify_data) {
1165 }
1166
1167 void BrowserPlugin::didFailLoadingFrameRequest(
1168 const WebKit::WebURL& url,
1169 void* notify_data,
1170 const WebKit::WebURLError& error) {
1171 }
1172
1173 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698