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