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