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