Implementation of Appcontrol functionalities
[platform/framework/web/crosswalk-tizen.git] / atom / browser / api / atom_api_web_contents.cc
1 // Copyright (c) 2014 GitHub, Inc.
2 // Use of this source code is governed by the MIT license that can be
3 // found in the LICENSE file.
4
5 #include "atom/browser/api/atom_api_web_contents.h"
6
7 #include <Eina.h>
8 #include <set>
9 #include <string>
10
11 #include "atom/browser/api/atom_api_debugger.h"
12 #include "atom/browser/api/atom_api_session.h"
13 #include "atom/browser/api/atom_api_window.h"
14 #include "atom/browser/atom_browser_client.h"
15 #include "atom/browser/atom_browser_context.h"
16 #include "atom/browser/atom_browser_main_parts.h"
17 #include "atom/browser/browser.h"
18 #include "atom/browser/lib/bluetooth_chooser.h"
19 #include "atom/browser/native_window.h"
20 #include "atom/browser/net/atom_network_delegate.h"
21 #include "atom/browser/osr/osr_output_device.h"
22 #include "atom/browser/osr/osr_render_widget_host_view.h"
23 #include "atom/browser/osr/osr_web_contents_view.h"
24 #include "atom/browser/ui/drag_util.h"
25 #include "atom/browser/web_contents_permission_helper.h"
26 #include "atom/browser/web_contents_preferences.h"
27 #include "atom/browser/web_contents_zoom_controller.h"
28 #include "atom/browser/web_view_guest_delegate.h"
29 #include "atom/common/api/api_messages.h"
30 #include "atom/common/api/event_emitter_caller.h"
31 #include "atom/common/color_util.h"
32 #include "atom/common/mouse_util.h"
33 #include "atom/common/native_mate_converters/blink_converter.h"
34 #include "atom/common/native_mate_converters/callback.h"
35 #include "atom/common/native_mate_converters/content_converter.h"
36 #include "atom/common/native_mate_converters/file_path_converter.h"
37 #include "atom/common/native_mate_converters/gfx_converter.h"
38 #include "atom/common/native_mate_converters/gurl_converter.h"
39 #include "atom/common/native_mate_converters/image_converter.h"
40 #include "atom/common/native_mate_converters/net_converter.h"
41 #include "atom/common/native_mate_converters/string16_converter.h"
42 #include "atom/common/native_mate_converters/value_converter.h"
43 #include "atom/common/options_switches.h"
44 #include "base/strings/utf_string_conversions.h"
45 #include "base/threading/thread_task_runner_handle.h"
46 #include "brightray/browser/inspectable_web_contents.h"
47 #include "brightray/browser/inspectable_web_contents_view.h"
48 #include "chrome/browser/printing/print_preview_message_handler.h"
49 #include "chrome/browser/printing/print_view_manager_basic.h"
50 #include "chrome/browser/ssl/security_state_tab_helper.h"
51 #include "content/browser/frame_host/navigation_entry_impl.h"
52 #include "content/browser/renderer_host/render_widget_host_impl.h"
53 #include "content/browser/web_contents/web_contents_impl.h"
54 #include "content/common/view_messages.h"
55 #include "content/public/browser/favicon_status.h"
56 #include "content/public/browser/native_web_keyboard_event.h"
57 #include "content/public/browser/navigation_details.h"
58 #include "content/public/browser/navigation_entry.h"
59 #include "content/public/browser/navigation_handle.h"
60 #include "content/public/browser/notification_details.h"
61 #include "content/public/browser/notification_source.h"
62 #include "content/public/browser/notification_types.h"
63 #include "content/public/browser/plugin_service.h"
64 #include "content/public/browser/render_frame_host.h"
65 #include "content/public/browser/render_process_host.h"
66 #include "content/public/browser/render_view_host.h"
67 #include "content/public/browser/render_widget_host.h"
68 #include "content/public/browser/render_widget_host_view.h"
69 #include "content/public/browser/resource_request_details.h"
70 #include "content/public/browser/service_worker_context.h"
71 #include "content/public/browser/site_instance.h"
72 #include "content/public/browser/storage_partition.h"
73 #include "content/public/browser/web_contents.h"
74 #include "content/public/common/context_menu_params.h"
75 #include "native_mate/dictionary.h"
76 #include "native_mate/object_template_builder.h"
77 #include "net/url_request/url_request_context.h"
78 #include "third_party/WebKit/public/platform/WebInputEvent.h"
79 #include "third_party/WebKit/public/web/WebFindOptions.h"
80 #include "ui/display/screen.h"
81
82 #if defined(USE_EFL)
83 #include "tizen/extensions/common/xwalk_extension_server.h"
84 #endif
85
86 #if !defined(OS_MACOSX) && !defined(USE_EFL)
87 #include "ui/aura/window.h"
88 #endif
89
90 #include "atom/common/node_includes.h"
91
92 namespace {
93
94 struct PrintSettings {
95   bool silent;
96   bool print_background;
97 };
98
99 }  // namespace
100
101 namespace mate {
102
103 template<>
104 struct Converter<atom::SetSizeParams> {
105   static bool FromV8(v8::Isolate* isolate,
106                      v8::Local<v8::Value> val,
107                      atom::SetSizeParams* out) {
108     mate::Dictionary params;
109     if (!ConvertFromV8(isolate, val, &params))
110       return false;
111     bool autosize;
112     if (params.Get("enableAutoSize", &autosize))
113       out->enable_auto_size.reset(new bool(true));
114     gfx::Size size;
115     if (params.Get("min", &size))
116       out->min_size.reset(new gfx::Size(size));
117     if (params.Get("max", &size))
118       out->max_size.reset(new gfx::Size(size));
119     if (params.Get("normal", &size))
120       out->normal_size.reset(new gfx::Size(size));
121     return true;
122   }
123 };
124
125 template<>
126 struct Converter<PrintSettings> {
127   static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
128                      PrintSettings* out) {
129     mate::Dictionary dict;
130     if (!ConvertFromV8(isolate, val, &dict))
131       return false;
132     dict.Get("silent", &(out->silent));
133     dict.Get("printBackground", &(out->print_background));
134     return true;
135   }
136 };
137
138 template<>
139 struct Converter<WindowOpenDisposition> {
140   static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
141                                    WindowOpenDisposition val) {
142     std::string disposition = "other";
143     switch (val) {
144       case WindowOpenDisposition::CURRENT_TAB:
145         disposition = "default";
146         break;
147       case WindowOpenDisposition::NEW_FOREGROUND_TAB:
148         disposition = "foreground-tab";
149         break;
150       case WindowOpenDisposition::NEW_BACKGROUND_TAB:
151         disposition = "background-tab";
152         break;
153       case WindowOpenDisposition::NEW_POPUP:
154       case WindowOpenDisposition::NEW_WINDOW:
155         disposition = "new-window";
156         break;
157       case WindowOpenDisposition::SAVE_TO_DISK:
158         disposition = "save-to-disk";
159         break;
160       default:
161         break;
162     }
163     return mate::ConvertToV8(isolate, disposition);
164   }
165 };
166
167 template<>
168 struct Converter<content::SavePageType> {
169   static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
170                      content::SavePageType* out) {
171     std::string save_type;
172     if (!ConvertFromV8(isolate, val, &save_type))
173       return false;
174     save_type = base::ToLowerASCII(save_type);
175     if (save_type == "htmlonly") {
176       *out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
177     } else if (save_type == "htmlcomplete") {
178       *out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
179     } else if (save_type == "mhtml") {
180       *out = content::SAVE_PAGE_TYPE_AS_MHTML;
181     } else {
182       return false;
183     }
184     return true;
185   }
186 };
187
188 template<>
189 struct Converter<atom::api::WebContents::Type> {
190   static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
191                                    atom::api::WebContents::Type val) {
192     using Type = atom::api::WebContents::Type;
193     std::string type = "";
194     switch (val) {
195       case Type::BACKGROUND_PAGE: type = "backgroundPage"; break;
196       case Type::BROWSER_WINDOW: type = "window"; break;
197       case Type::BROWSER_VIEW: type = "browserView"; break;
198       case Type::REMOTE: type = "remote"; break;
199       case Type::WEB_VIEW: type = "webview"; break;
200       case Type::OFF_SCREEN: type = "offscreen"; break;
201       default: break;
202     }
203     return mate::ConvertToV8(isolate, type);
204   }
205
206   static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
207                      atom::api::WebContents::Type* out) {
208     using Type = atom::api::WebContents::Type;
209     std::string type;
210     if (!ConvertFromV8(isolate, val, &type))
211       return false;
212     if (type == "backgroundPage") {
213       *out = Type::BACKGROUND_PAGE;
214     } else if (type == "browserView") {
215       *out = Type::BROWSER_VIEW;
216     } else if (type == "webview") {
217       *out = Type::WEB_VIEW;
218     } else if (type == "offscreen") {
219       *out = Type::OFF_SCREEN;
220     } else {
221       return false;
222     }
223     return true;
224   }
225 };
226
227 }  // namespace mate
228
229
230 namespace atom {
231
232 namespace api {
233
234 namespace {
235
236 content::ServiceWorkerContext* GetServiceWorkerContext(
237     const content::WebContents* web_contents) {
238   auto context = web_contents->GetBrowserContext();
239   auto site_instance = web_contents->GetSiteInstance();
240   if (!context || !site_instance)
241     return nullptr;
242
243   auto storage_partition =
244       content::BrowserContext::GetStoragePartition(context, site_instance);
245   if (!storage_partition)
246     return nullptr;
247
248   return storage_partition->GetServiceWorkerContext();
249 }
250
251 // Called when CapturePage is done.
252 void OnCapturePageDone(const base::Callback<void(const gfx::Image&)>& callback,
253                        const SkBitmap& bitmap,
254                        content::ReadbackResponse response) {
255   callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
256 }
257
258 // Set the background color of RenderWidgetHostView.
259 void SetBackgroundColor(content::WebContents* web_contents) {
260   const auto view = web_contents->GetRenderWidgetHostView();
261   if (view) {
262     WebContentsPreferences* web_preferences =
263         WebContentsPreferences::FromWebContents(web_contents);
264     std::string color_name;
265     if (web_preferences->web_preferences()->GetString(options::kBackgroundColor,
266                                                       &color_name)) {
267       view->SetBackgroundColor(ParseHexColor(color_name));
268     } else {
269       view->SetBackgroundColor(SK_ColorTRANSPARENT);
270     }
271   }
272 }
273
274 }  // namespace
275
276 WebContents::WebContents(v8::Isolate* isolate,
277                          content::WebContents* web_contents,
278                          Type type)
279     : content::WebContentsObserver(web_contents),
280       embedder_(nullptr),
281       zoom_controller_(nullptr),
282       type_(type),
283       request_id_(0),
284       background_throttling_(true),
285       enable_devtools_(true) {
286   if (type == REMOTE) {
287     web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
288     Init(isolate);
289     AttachAsUserData(web_contents);
290   } else {
291     const mate::Dictionary options = mate::Dictionary::CreateEmpty(isolate);
292     auto session = Session::CreateFrom(isolate, GetBrowserContext());
293     session_.Reset(isolate, session.ToV8());
294     InitWithSessionAndOptions(isolate, web_contents, session, options);
295   }
296 }
297
298 WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
299     : embedder_(nullptr),
300       zoom_controller_(nullptr),
301       type_(BROWSER_WINDOW),
302       request_id_(0),
303       background_throttling_(true),
304       enable_devtools_(true) {
305   // Read options.
306   options.Get("backgroundThrottling", &background_throttling_);
307
308   // FIXME(zcbenz): We should read "type" parameter for better design, but
309   // on Windows we have encountered a compiler bug that if we read "type"
310   // from |options| and then set |type_|, a memory corruption will happen
311   // and Electron will soon crash.
312   // Remvoe this after we upgraded to use VS 2015 Update 3.
313   bool b = false;
314   if (options.Get("isGuest", &b) && b)
315     type_ = WEB_VIEW;
316   else if (options.Get("isBackgroundPage", &b) && b)
317     type_ = BACKGROUND_PAGE;
318   else if (options.Get("isBrowserView", &b) && b)
319     type_ = BROWSER_VIEW;
320   else if (options.Get("offscreen", &b) && b)
321     type_ = OFF_SCREEN;
322
323   // Whether to enable DevTools.
324   options.Get("devTools", &enable_devtools_);
325
326   // Obtain the session.
327   std::string partition;
328   mate::Handle<api::Session> session;
329   if (options.Get("session", &session)) {
330   } else if (options.Get("partition", &partition)) {
331     session = Session::FromPartition(isolate, partition);
332   } else {
333     // Use the default session if not specified.
334     session = Session::FromPartition(isolate, "");
335   }
336   session_.Reset(isolate, session.ToV8());
337
338   content::WebContents* web_contents;
339   if (IsGuest()) {
340     scoped_refptr<content::SiteInstance> site_instance =
341         content::SiteInstance::CreateForURL(
342             session->browser_context(), GURL("chrome-guest://fake-host"));
343     content::WebContents::CreateParams params(
344         session->browser_context(), site_instance);
345     guest_delegate_.reset(new WebViewGuestDelegate);
346     params.guest_delegate = guest_delegate_.get();
347     web_contents = content::WebContents::Create(params);
348   } else if (IsOffScreen()) {
349     bool transparent = false;
350     options.Get("transparent", &transparent);
351
352     content::WebContents::CreateParams params(session->browser_context());
353     auto* view = new OffScreenWebContentsView(
354         transparent, base::Bind(&WebContents::OnPaint, base::Unretained(this)));
355     params.view = view;
356     params.delegate_view = view;
357
358     web_contents = content::WebContents::Create(params);
359     view->SetWebContents(web_contents);
360   } else {
361     content::WebContents::CreateParams params(session->browser_context());
362     web_contents = content::WebContents::Create(params);
363   }
364
365   InitWithSessionAndOptions(isolate, web_contents, session, options);
366 }
367
368 void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
369                                             content::WebContents *web_contents,
370                                             mate::Handle<api::Session> session,
371                                             const mate::Dictionary& options) {
372   content::WebContentsObserver::Observe(web_contents);
373   InitWithWebContents(web_contents, session->browser_context());
374
375   managed_web_contents()->GetView()->SetDelegate(this);
376
377   // Save the preferences in C++.
378   new WebContentsPreferences(web_contents, options);
379
380   // Initialize permission helper.
381   WebContentsPermissionHelper::CreateForWebContents(web_contents);
382   // Initialize security state client.
383   SecurityStateTabHelper::CreateForWebContents(web_contents);
384   // Initialize zoom controller.
385   WebContentsZoomController::CreateForWebContents(web_contents);
386   zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents);
387   double zoom_factor;
388   if (options.Get(options::kZoomFactor, &zoom_factor))
389     zoom_controller_->SetDefaultZoomFactor(zoom_factor);
390
391   web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
392
393   if (IsGuest()) {
394     guest_delegate_->Initialize(this);
395
396     NativeWindow* owner_window = nullptr;
397     if (options.Get("embedder", &embedder_) && embedder_) {
398       // New WebContents's owner_window is the embedder's owner_window.
399       auto relay =
400           NativeWindowRelay::FromWebContents(embedder_->web_contents());
401       if (relay)
402         owner_window = relay->window.get();
403     }
404     if (owner_window)
405       SetOwnerWindow(owner_window);
406   }
407
408   const content::NavigationController* controller =
409       &web_contents->GetController();
410   registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
411                  content::Source<content::NavigationController>(controller));
412
413   Init(isolate);
414   AttachAsUserData(web_contents);
415 }
416
417 WebContents::~WebContents() {
418   // The destroy() is called.
419   if (managed_web_contents()) {
420     // For webview we need to tell content module to do some cleanup work before
421     // destroying it.
422     if (type_ == WEB_VIEW)
423       guest_delegate_->Destroy();
424
425     RenderViewDeleted(web_contents()->GetRenderViewHost());
426     DestroyWebContents();
427   }
428 }
429
430 void WebContents::DestroyWebContents() {
431   // This event is only for internal use, which is emitted when WebContents is
432   // being destroyed.
433   Emit("will-destroy");
434   ResetManagedWebContents();
435 }
436
437 bool WebContents::DidAddMessageToConsole(content::WebContents* source,
438                                          int32_t level,
439                                          const base::string16& message,
440                                          int32_t line_no,
441                                          const base::string16& source_id) {
442   if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) {
443     LOG(ERROR) << "Console Message : " << message << ", source:" << source_id << " (" << line_no << ")";
444     return true;
445   } else {
446     Emit("console-message", level, message, line_no, source_id);
447     return true;
448   }
449 }
450
451 void WebContents::OnCreateWindow(
452     const GURL& target_url,
453     const std::string& frame_name,
454     WindowOpenDisposition disposition,
455     const std::vector<std::string>& features,
456     const scoped_refptr<content::ResourceRequestBodyImpl>& body) {
457   if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
458     Emit("-new-window", target_url, frame_name, disposition, features, body);
459   else
460     Emit("new-window", target_url, frame_name, disposition, features);
461 }
462
463 void WebContents::WebContentsCreated(content::WebContents* source_contents,
464                                      int opener_render_process_id,
465                                      int opener_render_frame_id,
466                                      const std::string& frame_name,
467                                      const GURL& target_url,
468                                      content::WebContents* new_contents) {
469   v8::Locker locker(isolate());
470   v8::HandleScope handle_scope(isolate());
471   auto api_web_contents = CreateFrom(isolate(), new_contents, BROWSER_WINDOW);
472   Emit("-web-contents-created", api_web_contents, target_url, frame_name);
473 }
474
475 void WebContents::AddNewContents(content::WebContents* source,
476                                  content::WebContents* new_contents,
477                                  WindowOpenDisposition disposition,
478                                  const gfx::Rect& initial_rect,
479                                  bool user_gesture,
480                                  bool* was_blocked) {
481   v8::Locker locker(isolate());
482   v8::HandleScope handle_scope(isolate());
483   auto api_web_contents = CreateFrom(isolate(), new_contents);
484   if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
485       initial_rect.x(), initial_rect.y(), initial_rect.width(),
486       initial_rect.height())) {
487     api_web_contents->DestroyWebContents();
488   }
489 }
490
491 content::WebContents* WebContents::OpenURLFromTab(
492     content::WebContents* source,
493     const content::OpenURLParams& params) {
494   if (params.disposition != WindowOpenDisposition::CURRENT_TAB) {
495     if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
496       Emit("-new-window", params.url, "", params.disposition);
497     else
498       Emit("new-window", params.url, "", params.disposition);
499     return nullptr;
500   }
501
502   // Give user a chance to cancel navigation.
503   if (Emit("will-navigate", params.url))
504     return nullptr;
505
506   // Don't load the URL if the web contents was marked as destroyed from a
507   // will-navigate event listener
508   if (IsDestroyed())
509     return nullptr;
510
511   return CommonWebContentsDelegate::OpenURLFromTab(source, params);
512 }
513
514 void WebContents::BeforeUnloadFired(content::WebContents* tab,
515                                     bool proceed,
516                                     bool* proceed_to_fire_unload) {
517   if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
518     *proceed_to_fire_unload = proceed;
519   else
520     *proceed_to_fire_unload = true;
521 }
522
523 void WebContents::MoveContents(content::WebContents* source,
524                                const gfx::Rect& pos) {
525   Emit("move", pos);
526 }
527
528 void WebContents::CloseContents(content::WebContents* source) {
529   Emit("close");
530   LOG(ERROR) << __FUNCTION__;
531   if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
532     owner_window()->CloseContents(source);
533 }
534
535 void WebContents::ActivateContents(content::WebContents* source) {
536   Emit("activate");
537 }
538
539 void WebContents::UpdateTargetURL(content::WebContents* source,
540                                   const GURL& url) {
541   Emit("update-target-url", url);
542 }
543
544 bool WebContents::IsPopupOrPanel(const content::WebContents* source) const {
545   return type_ == BROWSER_WINDOW;
546 }
547
548 void WebContents::HandleKeyboardEvent(
549     content::WebContents* source,
550     const content::NativeWebKeyboardEvent& event) {
551   if (type_ == WEB_VIEW && embedder_) {
552     // Send the unhandled keyboard events back to the embedder.
553     embedder_->HandleKeyboardEvent(source, event);
554   } else {
555     // Go to the default keyboard handling.
556     CommonWebContentsDelegate::HandleKeyboardEvent(source, event);
557   }
558 }
559
560 bool WebContents::PreHandleKeyboardEvent(
561     content::WebContents* source,
562     const content::NativeWebKeyboardEvent& event,
563     bool* is_keyboard_shortcut) {
564   if (event.type == blink::WebInputEvent::Type::RawKeyDown
565       || event.type == blink::WebInputEvent::Type::KeyUp)
566     return Emit("before-input-event", event);
567   else
568     return false;
569 }
570
571 void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
572                                             const GURL& origin) {
573   auto permission_helper =
574       WebContentsPermissionHelper::FromWebContents(source);
575   auto callback = base::Bind(&WebContents::OnEnterFullscreenModeForTab,
576                              base::Unretained(this), source, origin);
577   permission_helper->RequestFullscreenPermission(callback);
578 }
579
580 void WebContents::OnEnterFullscreenModeForTab(content::WebContents* source,
581                                               const GURL& origin,
582                                               bool allowed) {
583   if (!allowed)
584     return;
585   CommonWebContentsDelegate::EnterFullscreenModeForTab(source, origin);
586   Emit("enter-html-full-screen");
587 }
588
589 void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
590   CommonWebContentsDelegate::ExitFullscreenModeForTab(source);
591   Emit("leave-html-full-screen");
592 }
593
594 void WebContents::RendererUnresponsive(
595     content::WebContents* source,
596     const content::WebContentsUnresponsiveState& unresponsive_state) {
597   Emit("unresponsive");
598   if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
599     owner_window()->RendererUnresponsive(source);
600 }
601
602 void WebContents::RendererResponsive(content::WebContents* source) {
603   Emit("responsive");
604   if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
605     owner_window()->RendererResponsive(source);
606 }
607
608 bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) {
609   if (params.custom_context.is_pepper_menu) {
610     Emit("pepper-context-menu", std::make_pair(params, web_contents()));
611     web_contents()->NotifyContextMenuClosed(params.custom_context);
612   } else {
613     Emit("context-menu", std::make_pair(params, web_contents()));
614   }
615
616   return true;
617 }
618
619 bool WebContents::OnGoToEntryOffset(int offset) {
620   GoToOffset(offset);
621   return false;
622 }
623
624 void WebContents::FindReply(content::WebContents* web_contents,
625                             int request_id,
626                             int number_of_matches,
627                             const gfx::Rect& selection_rect,
628                             int active_match_ordinal,
629                             bool final_update) {
630   if (!final_update)
631     return;
632
633   v8::Locker locker(isolate());
634   v8::HandleScope handle_scope(isolate());
635   mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate());
636   result.Set("requestId", request_id);
637   result.Set("matches", number_of_matches);
638   result.Set("selectionArea", selection_rect);
639   result.Set("activeMatchOrdinal", active_match_ordinal);
640   result.Set("finalUpdate", final_update);  // Deprecate after 2.0
641   Emit("found-in-page", result);
642 }
643
644 bool WebContents::CheckMediaAccessPermission(
645     content::WebContents* web_contents,
646     const GURL& security_origin,
647     content::MediaStreamType type) {
648   return true;
649 }
650
651 void WebContents::RequestMediaAccessPermission(
652     content::WebContents* web_contents,
653     const content::MediaStreamRequest& request,
654     const content::MediaResponseCallback& callback) {
655   auto permission_helper =
656       WebContentsPermissionHelper::FromWebContents(web_contents);
657   permission_helper->RequestMediaAccessPermission(request, callback);
658 }
659
660 void WebContents::RequestToLockMouse(
661     content::WebContents* web_contents,
662     bool user_gesture,
663     bool last_unlocked_by_target) {
664   auto permission_helper =
665       WebContentsPermissionHelper::FromWebContents(web_contents);
666   permission_helper->RequestPointerLockPermission(user_gesture);
667 }
668
669 std::unique_ptr<content::BluetoothChooser> WebContents::RunBluetoothChooser(
670     content::RenderFrameHost* frame,
671     const content::BluetoothChooser::EventHandler& event_handler) {
672   std::unique_ptr<BluetoothChooser> bluetooth_chooser(
673       new BluetoothChooser(this, event_handler));
674   return std::move(bluetooth_chooser);
675 }
676
677 void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
678   // Do nothing, we override this method just to avoid compilation error since
679   // there are two virtual functions named BeforeUnloadFired.
680 }
681
682 void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) {
683   const auto impl = content::RenderWidgetHostImpl::FromID(
684       render_view_host->GetProcess()->GetID(),
685       render_view_host->GetRoutingID());
686   if (impl)
687     impl->disable_hidden_ = !background_throttling_;
688   atom::Browser::Get()->RenderViewCreated(render_view_host);
689 }
690
691 void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
692   Emit("render-view-deleted", render_view_host->GetProcess()->GetID());
693 }
694
695 void WebContents::RenderProcessGone(base::TerminationStatus status) {
696   Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
697 }
698
699 void WebContents::PluginCrashed(const base::FilePath& plugin_path,
700                                 base::ProcessId plugin_pid) {
701   content::WebPluginInfo info;
702   auto plugin_service = content::PluginService::GetInstance();
703   plugin_service->GetPluginInfoByPath(plugin_path, &info);
704   Emit("plugin-crashed", info.name, info.version);
705 }
706
707 void WebContents::MediaStartedPlaying(const MediaPlayerInfo& video_type,
708                                       const MediaPlayerId& id) {
709   Emit("media-started-playing");
710 }
711
712 void WebContents::MediaStoppedPlaying(const MediaPlayerInfo& video_type,
713                                       const MediaPlayerId& id) {
714   Emit("media-paused");
715 }
716
717 void WebContents::DidChangeThemeColor(SkColor theme_color) {
718   Emit("did-change-theme-color", atom::ToRGBHex(theme_color));
719 }
720
721 void WebContents::DocumentLoadedInFrame(
722     content::RenderFrameHost* render_frame_host) {
723   if (!render_frame_host->GetParent())
724     Emit("dom-ready");
725 }
726
727 void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
728                                 const GURL& validated_url) {
729   bool is_main_frame = !render_frame_host->GetParent();
730   Emit("did-frame-finish-load", is_main_frame);
731
732   if (is_main_frame)
733     Emit("did-finish-load");
734 }
735
736 void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
737                               const GURL& url,
738                               int error_code,
739                               const base::string16& error_description,
740                               bool was_ignored_by_handler) {
741   bool is_main_frame = !render_frame_host->GetParent();
742   Emit("did-fail-load", error_code, error_description, url, is_main_frame);
743 }
744
745 void WebContents::DidStartLoading() {
746 #if defined(OS_TIZEN)
747   if (owner_window() && !owner_window()->IsVisible()) {
748     std::string scheme = web_contents()->GetURL().scheme();
749     if (std::string::npos != scheme.find("http")) {
750       owner_window()->Show();
751     }
752   }
753 #endif
754   Emit("did-start-loading");
755 }
756
757 void WebContents::DidStopLoading() {
758   Emit("did-stop-loading");
759 }
760
761 void WebContents::DidGetResourceResponseStart(
762     const content::ResourceRequestDetails& details) {
763   Emit("did-get-response-details",
764        details.socket_address.IsEmpty(),
765        details.url,
766        details.original_url,
767        details.http_response_code,
768        details.method,
769        details.referrer,
770        details.headers.get(),
771        ResourceTypeToString(details.resource_type));
772 }
773
774 void WebContents::DidGetRedirectForResourceRequest(
775     const content::ResourceRedirectDetails& details) {
776   Emit("did-get-redirect-request",
777        details.url,
778        details.new_url,
779        (details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME),
780        details.http_response_code,
781        details.method,
782        details.referrer,
783        details.headers.get());
784 }
785
786 void WebContents::DidStartNavigation(
787     content::NavigationHandle* navigation_handle) {
788   if (!navigation_handle->IsInMainFrame() || navigation_handle->IsSamePage())
789     return;
790
791   if (deferred_load_url_.id) {
792     auto web_contents = navigation_handle->GetWebContents();
793     auto& controller = web_contents->GetController();
794     int id = controller.GetPendingEntry()->GetUniqueID();
795     if (id == deferred_load_url_.id) {
796       if (!deferred_load_url_.params.url.is_empty()) {
797         auto params = deferred_load_url_.params;
798         deferred_load_url_.id = 0;
799         deferred_load_url_.params =
800             content::NavigationController::LoadURLParams(GURL());
801         controller.LoadURLWithParams(params);
802         SetBackgroundColor(web_contents);
803       } else {
804         deferred_load_url_.id = 0;
805       }
806     }
807   }
808 }
809
810 void WebContents::DidFinishNavigation(
811     content::NavigationHandle* navigation_handle) {
812   bool is_main_frame = navigation_handle->IsInMainFrame();
813   if (navigation_handle->HasCommitted() && !navigation_handle->IsErrorPage()) {
814     auto url = navigation_handle->GetURL();
815     bool is_in_page = navigation_handle->IsSamePage();
816     if (is_main_frame && !is_in_page) {
817       Emit("did-navigate", url);
818     } else if (is_in_page) {
819       Emit("did-navigate-in-page", url, is_main_frame);
820     }
821   } else {
822     auto url = navigation_handle->GetURL();
823     int code = navigation_handle->GetNetErrorCode();
824     auto description = net::ErrorToShortString(code);
825     Emit("did-fail-provisional-load", code, description, url, is_main_frame);
826
827     // Do not emit "did-fail-load" for canceled requests.
828     if (code != net::ERR_ABORTED)
829       Emit("did-fail-load", code, description, url, is_main_frame);
830   }
831 }
832
833 void WebContents::TitleWasSet(content::NavigationEntry* entry,
834                               bool explicit_set) {
835   if (entry)
836     Emit("-page-title-updated", entry->GetTitle(), explicit_set);
837   else
838     Emit("-page-title-updated", "", explicit_set);
839 }
840
841 void WebContents::DidUpdateFaviconURL(
842     const std::vector<content::FaviconURL>& urls) {
843   std::set<GURL> unique_urls;
844   for (const auto& iter : urls) {
845     if (iter.icon_type != content::FaviconURL::FAVICON)
846       continue;
847     const GURL& url = iter.icon_url;
848     if (url.is_valid())
849       unique_urls.insert(url);
850   }
851   Emit("page-favicon-updated", unique_urls);
852 }
853
854 void WebContents::Observe(int type,
855                           const content::NotificationSource& source,
856                           const content::NotificationDetails& details) {
857   switch (type) {
858     case content::NOTIFICATION_NAV_ENTRY_PENDING: {
859       content::NavigationEntry* entry =
860           content::Details<content::NavigationEntry>(details).ptr();
861       content::NavigationEntryImpl* entry_impl =
862           static_cast<content::NavigationEntryImpl*>(entry);
863       // In NavigatorImpl::DidStartMainFrameNavigation when there is no
864       // browser side pending entry available it creates a new one based
865       // on existing pending entry, hence we track the unique id here
866       // instead in WebContents::LoadURL with controller.GetPendingEntry()
867       // TODO(deepak1556): Remove once we have
868       // https://codereview.chromium.org/2661743002.
869       if (entry_impl->frame_tree_node_id() == -1) {
870         deferred_load_url_.id = entry->GetUniqueID();
871       }
872       break;
873     }
874     default:
875       NOTREACHED();
876       break;
877   }
878 }
879
880 void WebContents::DevToolsReloadPage() {
881   Emit("devtools-reload-page");
882 }
883
884 void WebContents::DevToolsFocused() {
885   Emit("devtools-focused");
886 }
887
888 void WebContents::DevToolsOpened() {
889   v8::Locker locker(isolate());
890   v8::HandleScope handle_scope(isolate());
891   auto handle = WebContents::CreateFrom(
892       isolate(), managed_web_contents()->GetDevToolsWebContents());
893   devtools_web_contents_.Reset(isolate(), handle.ToV8());
894
895   // Set inspected tabID.
896   base::FundamentalValue tab_id(ID());
897   managed_web_contents()->CallClientFunction(
898       "DevToolsAPI.setInspectedTabId", &tab_id, nullptr, nullptr);
899
900   // Inherit owner window in devtools.
901   if (owner_window())
902     handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(),
903                            owner_window());
904
905   Emit("devtools-opened");
906 }
907
908 void WebContents::DevToolsClosed() {
909   v8::Locker locker(isolate());
910   v8::HandleScope handle_scope(isolate());
911   devtools_web_contents_.Reset();
912
913   Emit("devtools-closed");
914 }
915
916 void WebContents::OnWrtPluginMessage(const Ewk_Wrt_Message_Data& data) {
917   Ewk_Wrt_Message_Data tmp = data;
918   HandleWrtPluginMessage(&tmp);
919 }
920
921 void WebContents::OnWrtPluginSyncMessage(const Ewk_Wrt_Message_Data& data,
922                                                     IPC::Message* reply) {
923   Ewk_Wrt_Message_Data tmp = data;
924   HandleWrtPluginMessage(&tmp);
925   AtomHostMsg_WrtSyncMessage::WriteReplyParams(reply, tmp.value);
926   Send(reply);
927 }
928
929 void WebContents::HandleWrtPluginMessage(Ewk_Wrt_Message_Data* msg) {
930   Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(msg);
931   LOG(INFO) << msg_type;
932 #define TYPE_BEGIN(x) (!strncmp(msg_type, x, strlen(x)))
933 #define TYPE_IS(x) (!strcmp(msg_type, x))
934   if (TYPE_BEGIN("xwalk://")) {
935     auto extension_server = extensions::XWalkExtensionServer::GetInstance();
936     extension_server->HandleIPCMessage(msg);
937   } else {
938     Eina_Stringshare* msg_id = msg->GetId();
939     Eina_Stringshare* msg_ref_id = msg->GetReferenceId();
940     Eina_Stringshare* msg_value = msg->GetValue();
941     if (TYPE_IS("tizen://exit")) {
942       atom::Browser::Get()->Quit();
943     }
944
945     eina_stringshare_del(msg_ref_id);
946     eina_stringshare_del(msg_id);
947     eina_stringshare_del(msg_value);
948   }
949 #undef TYPE_IS
950 #undef TYPE_BEGIN
951
952   eina_stringshare_del(msg_type);
953 }
954
955 bool WebContents::OnMessageReceived(const IPC::Message& message) {
956   bool handled = true;
957   IPC_BEGIN_MESSAGE_MAP(WebContents, message)
958     IPC_MESSAGE_HANDLER_DELAY_REPLY(WrtViewMsg_GetCSP, OnGetContentSecurityPolicy)
959     IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
960     IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
961                                     OnRendererMessageSync)
962     IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_SetTemporaryZoomLevel,
963                                     OnSetTemporaryZoomLevel)
964     IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_GetZoomLevel,
965                                     OnGetZoomLevel)
966     IPC_MESSAGE_HANDLER(AtomHostMsg_WrtMessage, OnWrtPluginMessage)
967     IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomHostMsg_WrtSyncMessage, OnWrtPluginSyncMessage)
968     // FIXME: Disable OnCursorChange due to stach_chk_fail crash.
969     // IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
970     //   handled = false)
971     IPC_MESSAGE_UNHANDLED(handled = false)
972   IPC_END_MESSAGE_MAP()
973
974   return handled;
975 }
976
977 // There are three ways of destroying a webContents:
978 // 1. call webContents.destroy();
979 // 2. garbage collection;
980 // 3. user closes the window of webContents;
981 // For webview only #1 will happen, for BrowserWindow both #1 and #3 may
982 // happen. The #2 should never happen for webContents, because webview is
983 // managed by GuestViewManager, and BrowserWindow's webContents is managed
984 // by api::Window.
985 // For #1, the destructor will do the cleanup work and we only need to make
986 // sure "destroyed" event is emitted. For #3, the content::WebContents will
987 // be destroyed on close, and WebContentsDestroyed would be called for it, so
988 // we need to make sure the api::WebContents is also deleted.
989 void WebContents::WebContentsDestroyed() {
990   // Cleanup relationships with other parts.
991   RemoveFromWeakMap();
992
993   // We can not call Destroy here because we need to call Emit first, but we
994   // also do not want any method to be used, so just mark as destroyed here.
995   MarkDestroyed();
996
997   Emit("destroyed");
998
999   // Destroy the native class in next tick.
1000   base::ThreadTaskRunnerHandle::Get()->PostTask(
1001       FROM_HERE, GetDestroyClosure());
1002 }
1003
1004 void WebContents::NavigationEntryCommitted(
1005     const content::LoadCommittedDetails& details) {
1006   Emit("navigation-entry-commited", details.entry->GetURL(),
1007        details.is_in_page, details.did_replace_entry);
1008 }
1009
1010 int64_t WebContents::GetID() const {
1011   int64_t process_id = web_contents()->GetRenderProcessHost()->GetID();
1012   int64_t routing_id = web_contents()->GetRoutingID();
1013   int64_t rv = (process_id << 32) + routing_id;
1014   return rv;
1015 }
1016
1017 int WebContents::GetProcessID() const {
1018   return web_contents()->GetRenderProcessHost()->GetID();
1019 }
1020
1021 WebContents::Type WebContents::GetType() const {
1022   return type_;
1023 }
1024
1025 bool WebContents::Equal(const WebContents* web_contents) const {
1026   return GetID() == web_contents->GetID();
1027 }
1028
1029 void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
1030   if (!url.is_valid() || url.spec().size() > url::kMaxURLChars) {
1031     Emit("did-fail-load",
1032          static_cast<int>(net::ERR_INVALID_URL),
1033          net::ErrorToShortString(net::ERR_INVALID_URL),
1034          url.possibly_invalid_spec(),
1035          true);
1036     return;
1037   }
1038
1039   content::NavigationController::LoadURLParams params(url);
1040
1041   GURL http_referrer;
1042   if (options.Get("httpReferrer", &http_referrer))
1043     params.referrer = content::Referrer(http_referrer.GetAsReferrer(),
1044                                         blink::WebReferrerPolicyDefault);
1045
1046   std::string user_agent;
1047   if (options.Get("userAgent", &user_agent))
1048     web_contents()->SetUserAgentOverride(user_agent);
1049
1050   std::string extra_headers;
1051   if (options.Get("extraHeaders", &extra_headers))
1052     params.extra_headers = extra_headers;
1053
1054   scoped_refptr<content::ResourceRequestBodyImpl> body;
1055   if (options.Get("postData", &body)) {
1056     params.post_data = body;
1057     params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST;
1058   }
1059
1060   GURL base_url_for_data_url;
1061   if (options.Get("baseURLForDataURL", &base_url_for_data_url)) {
1062     params.base_url_for_data_url = base_url_for_data_url;
1063     params.load_type = content::NavigationController::LOAD_TYPE_DATA;
1064   }
1065
1066   params.transition_type = ui::PAGE_TRANSITION_TYPED;
1067   params.should_clear_history_list = true;
1068   params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
1069
1070   if (deferred_load_url_.id) {
1071     deferred_load_url_.params = params;
1072     return;
1073   }
1074
1075   web_contents()->GetController().LoadURLWithParams(params);
1076   // We have to call it right after LoadURL because the RenderViewHost is only
1077   // created after loading a page.
1078   SetBackgroundColor(web_contents());
1079 }
1080
1081 void WebContents::DownloadURL(const GURL& url) {
1082   auto browser_context = web_contents()->GetBrowserContext();
1083   auto download_manager =
1084     content::BrowserContext::GetDownloadManager(browser_context);
1085
1086   download_manager->DownloadUrl(
1087       content::DownloadUrlParameters::CreateForWebContentsMainFrame(
1088           web_contents(), url));
1089 }
1090
1091 GURL WebContents::GetURL() const {
1092   return web_contents()->GetURL();
1093 }
1094
1095 base::string16 WebContents::GetTitle() const {
1096   return web_contents()->GetTitle();
1097 }
1098
1099 bool WebContents::IsLoading() const {
1100   return web_contents()->IsLoading();
1101 }
1102
1103 bool WebContents::IsLoadingMainFrame() const {
1104   // Comparing site instances works because Electron always creates a new site
1105   // instance when navigating, regardless of origin. See AtomBrowserClient.
1106   return (web_contents()->GetLastCommittedURL().is_empty() ||
1107           web_contents()->GetSiteInstance() !=
1108           web_contents()->GetPendingSiteInstance()) && IsLoading();
1109 }
1110
1111 bool WebContents::IsWaitingForResponse() const {
1112   return web_contents()->IsWaitingForResponse();
1113 }
1114
1115 void WebContents::Stop() {
1116   LOG(ERROR) << __FUNCTION__;
1117   web_contents()->Stop();
1118 }
1119
1120 void WebContents::GoBack() {
1121   atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
1122   web_contents()->GetController().GoBack();
1123 }
1124
1125 void WebContents::GoForward() {
1126   atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
1127   web_contents()->GetController().GoForward();
1128 }
1129
1130 void WebContents::GoToOffset(int offset) {
1131   atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
1132   web_contents()->GetController().GoToOffset(offset);
1133 }
1134
1135 const std::string WebContents::GetWebRTCIPHandlingPolicy() const {
1136   return web_contents()->
1137     GetMutableRendererPrefs()->webrtc_ip_handling_policy;
1138 }
1139
1140 void WebContents::SetWebRTCIPHandlingPolicy(
1141     const std::string& webrtc_ip_handling_policy) {
1142   if (GetWebRTCIPHandlingPolicy() == webrtc_ip_handling_policy)
1143     return;
1144   web_contents()->GetMutableRendererPrefs()->webrtc_ip_handling_policy =
1145     webrtc_ip_handling_policy;
1146
1147   content::RenderViewHost* host = web_contents()->GetRenderViewHost();
1148   if (host)
1149     host->SyncRendererPrefs();
1150 }
1151
1152 bool WebContents::IsCrashed() const {
1153   return web_contents()->IsCrashed();
1154 }
1155
1156 void WebContents::SetUserAgent(const std::string& user_agent,
1157                                mate::Arguments* args) {
1158   web_contents()->SetUserAgentOverride(user_agent);
1159 }
1160
1161 std::string WebContents::GetUserAgent() {
1162   return web_contents()->GetUserAgentOverride();
1163 }
1164
1165 bool WebContents::SavePage(const base::FilePath& full_file_path,
1166                            const content::SavePageType& save_type,
1167                            const SavePageHandler::SavePageCallback& callback) {
1168   auto handler = new SavePageHandler(web_contents(), callback);
1169   return handler->Handle(full_file_path, save_type);
1170 }
1171
1172 void WebContents::OpenDevTools(mate::Arguments* args) {
1173   if (type_ == REMOTE)
1174     return;
1175
1176   if (!enable_devtools_)
1177     return;
1178
1179   std::string state;
1180   if (type_ == WEB_VIEW || !owner_window()) {
1181     state = "detach";
1182   } else if (args && args->Length() == 1) {
1183     bool detach = false;
1184     mate::Dictionary options;
1185     if (args->GetNext(&options)) {
1186       options.Get("mode", &state);
1187
1188       // TODO(kevinsawicki) Remove in 2.0
1189       options.Get("detach", &detach);
1190       if (state.empty() && detach)
1191         state = "detach";
1192     }
1193   }
1194   managed_web_contents()->SetDockState(state);
1195   managed_web_contents()->ShowDevTools();
1196 }
1197
1198 void WebContents::CloseDevTools() {
1199   if (type_ == REMOTE)
1200     return;
1201
1202   managed_web_contents()->CloseDevTools();
1203 }
1204
1205 bool WebContents::IsDevToolsOpened() {
1206   if (type_ == REMOTE)
1207     return false;
1208
1209   return managed_web_contents()->IsDevToolsViewShowing();
1210 }
1211
1212 bool WebContents::IsDevToolsFocused() {
1213   if (type_ == REMOTE)
1214     return false;
1215
1216   return managed_web_contents()->GetView()->IsDevToolsViewFocused();
1217 }
1218
1219 void WebContents::EnableDeviceEmulation(
1220     const blink::WebDeviceEmulationParams& params) {
1221   if (type_ == REMOTE)
1222     return;
1223
1224   Send(new ViewMsg_EnableDeviceEmulation(routing_id(), params));
1225 }
1226
1227 void WebContents::DisableDeviceEmulation() {
1228   if (type_ == REMOTE)
1229     return;
1230
1231   Send(new ViewMsg_DisableDeviceEmulation(routing_id()));
1232 }
1233
1234 void WebContents::ToggleDevTools() {
1235   if (IsDevToolsOpened())
1236     CloseDevTools();
1237   else
1238     OpenDevTools(nullptr);
1239 }
1240
1241 void WebContents::InspectElement(int x, int y) {
1242   if (type_ == REMOTE)
1243     return;
1244
1245   if (!enable_devtools_)
1246     return;
1247
1248   if (!managed_web_contents()->GetDevToolsWebContents())
1249     OpenDevTools(nullptr);
1250   managed_web_contents()->InspectElement(x, y);
1251 }
1252
1253 void WebContents::InspectServiceWorker() {
1254   if (type_ == REMOTE)
1255     return;
1256
1257   if (!enable_devtools_)
1258     return;
1259
1260   for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
1261     if (agent_host->GetType() ==
1262         content::DevToolsAgentHost::kTypeServiceWorker) {
1263       OpenDevTools(nullptr);
1264       managed_web_contents()->AttachTo(agent_host);
1265       break;
1266     }
1267   }
1268 }
1269
1270 void WebContents::HasServiceWorker(
1271     const base::Callback<void(bool)>& callback) {
1272   auto context = GetServiceWorkerContext(web_contents());
1273   if (!context)
1274     return;
1275
1276   context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(),
1277                                  GURL::EmptyGURL(),
1278                                  callback);
1279 }
1280
1281 void WebContents::UnregisterServiceWorker(
1282     const base::Callback<void(bool)>& callback) {
1283   auto context = GetServiceWorkerContext(web_contents());
1284   if (!context)
1285     return;
1286
1287   context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(),
1288                                    callback);
1289 }
1290
1291 void WebContents::SetAudioMuted(bool muted) {
1292   web_contents()->SetAudioMuted(muted);
1293 }
1294
1295 bool WebContents::IsAudioMuted() {
1296   return web_contents()->IsAudioMuted();
1297 }
1298
1299 void WebContents::Print(mate::Arguments* args) {
1300   PrintSettings settings = { false, false };
1301   if (args->Length() == 1 && !args->GetNext(&settings)) {
1302     args->ThrowError();
1303     return;
1304   }
1305
1306   printing::PrintViewManagerBasic::FromWebContents(web_contents())->
1307       PrintNow(web_contents()->GetMainFrame(),
1308                settings.silent,
1309                settings.print_background);
1310 }
1311
1312 void WebContents::PrintToPDF(const base::DictionaryValue& setting,
1313                              const PrintToPDFCallback& callback) {
1314   printing::PrintPreviewMessageHandler::FromWebContents(web_contents())->
1315       PrintToPDF(setting, callback);
1316 }
1317
1318 void WebContents::AddWorkSpace(mate::Arguments* args,
1319                                const base::FilePath& path) {
1320   if (path.empty()) {
1321     args->ThrowError("path cannot be empty");
1322     return;
1323   }
1324   DevToolsAddFileSystem(path);
1325 }
1326
1327 void WebContents::RemoveWorkSpace(mate::Arguments* args,
1328                                   const base::FilePath& path) {
1329   if (path.empty()) {
1330     args->ThrowError("path cannot be empty");
1331     return;
1332   }
1333   DevToolsRemoveFileSystem(path);
1334 }
1335
1336 void WebContents::Undo() {
1337   web_contents()->Undo();
1338 }
1339
1340 void WebContents::Redo() {
1341   web_contents()->Redo();
1342 }
1343
1344 void WebContents::Cut() {
1345   web_contents()->Cut();
1346 }
1347
1348 void WebContents::Copy() {
1349   web_contents()->Copy();
1350 }
1351
1352 void WebContents::Paste() {
1353   web_contents()->Paste();
1354 }
1355
1356 void WebContents::PasteAndMatchStyle() {
1357   web_contents()->PasteAndMatchStyle();
1358 }
1359
1360 void WebContents::Delete() {
1361   web_contents()->Delete();
1362 }
1363
1364 void WebContents::SelectAll() {
1365   web_contents()->SelectAll();
1366 }
1367
1368 void WebContents::Unselect() {
1369   web_contents()->Unselect();
1370 }
1371
1372 void WebContents::Replace(const base::string16& word) {
1373   web_contents()->Replace(word);
1374 }
1375
1376 void WebContents::ReplaceMisspelling(const base::string16& word) {
1377   web_contents()->ReplaceMisspelling(word);
1378 }
1379
1380 uint32_t WebContents::FindInPage(mate::Arguments* args) {
1381   uint32_t request_id = GetNextRequestId();
1382   base::string16 search_text;
1383   blink::WebFindOptions options;
1384   if (!args->GetNext(&search_text) || search_text.empty()) {
1385     args->ThrowError("Must provide a non-empty search content");
1386     return 0;
1387   }
1388
1389   args->GetNext(&options);
1390
1391   web_contents()->Find(request_id, search_text, options);
1392   return request_id;
1393 }
1394
1395 void WebContents::StopFindInPage(content::StopFindAction action) {
1396   web_contents()->StopFinding(action);
1397 }
1398
1399 void WebContents::ShowDefinitionForSelection() {
1400 #if defined(OS_MACOSX)
1401   const auto view = web_contents()->GetRenderWidgetHostView();
1402   if (view)
1403     view->ShowDefinitionForSelection();
1404 #endif
1405 }
1406
1407 void WebContents::CopyImageAt(int x, int y) {
1408   const auto host = web_contents()->GetMainFrame();
1409   if (host)
1410     host->CopyImageAt(x, y);
1411 }
1412
1413 void WebContents::Focus() {
1414   web_contents()->Focus();
1415 }
1416
1417 #if !defined(OS_MACOSX)
1418 bool WebContents::IsFocused() const {
1419   auto view = web_contents()->GetRenderWidgetHostView();
1420   if (!view) return false;
1421
1422 #if defined(USE_EFL)
1423   NOTIMPLEMENTED();
1424 #else
1425   if (GetType() != BACKGROUND_PAGE) {
1426     auto window = web_contents()->GetNativeView()->GetToplevelWindow();
1427     if (window && !window->IsVisible())
1428       return false;
1429   }
1430 #endif
1431
1432   return view->HasFocus();
1433 }
1434 #endif
1435
1436 void WebContents::TabTraverse(bool reverse) {
1437   web_contents()->FocusThroughTabTraversal(reverse);
1438 }
1439
1440 bool WebContents::SendIPCMessage(bool all_frames,
1441                                  const base::string16& channel,
1442                                  const base::ListValue& args) {
1443   return Send(new AtomViewMsg_Message(routing_id(), all_frames, channel, args));
1444 }
1445
1446 void WebContents::SendInputEvent(v8::Isolate* isolate,
1447                                  v8::Local<v8::Value> input_event) {
1448   const auto view = web_contents()->GetRenderWidgetHostView();
1449   if (!view)
1450     return;
1451   const auto host = view->GetRenderWidgetHost();
1452   if (!host)
1453     return;
1454
1455   int type = mate::GetWebInputEventType(isolate, input_event);
1456   if (blink::WebInputEvent::isMouseEventType(type)) {
1457     blink::WebMouseEvent mouse_event;
1458     if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) {
1459       host->ForwardMouseEvent(mouse_event);
1460       return;
1461     }
1462   } else if (blink::WebInputEvent::isKeyboardEventType(type)) {
1463     content::NativeWebKeyboardEvent keyboard_event;
1464     if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) {
1465       host->ForwardKeyboardEvent(keyboard_event);
1466       return;
1467     }
1468   } else if (type == blink::WebInputEvent::MouseWheel) {
1469     blink::WebMouseWheelEvent mouse_wheel_event;
1470     if (mate::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) {
1471       host->ForwardWheelEvent(mouse_wheel_event);
1472       return;
1473     }
1474   }
1475
1476   isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
1477       isolate, "Invalid event object")));
1478 }
1479
1480 void WebContents::BeginFrameSubscription(mate::Arguments* args) {
1481   bool only_dirty = false;
1482   FrameSubscriber::FrameCaptureCallback callback;
1483
1484   args->GetNext(&only_dirty);
1485   if (!args->GetNext(&callback)) {
1486     args->ThrowError();
1487     return;
1488   }
1489
1490   const auto view = web_contents()->GetRenderWidgetHostView();
1491   if (view) {
1492     std::unique_ptr<FrameSubscriber> frame_subscriber(new FrameSubscriber(
1493         isolate(), view, callback, only_dirty));
1494     view->BeginFrameSubscription(std::move(frame_subscriber));
1495   }
1496 }
1497
1498 void WebContents::EndFrameSubscription() {
1499   const auto view = web_contents()->GetRenderWidgetHostView();
1500   if (view)
1501     view->EndFrameSubscription();
1502 }
1503
1504 void WebContents::StartDrag(const mate::Dictionary& item,
1505                             mate::Arguments* args) {
1506   base::FilePath file;
1507   std::vector<base::FilePath> files;
1508   if (!item.Get("files", &files) && item.Get("file", &file)) {
1509     files.push_back(file);
1510   }
1511
1512   mate::Handle<NativeImage> icon;
1513   if (!item.Get("icon", &icon) && !file.empty()) {
1514     // TODO(zcbenz): Set default icon from file.
1515   }
1516
1517   // Error checking.
1518   if (icon.IsEmpty()) {
1519     args->ThrowError("Must specify 'icon' option");
1520     return;
1521   }
1522
1523 #if defined(OS_MACOSX)
1524   // NSWindow.dragImage requires a non-empty NSImage
1525   if (icon->image().IsEmpty()) {
1526     args->ThrowError("Must specify non-empty 'icon' option");
1527     return;
1528   }
1529 #endif
1530
1531   // Start dragging.
1532   if (!files.empty()) {
1533     base::MessageLoop::ScopedNestableTaskAllower allow(
1534         base::MessageLoop::current());
1535     DragFileItems(files, icon->image(), web_contents()->GetNativeView());
1536   } else {
1537     args->ThrowError("Must specify either 'file' or 'files' option");
1538   }
1539 }
1540
1541 void WebContents::CapturePage(mate::Arguments* args) {
1542   gfx::Rect rect;
1543   base::Callback<void(const gfx::Image&)> callback;
1544
1545   if (!(args->Length() == 1 && args->GetNext(&callback)) &&
1546       !(args->Length() == 2 && args->GetNext(&rect)
1547                             && args->GetNext(&callback))) {
1548     args->ThrowError();
1549     return;
1550   }
1551
1552   const auto view = web_contents()->GetRenderWidgetHostView();
1553   const auto host = view ? view->GetRenderWidgetHost() : nullptr;
1554   if (!view || !host) {
1555     callback.Run(gfx::Image());
1556     return;
1557   }
1558
1559   // Capture full page if user doesn't specify a |rect|.
1560   const gfx::Size view_size = rect.IsEmpty() ? view->GetViewBounds().size() :
1561                                                rect.size();
1562
1563   // By default, the requested bitmap size is the view size in screen
1564   // coordinates.  However, if there's more pixel detail available on the
1565   // current system, increase the requested bitmap size to capture it all.
1566   gfx::Size bitmap_size = view_size;
1567   const gfx::NativeView native_view = view->GetNativeView();
1568   const float scale =
1569       display::Screen::GetScreen()->GetDisplayNearestWindow(native_view)
1570       .device_scale_factor();
1571   if (scale > 1.0f)
1572     bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
1573
1574   host->CopyFromBackingStore(gfx::Rect(rect.origin(), view_size),
1575                              bitmap_size,
1576                              base::Bind(&OnCapturePageDone, callback),
1577                              kBGRA_8888_SkColorType);
1578 }
1579
1580 void WebContents::OnCursorChange(const content::WebCursor& cursor) {
1581   content::WebCursor::CursorInfo info;
1582   cursor.GetCursorInfo(&info);
1583
1584   if (cursor.IsCustom()) {
1585     Emit("cursor-changed", CursorTypeToString(info),
1586       gfx::Image::CreateFrom1xBitmap(info.custom_image),
1587       info.image_scale_factor,
1588       gfx::Size(info.custom_image.width(), info.custom_image.height()),
1589       info.hotspot);
1590   } else {
1591     Emit("cursor-changed", CursorTypeToString(info));
1592   }
1593 }
1594
1595 void WebContents::SetSize(const SetSizeParams& params) {
1596   if (guest_delegate_)
1597     guest_delegate_->SetSize(params);
1598 }
1599
1600 bool WebContents::IsGuest() const {
1601   return type_ == WEB_VIEW;
1602 }
1603
1604 bool WebContents::IsOffScreen() const {
1605   return type_ == OFF_SCREEN;
1606 }
1607
1608 void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) {
1609   mate::Handle<NativeImage> image =
1610       NativeImage::Create(isolate(), gfx::Image::CreateFrom1xBitmap(bitmap));
1611   Emit("paint", dirty_rect, image);
1612 }
1613
1614 void WebContents::StartPainting() {
1615   if (!IsOffScreen())
1616     return;
1617
1618   auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1619       web_contents()->GetRenderWidgetHostView());
1620   if (osr_rwhv)
1621     osr_rwhv->SetPainting(true);
1622 }
1623
1624 void WebContents::StopPainting() {
1625   if (!IsOffScreen())
1626     return;
1627
1628   auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1629       web_contents()->GetRenderWidgetHostView());
1630   if (osr_rwhv)
1631     osr_rwhv->SetPainting(false);
1632 }
1633
1634 bool WebContents::IsPainting() const {
1635   if (!IsOffScreen())
1636     return false;
1637
1638   const auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1639       web_contents()->GetRenderWidgetHostView());
1640   return osr_rwhv && osr_rwhv->IsPainting();
1641 }
1642
1643 void WebContents::SetFrameRate(int frame_rate) {
1644   if (!IsOffScreen())
1645     return;
1646
1647   auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1648       web_contents()->GetRenderWidgetHostView());
1649   if (osr_rwhv)
1650     osr_rwhv->SetFrameRate(frame_rate);
1651 }
1652
1653 int WebContents::GetFrameRate() const {
1654   if (!IsOffScreen())
1655     return 0;
1656
1657   const auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1658       web_contents()->GetRenderWidgetHostView());
1659   return osr_rwhv ? osr_rwhv->GetFrameRate() : 0;
1660 }
1661
1662 void WebContents::Invalidate() {
1663   if (IsOffScreen()) {
1664     auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1665       web_contents()->GetRenderWidgetHostView());
1666     if (osr_rwhv)
1667       osr_rwhv->Invalidate();
1668   } else {
1669     const auto window = owner_window();
1670     if (window)
1671       window->Invalidate();
1672   }
1673 }
1674
1675 void WebContents::SetZoomLevel(double level) {
1676   zoom_controller_->SetZoomLevel(level);
1677 }
1678
1679 double WebContents::GetZoomLevel() {
1680   return zoom_controller_->GetZoomLevel();
1681 }
1682
1683 void WebContents::SetZoomFactor(double factor) {
1684   auto level = content::ZoomFactorToZoomLevel(factor);
1685   SetZoomLevel(level);
1686 }
1687
1688 double WebContents::GetZoomFactor() {
1689   auto level = GetZoomLevel();
1690   return content::ZoomLevelToZoomFactor(level);
1691 }
1692
1693 void WebContents::OnSetTemporaryZoomLevel(double level,
1694                                           IPC::Message* reply_msg) {
1695   zoom_controller_->SetTemporaryZoomLevel(level);
1696   double new_level = zoom_controller_->GetZoomLevel();
1697   AtomViewHostMsg_SetTemporaryZoomLevel::WriteReplyParams(reply_msg, new_level);
1698   Send(reply_msg);
1699 }
1700
1701 void WebContents::OnGetZoomLevel(IPC::Message* reply_msg) {
1702   AtomViewHostMsg_GetZoomLevel::WriteReplyParams(reply_msg, GetZoomLevel());
1703   Send(reply_msg);
1704 }
1705
1706 void WebContents::OnGetContentSecurityPolicy(IPC::Message* reply_msg) {
1707   std::string csp_rule;
1708   std::string csp_report_rule;
1709   atom::Browser::Get()->GetCSP(csp_rule, csp_report_rule);
1710   WrtViewMsg_GetCSP::WriteReplyParams(reply_msg, csp_rule, csp_report_rule);
1711   Send(reply_msg);
1712 }
1713
1714 v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
1715   WebContentsPreferences* web_preferences =
1716       WebContentsPreferences::FromWebContents(web_contents());
1717   return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
1718 }
1719
1720 v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() {
1721   if (owner_window())
1722     return Window::From(isolate(), owner_window());
1723   else
1724     return v8::Null(isolate());
1725 }
1726
1727 int32_t WebContents::ID() const {
1728   return weak_map_id();
1729 }
1730
1731 v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
1732   return v8::Local<v8::Value>::New(isolate, session_);
1733 }
1734
1735 content::WebContents* WebContents::HostWebContents() {
1736   if (!embedder_)
1737     return nullptr;
1738   return embedder_->web_contents();
1739 }
1740
1741 void WebContents::SetEmbedder(const WebContents* embedder) {
1742   if (embedder) {
1743     NativeWindow* owner_window = nullptr;
1744     auto relay = NativeWindowRelay::FromWebContents(embedder->web_contents());
1745     if (relay) {
1746       owner_window = relay->window.get();
1747     }
1748     if (owner_window)
1749       SetOwnerWindow(owner_window);
1750
1751     content::RenderWidgetHostView* rwhv =
1752         web_contents()->GetRenderWidgetHostView();
1753     if (rwhv) {
1754       rwhv->Hide();
1755       rwhv->Show();
1756     }
1757   }
1758 }
1759
1760 v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
1761   if (devtools_web_contents_.IsEmpty())
1762     return v8::Null(isolate);
1763   else
1764     return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
1765 }
1766
1767 v8::Local<v8::Value> WebContents::Debugger(v8::Isolate* isolate) {
1768   if (debugger_.IsEmpty()) {
1769     auto handle = atom::api::Debugger::Create(isolate, web_contents());
1770     debugger_.Reset(isolate, handle.ToV8());
1771   }
1772   return v8::Local<v8::Value>::New(isolate, debugger_);
1773 }
1774
1775 // static
1776 void WebContents::BuildPrototype(v8::Isolate* isolate,
1777                                  v8::Local<v8::FunctionTemplate> prototype) {
1778   prototype->SetClassName(mate::StringToV8(isolate, "WebContents"));
1779   mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
1780       .MakeDestroyable()
1781       .SetMethod("getId", &WebContents::GetID)
1782       .SetMethod("getProcessId", &WebContents::GetProcessID)
1783       .SetMethod("equal", &WebContents::Equal)
1784       .SetMethod("_loadURL", &WebContents::LoadURL)
1785       .SetMethod("downloadURL", &WebContents::DownloadURL)
1786       .SetMethod("_getURL", &WebContents::GetURL)
1787       .SetMethod("getTitle", &WebContents::GetTitle)
1788       .SetMethod("isLoading", &WebContents::IsLoading)
1789       .SetMethod("isLoadingMainFrame", &WebContents::IsLoadingMainFrame)
1790       .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
1791       .SetMethod("_stop", &WebContents::Stop)
1792       .SetMethod("_goBack", &WebContents::GoBack)
1793       .SetMethod("_goForward", &WebContents::GoForward)
1794       .SetMethod("_goToOffset", &WebContents::GoToOffset)
1795       .SetMethod("isCrashed", &WebContents::IsCrashed)
1796       .SetMethod("setUserAgent", &WebContents::SetUserAgent)
1797       .SetMethod("getUserAgent", &WebContents::GetUserAgent)
1798       .SetMethod("savePage", &WebContents::SavePage)
1799       .SetMethod("openDevTools", &WebContents::OpenDevTools)
1800       .SetMethod("closeDevTools", &WebContents::CloseDevTools)
1801       .SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
1802       .SetMethod("isDevToolsFocused", &WebContents::IsDevToolsFocused)
1803       .SetMethod("enableDeviceEmulation",
1804                  &WebContents::EnableDeviceEmulation)
1805       .SetMethod("disableDeviceEmulation",
1806                  &WebContents::DisableDeviceEmulation)
1807       .SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
1808       .SetMethod("inspectElement", &WebContents::InspectElement)
1809       .SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
1810       .SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
1811       .SetMethod("undo", &WebContents::Undo)
1812       .SetMethod("redo", &WebContents::Redo)
1813       .SetMethod("cut", &WebContents::Cut)
1814       .SetMethod("copy", &WebContents::Copy)
1815       .SetMethod("paste", &WebContents::Paste)
1816       .SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
1817       .SetMethod("delete", &WebContents::Delete)
1818       .SetMethod("selectAll", &WebContents::SelectAll)
1819       .SetMethod("unselect", &WebContents::Unselect)
1820       .SetMethod("replace", &WebContents::Replace)
1821       .SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
1822       .SetMethod("findInPage", &WebContents::FindInPage)
1823       .SetMethod("stopFindInPage", &WebContents::StopFindInPage)
1824       .SetMethod("focus", &WebContents::Focus)
1825       .SetMethod("isFocused", &WebContents::IsFocused)
1826       .SetMethod("tabTraverse", &WebContents::TabTraverse)
1827       .SetMethod("_send", &WebContents::SendIPCMessage)
1828       .SetMethod("sendInputEvent", &WebContents::SendInputEvent)
1829       .SetMethod("beginFrameSubscription",
1830                  &WebContents::BeginFrameSubscription)
1831       .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
1832       .SetMethod("startDrag", &WebContents::StartDrag)
1833       .SetMethod("setSize", &WebContents::SetSize)
1834       .SetMethod("isGuest", &WebContents::IsGuest)
1835       .SetMethod("isOffscreen", &WebContents::IsOffScreen)
1836       .SetMethod("startPainting", &WebContents::StartPainting)
1837       .SetMethod("stopPainting", &WebContents::StopPainting)
1838       .SetMethod("isPainting", &WebContents::IsPainting)
1839       .SetMethod("setFrameRate", &WebContents::SetFrameRate)
1840       .SetMethod("getFrameRate", &WebContents::GetFrameRate)
1841       .SetMethod("invalidate", &WebContents::Invalidate)
1842       .SetMethod("setZoomLevel", &WebContents::SetZoomLevel)
1843       .SetMethod("_getZoomLevel", &WebContents::GetZoomLevel)
1844       .SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
1845       .SetMethod("_getZoomFactor", &WebContents::GetZoomFactor)
1846       .SetMethod("getType", &WebContents::GetType)
1847       .SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
1848       .SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
1849       .SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
1850       .SetMethod("unregisterServiceWorker",
1851                  &WebContents::UnregisterServiceWorker)
1852       .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
1853       .SetMethod("print", &WebContents::Print)
1854       .SetMethod("_printToPDF", &WebContents::PrintToPDF)
1855       .SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
1856       .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
1857       .SetMethod("showDefinitionForSelection",
1858                  &WebContents::ShowDefinitionForSelection)
1859       .SetMethod("copyImageAt", &WebContents::CopyImageAt)
1860       .SetMethod("capturePage", &WebContents::CapturePage)
1861       .SetMethod("setEmbedder", &WebContents::SetEmbedder)
1862       .SetMethod("setWebRTCIPHandlingPolicy",
1863                  &WebContents::SetWebRTCIPHandlingPolicy)
1864       .SetMethod("getWebRTCIPHandlingPolicy",
1865                  &WebContents::GetWebRTCIPHandlingPolicy)
1866       .SetProperty("id", &WebContents::ID)
1867       .SetProperty("session", &WebContents::Session)
1868       .SetProperty("hostWebContents", &WebContents::HostWebContents)
1869       .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents)
1870       .SetProperty("debugger", &WebContents::Debugger);
1871 }
1872
1873 AtomBrowserContext* WebContents::GetBrowserContext() const {
1874   return static_cast<AtomBrowserContext*>(web_contents()->GetBrowserContext());
1875 }
1876
1877 void WebContents::OnRendererMessage(const base::string16& channel,
1878                                     const base::ListValue& args) {
1879   // webContents.emit(channel, new Event(), args...);
1880   Emit(base::UTF16ToUTF8(channel), args);
1881 }
1882
1883 void WebContents::OnRendererMessageSync(const base::string16& channel,
1884                                         const base::ListValue& args,
1885                                         IPC::Message* message) {
1886   // webContents.emit(channel, new Event(sender, message), args...);
1887   EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args);
1888 }
1889
1890 // static
1891 mate::Handle<WebContents> WebContents::CreateFrom(
1892     v8::Isolate* isolate, content::WebContents* web_contents) {
1893   // We have an existing WebContents object in JS.
1894   auto existing = TrackableObject::FromWrappedClass(isolate, web_contents);
1895   if (existing)
1896     return mate::CreateHandle(isolate, static_cast<WebContents*>(existing));
1897
1898   // Otherwise create a new WebContents wrapper object.
1899   return mate::CreateHandle(isolate, new WebContents(isolate, web_contents,
1900         REMOTE));
1901 }
1902
1903 mate::Handle<WebContents> WebContents::CreateFrom(
1904     v8::Isolate* isolate, content::WebContents* web_contents, Type type) {
1905   // Otherwise create a new WebContents wrapper object.
1906   return mate::CreateHandle(isolate, new WebContents(isolate, web_contents,
1907         type));
1908 }
1909
1910 // static
1911 mate::Handle<WebContents> WebContents::Create(
1912     v8::Isolate* isolate, const mate::Dictionary& options) {
1913   return mate::CreateHandle(isolate, new WebContents(isolate, options));
1914 }
1915
1916 }  // namespace api
1917
1918 }  // namespace atom
1919
1920 namespace {
1921
1922 using atom::api::WebContents;
1923
1924 void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
1925                 v8::Local<v8::Context> context, void* priv) {
1926   v8::Isolate* isolate = context->GetIsolate();
1927   mate::Dictionary dict(isolate, exports);
1928   dict.Set("WebContents", WebContents::GetConstructor(isolate)->GetFunction());
1929   dict.SetMethod("create", &WebContents::Create);
1930   dict.SetMethod("fromId", &mate::TrackableObject<WebContents>::FromWeakMapID);
1931   dict.SetMethod("getAllWebContents",
1932                  &mate::TrackableObject<WebContents>::GetAll);
1933 }
1934
1935 }  // namespace
1936
1937 NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_web_contents, Initialize)