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

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

Powered by Google App Engine
This is Rietveld 408576698