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.
5 #include "atom/browser/api/atom_api_web_contents.h"
10 #include "atom/browser/api/atom_api_debugger.h"
11 #include "atom/browser/api/atom_api_session.h"
12 #include "atom/browser/api/atom_api_window.h"
13 #include "atom/browser/atom_browser_client.h"
14 #include "atom/browser/atom_browser_context.h"
15 #include "atom/browser/atom_browser_main_parts.h"
16 #include "atom/browser/atom_security_state_model_client.h"
17 #include "atom/browser/lib/bluetooth_chooser.h"
18 #include "atom/browser/native_window.h"
19 #include "atom/browser/net/atom_network_delegate.h"
20 #include "atom/browser/osr/osr_output_device.h"
21 #include "atom/browser/osr/osr_render_widget_host_view.h"
22 #include "atom/browser/osr/osr_web_contents_view.h"
23 #include "atom/browser/ui/drag_util.h"
24 #include "atom/browser/web_contents_permission_helper.h"
25 #include "atom/browser/web_contents_preferences.h"
26 #include "atom/browser/web_view_guest_delegate.h"
27 #include "atom/common/api/api_messages.h"
28 #include "atom/common/api/event_emitter_caller.h"
29 #include "atom/common/color_util.h"
30 #include "atom/common/mouse_util.h"
31 #include "atom/common/native_mate_converters/blink_converter.h"
32 #include "atom/common/native_mate_converters/callback.h"
33 #include "atom/common/native_mate_converters/content_converter.h"
34 #include "atom/common/native_mate_converters/file_path_converter.h"
35 #include "atom/common/native_mate_converters/gfx_converter.h"
36 #include "atom/common/native_mate_converters/gurl_converter.h"
37 #include "atom/common/native_mate_converters/image_converter.h"
38 #include "atom/common/native_mate_converters/net_converter.h"
39 #include "atom/common/native_mate_converters/string16_converter.h"
40 #include "atom/common/native_mate_converters/value_converter.h"
41 #include "atom/common/options_switches.h"
42 #include "base/strings/utf_string_conversions.h"
43 #include "base/threading/thread_task_runner_handle.h"
44 #include "brightray/browser/inspectable_web_contents.h"
45 #include "brightray/browser/inspectable_web_contents_view.h"
46 #include "chrome/browser/printing/print_preview_message_handler.h"
47 #include "chrome/browser/printing/print_view_manager_basic.h"
48 #include "content/browser/renderer_host/render_widget_host_impl.h"
49 #include "content/browser/web_contents/web_contents_impl.h"
50 #include "content/common/view_messages.h"
51 #include "content/public/browser/favicon_status.h"
52 #include "content/public/browser/native_web_keyboard_event.h"
53 #include "content/public/browser/navigation_details.h"
54 #include "content/public/browser/navigation_entry.h"
55 #include "content/public/browser/navigation_handle.h"
56 #include "content/public/browser/plugin_service.h"
57 #include "content/public/browser/render_frame_host.h"
58 #include "content/public/browser/render_process_host.h"
59 #include "content/public/browser/render_view_host.h"
60 #include "content/public/browser/render_widget_host.h"
61 #include "content/public/browser/render_widget_host_view.h"
62 #include "content/public/browser/resource_request_details.h"
63 #include "content/public/browser/service_worker_context.h"
64 #include "content/public/browser/site_instance.h"
65 #include "content/public/browser/storage_partition.h"
66 #include "content/public/browser/web_contents.h"
67 #include "content/public/common/context_menu_params.h"
68 #include "native_mate/dictionary.h"
69 #include "native_mate/object_template_builder.h"
70 #include "net/url_request/url_request_context.h"
71 #include "third_party/WebKit/public/web/WebFindOptions.h"
72 #include "third_party/WebKit/public/web/WebInputEvent.h"
73 #include "ui/display/screen.h"
75 #if !defined(OS_MACOSX)
76 #include "ui/aura/window.h"
79 #include "atom/common/node_includes.h"
83 struct PrintSettings {
85 bool print_background;
93 struct Converter<atom::SetSizeParams> {
94 static bool FromV8(v8::Isolate* isolate,
95 v8::Local<v8::Value> val,
96 atom::SetSizeParams* out) {
97 mate::Dictionary params;
98 if (!ConvertFromV8(isolate, val, ¶ms))
101 if (params.Get("enableAutoSize", &autosize))
102 out->enable_auto_size.reset(new bool(true));
104 if (params.Get("min", &size))
105 out->min_size.reset(new gfx::Size(size));
106 if (params.Get("max", &size))
107 out->max_size.reset(new gfx::Size(size));
108 if (params.Get("normal", &size))
109 out->normal_size.reset(new gfx::Size(size));
115 struct Converter<PrintSettings> {
116 static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
117 PrintSettings* out) {
118 mate::Dictionary dict;
119 if (!ConvertFromV8(isolate, val, &dict))
121 dict.Get("silent", &(out->silent));
122 dict.Get("printBackground", &(out->print_background));
128 struct Converter<WindowOpenDisposition> {
129 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
130 WindowOpenDisposition val) {
131 std::string disposition = "other";
133 case CURRENT_TAB: disposition = "default"; break;
134 case NEW_FOREGROUND_TAB: disposition = "foreground-tab"; break;
135 case NEW_BACKGROUND_TAB: disposition = "background-tab"; break;
136 case NEW_POPUP: case NEW_WINDOW: disposition = "new-window"; break;
137 case SAVE_TO_DISK: disposition = "save-to-disk"; break;
140 return mate::ConvertToV8(isolate, disposition);
145 struct Converter<content::SavePageType> {
146 static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
147 content::SavePageType* out) {
148 std::string save_type;
149 if (!ConvertFromV8(isolate, val, &save_type))
151 save_type = base::ToLowerASCII(save_type);
152 if (save_type == "htmlonly") {
153 *out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
154 } else if (save_type == "htmlcomplete") {
155 *out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
156 } else if (save_type == "mhtml") {
157 *out = content::SAVE_PAGE_TYPE_AS_MHTML;
166 struct Converter<atom::api::WebContents::Type> {
167 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
168 atom::api::WebContents::Type val) {
169 using Type = atom::api::WebContents::Type;
170 std::string type = "";
172 case Type::BACKGROUND_PAGE: type = "backgroundPage"; break;
173 case Type::BROWSER_WINDOW: type = "window"; break;
174 case Type::REMOTE: type = "remote"; break;
175 case Type::WEB_VIEW: type = "webview"; break;
176 case Type::OFF_SCREEN: type = "offscreen"; break;
179 return mate::ConvertToV8(isolate, type);
182 static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
183 atom::api::WebContents::Type* out) {
184 using Type = atom::api::WebContents::Type;
186 if (!ConvertFromV8(isolate, val, &type))
188 if (type == "webview") {
189 *out = Type::WEB_VIEW;
190 } else if (type == "backgroundPage") {
191 *out = Type::BACKGROUND_PAGE;
192 } else if (type == "offscreen") {
193 *out = Type::OFF_SCREEN;
210 content::ServiceWorkerContext* GetServiceWorkerContext(
211 const content::WebContents* web_contents) {
212 auto context = web_contents->GetBrowserContext();
213 auto site_instance = web_contents->GetSiteInstance();
214 if (!context || !site_instance)
217 auto storage_partition =
218 content::BrowserContext::GetStoragePartition(context, site_instance);
219 if (!storage_partition)
222 return storage_partition->GetServiceWorkerContext();
225 // Called when CapturePage is done.
226 void OnCapturePageDone(base::Callback<void(const gfx::Image&)> callback,
227 const SkBitmap& bitmap,
228 content::ReadbackResponse response) {
229 callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
234 WebContents::WebContents(v8::Isolate* isolate,
235 content::WebContents* web_contents,
237 : content::WebContentsObserver(web_contents),
241 background_throttling_(true),
242 enable_devtools_(true) {
244 if (type == REMOTE) {
245 web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
247 AttachAsUserData(web_contents);
249 const mate::Dictionary options = mate::Dictionary::CreateEmpty(isolate);
250 auto session = Session::CreateFrom(isolate, GetBrowserContext());
251 session_.Reset(isolate, session.ToV8());
252 InitWithSessionAndOptions(isolate, web_contents, session, options);
256 WebContents::WebContents(v8::Isolate* isolate,
257 const mate::Dictionary& options)
258 : embedder_(nullptr),
259 type_(BROWSER_WINDOW),
261 background_throttling_(true),
262 enable_devtools_(true) {
264 options.Get("backgroundThrottling", &background_throttling_);
266 // FIXME(zcbenz): We should read "type" parameter for better design, but
267 // on Windows we have encountered a compiler bug that if we read "type"
268 // from |options| and then set |type_|, a memory corruption will happen
269 // and Electron will soon crash.
270 // Remvoe this after we upgraded to use VS 2015 Update 3.
272 if (options.Get("isGuest", &b) && b)
274 else if (options.Get("isBackgroundPage", &b) && b)
275 type_ = BACKGROUND_PAGE;
276 else if (options.Get("offscreen", &b) && b)
279 // Whether to enable DevTools.
280 options.Get("devTools", &enable_devtools_);
282 // Obtain the session.
283 std::string partition;
284 mate::Handle<api::Session> session;
285 if (options.Get("session", &session)) {
286 } else if (options.Get("partition", &partition)) {
287 session = Session::FromPartition(isolate, partition);
289 // Use the default session if not specified.
290 session = Session::FromPartition(isolate, "");
292 session_.Reset(isolate, session.ToV8());
294 content::WebContents* web_contents;
296 scoped_refptr<content::SiteInstance> site_instance =
297 content::SiteInstance::CreateForURL(
298 session->browser_context(), GURL("chrome-guest://fake-host"));
299 content::WebContents::CreateParams params(
300 session->browser_context(), site_instance);
301 guest_delegate_.reset(new WebViewGuestDelegate);
302 params.guest_delegate = guest_delegate_.get();
303 web_contents = content::WebContents::Create(params);
304 } else if (IsOffScreen()) {
305 bool transparent = false;
306 options.Get("transparent", &transparent);
308 content::WebContents::CreateParams params(session->browser_context());
309 auto* view = new OffScreenWebContentsView(
310 transparent, base::Bind(&WebContents::OnPaint, base::Unretained(this)));
312 params.delegate_view = view;
314 web_contents = content::WebContents::Create(params);
315 view->SetWebContents(web_contents);
317 content::WebContents::CreateParams params(session->browser_context());
318 web_contents = content::WebContents::Create(params);
321 InitWithSessionAndOptions(isolate, web_contents, session, options);
324 void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
325 content::WebContents *web_contents,
326 mate::Handle<api::Session> session,
327 const mate::Dictionary& options) {
328 Observe(web_contents);
329 InitWithWebContents(web_contents, session->browser_context());
331 managed_web_contents()->GetView()->SetDelegate(this);
333 // Save the preferences in C++.
334 new WebContentsPreferences(web_contents, options);
336 // Intialize permission helper.
337 WebContentsPermissionHelper::CreateForWebContents(web_contents);
338 // Intialize security state client.
339 AtomSecurityStateModelClient::CreateForWebContents(web_contents);
341 web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
344 guest_delegate_->Initialize(this);
346 NativeWindow* owner_window = nullptr;
347 if (options.Get("embedder", &embedder_) && embedder_) {
348 // New WebContents's owner_window is the embedder's owner_window.
350 NativeWindowRelay::FromWebContents(embedder_->web_contents());
352 owner_window = relay->window.get();
355 SetOwnerWindow(owner_window);
359 AttachAsUserData(web_contents);
362 WebContents::~WebContents() {
363 // The destroy() is called.
364 if (managed_web_contents()) {
365 // For webview we need to tell content module to do some cleanup work before
367 if (type_ == WEB_VIEW)
368 guest_delegate_->Destroy();
370 // The WebContentsDestroyed will not be called automatically because we
371 // unsubscribe from webContents before destroying it. So we have to manually
372 // call it here to make sure "destroyed" event is emitted.
373 RenderViewDeleted(web_contents()->GetRenderViewHost());
374 WebContentsDestroyed();
378 bool WebContents::AddMessageToConsole(content::WebContents* source,
380 const base::string16& message,
382 const base::string16& source_id) {
383 if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) {
386 Emit("console-message", level, message, line_no, source_id);
391 void WebContents::OnCreateWindow(
392 const GURL& target_url,
393 const std::string& frame_name,
394 WindowOpenDisposition disposition,
395 const std::vector<std::string>& features,
396 const scoped_refptr<content::ResourceRequestBodyImpl>& body) {
397 if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
398 Emit("-new-window", target_url, frame_name, disposition, features, body);
400 Emit("new-window", target_url, frame_name, disposition, features);
403 void WebContents::WebContentsCreated(content::WebContents* source_contents,
404 int opener_render_frame_id,
405 const std::string& frame_name,
406 const GURL& target_url,
407 content::WebContents* new_contents) {
408 v8::Locker locker(isolate());
409 v8::HandleScope handle_scope(isolate());
410 auto api_web_contents = CreateFrom(isolate(), new_contents, BROWSER_WINDOW);
411 Emit("-web-contents-created", api_web_contents, target_url, frame_name);
414 void WebContents::AddNewContents(content::WebContents* source,
415 content::WebContents* new_contents,
416 WindowOpenDisposition disposition,
417 const gfx::Rect& initial_rect,
420 v8::Locker locker(isolate());
421 v8::HandleScope handle_scope(isolate());
422 auto api_web_contents = CreateFrom(isolate(), new_contents);
423 if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
424 initial_rect.x(), initial_rect.y(), initial_rect.width(),
425 initial_rect.height())) {
426 api_web_contents->DestroyWebContents();
430 content::WebContents* WebContents::OpenURLFromTab(
431 content::WebContents* source,
432 const content::OpenURLParams& params) {
433 if (params.disposition != CURRENT_TAB) {
434 if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
435 Emit("-new-window", params.url, "", params.disposition);
437 Emit("new-window", params.url, "", params.disposition);
441 // Give user a chance to cancel navigation.
442 if (Emit("will-navigate", params.url))
445 // Don't load the URL if the web contents was marked as destroyed from a
446 // will-navigate event listener
450 return CommonWebContentsDelegate::OpenURLFromTab(source, params);
453 void WebContents::BeforeUnloadFired(content::WebContents* tab,
455 bool* proceed_to_fire_unload) {
456 if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
457 *proceed_to_fire_unload = proceed;
459 *proceed_to_fire_unload = true;
462 void WebContents::MoveContents(content::WebContents* source,
463 const gfx::Rect& pos) {
467 void WebContents::CloseContents(content::WebContents* source) {
470 if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
471 owner_window()->CloseContents(source);
474 void WebContents::ActivateContents(content::WebContents* source) {
478 void WebContents::UpdateTargetURL(content::WebContents* source,
480 Emit("update-target-url", url);
483 bool WebContents::IsPopupOrPanel(const content::WebContents* source) const {
484 return type_ == BROWSER_WINDOW;
487 void WebContents::HandleKeyboardEvent(
488 content::WebContents* source,
489 const content::NativeWebKeyboardEvent& event) {
490 if (type_ == WEB_VIEW && embedder_) {
491 // Send the unhandled keyboard events back to the embedder.
492 embedder_->HandleKeyboardEvent(source, event);
494 // Go to the default keyboard handling.
495 CommonWebContentsDelegate::HandleKeyboardEvent(source, event);
499 bool WebContents::PreHandleKeyboardEvent(
500 content::WebContents* source,
501 const content::NativeWebKeyboardEvent& event,
502 bool* is_keyboard_shortcut) {
503 if (event.type == blink::WebInputEvent::Type::RawKeyDown
504 || event.type == blink::WebInputEvent::Type::KeyUp)
505 return Emit("before-input-event", event);
510 void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
511 const GURL& origin) {
512 auto permission_helper =
513 WebContentsPermissionHelper::FromWebContents(source);
514 auto callback = base::Bind(&WebContents::OnEnterFullscreenModeForTab,
515 base::Unretained(this), source, origin);
516 permission_helper->RequestFullscreenPermission(callback);
519 void WebContents::OnEnterFullscreenModeForTab(content::WebContents* source,
524 CommonWebContentsDelegate::EnterFullscreenModeForTab(source, origin);
525 Emit("enter-html-full-screen");
528 void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
529 CommonWebContentsDelegate::ExitFullscreenModeForTab(source);
530 Emit("leave-html-full-screen");
533 void WebContents::RendererUnresponsive(content::WebContents* source) {
534 Emit("unresponsive");
535 if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
536 owner_window()->RendererUnresponsive(source);
539 void WebContents::RendererResponsive(content::WebContents* source) {
541 if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
542 owner_window()->RendererResponsive(source);
545 bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) {
546 if (params.custom_context.is_pepper_menu) {
547 Emit("pepper-context-menu", std::make_pair(params, web_contents()));
548 web_contents()->NotifyContextMenuClosed(params.custom_context);
550 Emit("context-menu", std::make_pair(params, web_contents()));
556 bool WebContents::OnGoToEntryOffset(int offset) {
561 void WebContents::FindReply(content::WebContents* web_contents,
563 int number_of_matches,
564 const gfx::Rect& selection_rect,
565 int active_match_ordinal,
570 v8::Locker locker(isolate());
571 v8::HandleScope handle_scope(isolate());
572 mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate());
573 result.Set("requestId", request_id);
574 result.Set("matches", number_of_matches);
575 result.Set("selectionArea", selection_rect);
576 result.Set("activeMatchOrdinal", active_match_ordinal);
577 result.Set("finalUpdate", final_update); // Deprecate after 2.0
578 Emit("found-in-page", result);
581 bool WebContents::CheckMediaAccessPermission(
582 content::WebContents* web_contents,
583 const GURL& security_origin,
584 content::MediaStreamType type) {
588 void WebContents::RequestMediaAccessPermission(
589 content::WebContents* web_contents,
590 const content::MediaStreamRequest& request,
591 const content::MediaResponseCallback& callback) {
592 auto permission_helper =
593 WebContentsPermissionHelper::FromWebContents(web_contents);
594 permission_helper->RequestMediaAccessPermission(request, callback);
597 void WebContents::RequestToLockMouse(
598 content::WebContents* web_contents,
600 bool last_unlocked_by_target) {
601 auto permission_helper =
602 WebContentsPermissionHelper::FromWebContents(web_contents);
603 permission_helper->RequestPointerLockPermission(user_gesture);
606 std::unique_ptr<content::BluetoothChooser> WebContents::RunBluetoothChooser(
607 content::RenderFrameHost* frame,
608 const content::BluetoothChooser::EventHandler& event_handler) {
609 std::unique_ptr<BluetoothChooser> bluetooth_chooser(
610 new BluetoothChooser(this, event_handler));
611 return std::move(bluetooth_chooser);
614 void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
615 // Do nothing, we override this method just to avoid compilation error since
616 // there are two virtual functions named BeforeUnloadFired.
619 void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) {
620 const auto impl = content::RenderWidgetHostImpl::FromID(
621 render_view_host->GetProcess()->GetID(),
622 render_view_host->GetRoutingID());
624 impl->disable_hidden_ = !background_throttling_;
627 void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
628 Emit("render-view-deleted", render_view_host->GetProcess()->GetID());
631 void WebContents::RenderProcessGone(base::TerminationStatus status) {
632 Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
635 void WebContents::PluginCrashed(const base::FilePath& plugin_path,
636 base::ProcessId plugin_pid) {
637 content::WebPluginInfo info;
638 auto plugin_service = content::PluginService::GetInstance();
639 plugin_service->GetPluginInfoByPath(plugin_path, &info);
640 Emit("plugin-crashed", info.name, info.version);
643 void WebContents::MediaStartedPlaying(const MediaPlayerId& id) {
644 Emit("media-started-playing");
647 void WebContents::MediaStoppedPlaying(const MediaPlayerId& id) {
648 Emit("media-paused");
651 void WebContents::DidChangeThemeColor(SkColor theme_color) {
652 Emit("did-change-theme-color", atom::ToRGBHex(theme_color));
655 void WebContents::DocumentLoadedInFrame(
656 content::RenderFrameHost* render_frame_host) {
657 if (!render_frame_host->GetParent())
661 void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
662 const GURL& validated_url) {
663 bool is_main_frame = !render_frame_host->GetParent();
664 Emit("did-frame-finish-load", is_main_frame);
667 Emit("did-finish-load");
670 void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
673 const base::string16& error_description,
674 bool was_ignored_by_handler) {
675 bool is_main_frame = !render_frame_host->GetParent();
676 Emit("did-fail-load", error_code, error_description, url, is_main_frame);
679 void WebContents::DidStartLoading() {
680 Emit("did-start-loading");
683 void WebContents::DidStopLoading() {
684 Emit("did-stop-loading");
687 void WebContents::DidGetResourceResponseStart(
688 const content::ResourceRequestDetails& details) {
689 Emit("did-get-response-details",
690 details.socket_address.IsEmpty(),
692 details.original_url,
693 details.http_response_code,
696 details.headers.get(),
697 ResourceTypeToString(details.resource_type));
700 void WebContents::DidGetRedirectForResourceRequest(
701 content::RenderFrameHost* render_frame_host,
702 const content::ResourceRedirectDetails& details) {
703 Emit("did-get-redirect-request",
706 (details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME),
707 details.http_response_code,
710 details.headers.get());
713 void WebContents::DidFinishNavigation(
714 content::NavigationHandle* navigation_handle) {
715 bool is_main_frame = navigation_handle->IsInMainFrame();
716 if (navigation_handle->HasCommitted() && !navigation_handle->IsErrorPage()) {
717 auto url = navigation_handle->GetURL();
718 bool is_in_page = navigation_handle->IsSamePage();
719 if (is_main_frame && !is_in_page) {
720 Emit("did-navigate", url);
721 } else if (is_in_page) {
722 Emit("did-navigate-in-page", url, is_main_frame);
725 auto url = navigation_handle->GetURL();
726 int code = navigation_handle->GetNetErrorCode();
727 auto description = net::ErrorToShortString(code);
728 Emit("did-fail-provisional-load", code, description, url, is_main_frame);
730 // Do not emit "did-fail-load" for canceled requests.
731 if (code != net::ERR_ABORTED)
732 Emit("did-fail-load", code, description, url, is_main_frame);
736 void WebContents::TitleWasSet(content::NavigationEntry* entry,
739 Emit("-page-title-updated", entry->GetTitle(), explicit_set);
741 Emit("-page-title-updated", "", explicit_set);
744 void WebContents::DidUpdateFaviconURL(
745 const std::vector<content::FaviconURL>& urls) {
746 std::set<GURL> unique_urls;
747 for (const auto& iter : urls) {
748 if (iter.icon_type != content::FaviconURL::FAVICON)
750 const GURL& url = iter.icon_url;
752 unique_urls.insert(url);
754 Emit("page-favicon-updated", unique_urls);
757 void WebContents::DevToolsReloadPage() {
758 Emit("devtools-reload-page");
761 void WebContents::DevToolsFocused() {
762 Emit("devtools-focused");
765 void WebContents::DevToolsOpened() {
766 v8::Locker locker(isolate());
767 v8::HandleScope handle_scope(isolate());
768 auto handle = WebContents::CreateFrom(
769 isolate(), managed_web_contents()->GetDevToolsWebContents());
770 devtools_web_contents_.Reset(isolate(), handle.ToV8());
772 // Set inspected tabID.
773 base::FundamentalValue tab_id(ID());
774 managed_web_contents()->CallClientFunction(
775 "DevToolsAPI.setInspectedTabId", &tab_id, nullptr, nullptr);
777 // Inherit owner window in devtools.
779 handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(),
782 Emit("devtools-opened");
785 void WebContents::DevToolsClosed() {
786 v8::Locker locker(isolate());
787 v8::HandleScope handle_scope(isolate());
788 devtools_web_contents_.Reset();
790 Emit("devtools-closed");
793 bool WebContents::OnMessageReceived(const IPC::Message& message) {
795 IPC_BEGIN_MESSAGE_MAP(WebContents, message)
796 IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
797 IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
798 OnRendererMessageSync)
799 IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
801 IPC_MESSAGE_UNHANDLED(handled = false)
802 IPC_END_MESSAGE_MAP()
807 // There are three ways of destroying a webContents:
808 // 1. call webContents.destroy();
809 // 2. garbage collection;
810 // 3. user closes the window of webContents;
811 // For webview only #1 will happen, for BrowserWindow both #1 and #3 may
812 // happen. The #2 should never happen for webContents, because webview is
813 // managed by GuestViewManager, and BrowserWindow's webContents is managed
815 // For #1, the destructor will do the cleanup work and we only need to make
816 // sure "destroyed" event is emitted. For #3, the content::WebContents will
817 // be destroyed on close, and WebContentsDestroyed would be called for it, so
818 // we need to make sure the api::WebContents is also deleted.
819 void WebContents::WebContentsDestroyed() {
820 // This event is only for internal use, which is emitted when WebContents is
822 Emit("will-destroy");
824 // Cleanup relationships with other parts.
827 // We can not call Destroy here because we need to call Emit first, but we
828 // also do not want any method to be used, so just mark as destroyed here.
833 // Destroy the native class in next tick.
834 base::ThreadTaskRunnerHandle::Get()->PostTask(
835 FROM_HERE, GetDestroyClosure());
838 void WebContents::NavigationEntryCommitted(
839 const content::LoadCommittedDetails& details) {
840 Emit("navigation-entry-commited", details.entry->GetURL(),
841 details.is_in_page, details.did_replace_entry);
844 int64_t WebContents::GetID() const {
845 int64_t process_id = web_contents()->GetRenderProcessHost()->GetID();
846 int64_t routing_id = web_contents()->GetRoutingID();
847 int64_t rv = (process_id << 32) + routing_id;
851 int WebContents::GetProcessID() const {
852 return web_contents()->GetRenderProcessHost()->GetID();
855 WebContents::Type WebContents::GetType() const {
859 bool WebContents::Equal(const WebContents* web_contents) const {
860 return GetID() == web_contents->GetID();
863 void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
864 if (!url.is_valid() || url.spec().size() > url::kMaxURLChars) {
865 Emit("did-fail-load",
866 static_cast<int>(net::ERR_INVALID_URL),
867 net::ErrorToShortString(net::ERR_INVALID_URL),
868 url.possibly_invalid_spec(),
873 content::NavigationController::LoadURLParams params(url);
876 if (options.Get("httpReferrer", &http_referrer))
877 params.referrer = content::Referrer(http_referrer.GetAsReferrer(),
878 blink::WebReferrerPolicyDefault);
880 std::string user_agent;
881 if (options.Get("userAgent", &user_agent))
882 web_contents()->SetUserAgentOverride(user_agent);
884 std::string extra_headers;
885 if (options.Get("extraHeaders", &extra_headers))
886 params.extra_headers = extra_headers;
888 scoped_refptr<content::ResourceRequestBodyImpl> body;
889 if (options.Get("postData", &body)) {
890 params.post_data = body;
891 params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST;
894 params.transition_type = ui::PAGE_TRANSITION_TYPED;
895 params.should_clear_history_list = true;
896 params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
897 web_contents()->GetController().LoadURLWithParams(params);
899 // Set the background color of RenderWidgetHostView.
900 // We have to call it right after LoadURL because the RenderViewHost is only
901 // created after loading a page.
902 const auto view = web_contents()->GetRenderWidgetHostView();
904 WebContentsPreferences* web_preferences =
905 WebContentsPreferences::FromWebContents(web_contents());
906 std::string color_name;
907 if (web_preferences->web_preferences()->GetString(options::kBackgroundColor,
909 view->SetBackgroundColor(ParseHexColor(color_name));
911 view->SetBackgroundColor(SK_ColorTRANSPARENT);
916 void WebContents::DownloadURL(const GURL& url) {
917 auto browser_context = web_contents()->GetBrowserContext();
918 auto download_manager =
919 content::BrowserContext::GetDownloadManager(browser_context);
921 download_manager->DownloadUrl(
922 content::DownloadUrlParameters::CreateForWebContentsMainFrame(
923 web_contents(), url));
926 GURL WebContents::GetURL() const {
927 return web_contents()->GetURL();
930 base::string16 WebContents::GetTitle() const {
931 return web_contents()->GetTitle();
934 bool WebContents::IsLoading() const {
935 return web_contents()->IsLoading();
938 bool WebContents::IsLoadingMainFrame() const {
939 // Comparing site instances works because Electron always creates a new site
940 // instance when navigating, regardless of origin. See AtomBrowserClient.
941 return (web_contents()->GetLastCommittedURL().is_empty() ||
942 web_contents()->GetSiteInstance() !=
943 web_contents()->GetPendingSiteInstance()) && IsLoading();
946 bool WebContents::IsWaitingForResponse() const {
947 return web_contents()->IsWaitingForResponse();
950 void WebContents::Stop() {
951 web_contents()->Stop();
954 void WebContents::GoBack() {
955 atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
956 web_contents()->GetController().GoBack();
959 void WebContents::GoForward() {
960 atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
961 web_contents()->GetController().GoForward();
964 void WebContents::GoToOffset(int offset) {
965 atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
966 web_contents()->GetController().GoToOffset(offset);
969 bool WebContents::IsCrashed() const {
970 return web_contents()->IsCrashed();
973 void WebContents::SetUserAgent(const std::string& user_agent,
974 mate::Arguments* args) {
975 web_contents()->SetUserAgentOverride(user_agent);
978 std::string WebContents::GetUserAgent() {
979 return web_contents()->GetUserAgentOverride();
982 bool WebContents::SavePage(const base::FilePath& full_file_path,
983 const content::SavePageType& save_type,
984 const SavePageHandler::SavePageCallback& callback) {
985 auto handler = new SavePageHandler(web_contents(), callback);
986 return handler->Handle(full_file_path, save_type);
989 void WebContents::OpenDevTools(mate::Arguments* args) {
993 if (!enable_devtools_)
997 if (type_ == WEB_VIEW || !owner_window()) {
999 } else if (args && args->Length() == 1) {
1000 bool detach = false;
1001 mate::Dictionary options;
1002 if (args->GetNext(&options)) {
1003 options.Get("mode", &state);
1005 // TODO(kevinsawicki) Remove in 2.0
1006 options.Get("detach", &detach);
1007 if (state.empty() && detach)
1011 managed_web_contents()->SetDockState(state);
1012 managed_web_contents()->ShowDevTools();
1015 void WebContents::CloseDevTools() {
1016 if (type_ == REMOTE)
1019 managed_web_contents()->CloseDevTools();
1022 bool WebContents::IsDevToolsOpened() {
1023 if (type_ == REMOTE)
1026 return managed_web_contents()->IsDevToolsViewShowing();
1029 bool WebContents::IsDevToolsFocused() {
1030 if (type_ == REMOTE)
1033 return managed_web_contents()->GetView()->IsDevToolsViewFocused();
1036 void WebContents::EnableDeviceEmulation(
1037 const blink::WebDeviceEmulationParams& params) {
1038 if (type_ == REMOTE)
1041 Send(new ViewMsg_EnableDeviceEmulation(routing_id(), params));
1044 void WebContents::DisableDeviceEmulation() {
1045 if (type_ == REMOTE)
1048 Send(new ViewMsg_DisableDeviceEmulation(routing_id()));
1051 void WebContents::ToggleDevTools() {
1052 if (IsDevToolsOpened())
1055 OpenDevTools(nullptr);
1058 void WebContents::InspectElement(int x, int y) {
1059 if (type_ == REMOTE)
1062 if (!enable_devtools_)
1065 if (!managed_web_contents()->GetDevToolsWebContents())
1066 OpenDevTools(nullptr);
1067 managed_web_contents()->InspectElement(x, y);
1070 void WebContents::InspectServiceWorker() {
1071 if (type_ == REMOTE)
1074 if (!enable_devtools_)
1077 for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
1078 if (agent_host->GetType() ==
1079 content::DevToolsAgentHost::TYPE_SERVICE_WORKER) {
1080 OpenDevTools(nullptr);
1081 managed_web_contents()->AttachTo(agent_host);
1087 void WebContents::HasServiceWorker(
1088 const base::Callback<void(bool)>& callback) {
1089 auto context = GetServiceWorkerContext(web_contents());
1093 context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(),
1098 void WebContents::UnregisterServiceWorker(
1099 const base::Callback<void(bool)>& callback) {
1100 auto context = GetServiceWorkerContext(web_contents());
1104 context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(),
1108 void WebContents::SetAudioMuted(bool muted) {
1109 web_contents()->SetAudioMuted(muted);
1112 bool WebContents::IsAudioMuted() {
1113 return web_contents()->IsAudioMuted();
1116 void WebContents::Print(mate::Arguments* args) {
1117 PrintSettings settings = { false, false };
1118 if (args->Length() == 1 && !args->GetNext(&settings)) {
1123 printing::PrintViewManagerBasic::FromWebContents(web_contents())->
1124 PrintNow(settings.silent, settings.print_background);
1127 void WebContents::PrintToPDF(const base::DictionaryValue& setting,
1128 const PrintToPDFCallback& callback) {
1129 printing::PrintPreviewMessageHandler::FromWebContents(web_contents())->
1130 PrintToPDF(setting, callback);
1133 void WebContents::AddWorkSpace(mate::Arguments* args,
1134 const base::FilePath& path) {
1136 args->ThrowError("path cannot be empty");
1139 DevToolsAddFileSystem(path);
1142 void WebContents::RemoveWorkSpace(mate::Arguments* args,
1143 const base::FilePath& path) {
1145 args->ThrowError("path cannot be empty");
1148 DevToolsRemoveFileSystem(path);
1151 void WebContents::Undo() {
1152 web_contents()->Undo();
1155 void WebContents::Redo() {
1156 web_contents()->Redo();
1159 void WebContents::Cut() {
1160 web_contents()->Cut();
1163 void WebContents::Copy() {
1164 web_contents()->Copy();
1167 void WebContents::Paste() {
1168 web_contents()->Paste();
1171 void WebContents::PasteAndMatchStyle() {
1172 web_contents()->PasteAndMatchStyle();
1175 void WebContents::Delete() {
1176 web_contents()->Delete();
1179 void WebContents::SelectAll() {
1180 web_contents()->SelectAll();
1183 void WebContents::Unselect() {
1184 web_contents()->Unselect();
1187 void WebContents::Replace(const base::string16& word) {
1188 web_contents()->Replace(word);
1191 void WebContents::ReplaceMisspelling(const base::string16& word) {
1192 web_contents()->ReplaceMisspelling(word);
1195 uint32_t WebContents::FindInPage(mate::Arguments* args) {
1196 uint32_t request_id = GetNextRequestId();
1197 base::string16 search_text;
1198 blink::WebFindOptions options;
1199 if (!args->GetNext(&search_text) || search_text.empty()) {
1200 args->ThrowError("Must provide a non-empty search content");
1204 args->GetNext(&options);
1206 web_contents()->Find(request_id, search_text, options);
1210 void WebContents::StopFindInPage(content::StopFindAction action) {
1211 web_contents()->StopFinding(action);
1214 void WebContents::ShowDefinitionForSelection() {
1215 #if defined(OS_MACOSX)
1216 const auto view = web_contents()->GetRenderWidgetHostView();
1218 view->ShowDefinitionForSelection();
1222 void WebContents::CopyImageAt(int x, int y) {
1223 const auto host = web_contents()->GetMainFrame();
1225 host->CopyImageAt(x, y);
1228 void WebContents::Focus() {
1229 web_contents()->Focus();
1232 #if !defined(OS_MACOSX)
1233 bool WebContents::IsFocused() const {
1234 auto view = web_contents()->GetRenderWidgetHostView();
1235 if (!view) return false;
1237 if (GetType() != BACKGROUND_PAGE) {
1238 auto window = web_contents()->GetNativeView()->GetToplevelWindow();
1239 if (window && !window->IsVisible())
1243 return view->HasFocus();
1247 void WebContents::TabTraverse(bool reverse) {
1248 web_contents()->FocusThroughTabTraversal(reverse);
1251 bool WebContents::SendIPCMessage(bool all_frames,
1252 const base::string16& channel,
1253 const base::ListValue& args) {
1254 return Send(new AtomViewMsg_Message(routing_id(), all_frames, channel, args));
1257 void WebContents::SendInputEvent(v8::Isolate* isolate,
1258 v8::Local<v8::Value> input_event) {
1259 const auto view = web_contents()->GetRenderWidgetHostView();
1262 const auto host = view->GetRenderWidgetHost();
1266 int type = mate::GetWebInputEventType(isolate, input_event);
1267 if (blink::WebInputEvent::isMouseEventType(type)) {
1268 blink::WebMouseEvent mouse_event;
1269 if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) {
1270 host->ForwardMouseEvent(mouse_event);
1273 } else if (blink::WebInputEvent::isKeyboardEventType(type)) {
1274 content::NativeWebKeyboardEvent keyboard_event;
1275 if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) {
1276 host->ForwardKeyboardEvent(keyboard_event);
1279 } else if (type == blink::WebInputEvent::MouseWheel) {
1280 blink::WebMouseWheelEvent mouse_wheel_event;
1281 if (mate::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) {
1282 host->ForwardWheelEvent(mouse_wheel_event);
1287 isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
1288 isolate, "Invalid event object")));
1291 void WebContents::BeginFrameSubscription(mate::Arguments* args) {
1292 bool only_dirty = false;
1293 FrameSubscriber::FrameCaptureCallback callback;
1295 args->GetNext(&only_dirty);
1296 if (!args->GetNext(&callback)) {
1301 const auto view = web_contents()->GetRenderWidgetHostView();
1303 std::unique_ptr<FrameSubscriber> frame_subscriber(new FrameSubscriber(
1304 isolate(), view, callback, only_dirty));
1305 view->BeginFrameSubscription(std::move(frame_subscriber));
1309 void WebContents::EndFrameSubscription() {
1310 const auto view = web_contents()->GetRenderWidgetHostView();
1312 view->EndFrameSubscription();
1315 void WebContents::StartDrag(const mate::Dictionary& item,
1316 mate::Arguments* args) {
1317 base::FilePath file;
1318 std::vector<base::FilePath> files;
1319 if (!item.Get("files", &files) && item.Get("file", &file)) {
1320 files.push_back(file);
1323 mate::Handle<NativeImage> icon;
1324 if (!item.Get("icon", &icon) && !file.empty()) {
1325 // TODO(zcbenz): Set default icon from file.
1329 if (icon.IsEmpty()) {
1330 args->ThrowError("Must specify 'icon' option");
1334 #if defined(OS_MACOSX)
1335 // NSWindow.dragImage requires a non-empty NSImage
1336 if (icon->image().IsEmpty()) {
1337 args->ThrowError("Must specify non-empty 'icon' option");
1343 if (!files.empty()) {
1344 base::MessageLoop::ScopedNestableTaskAllower allow(
1345 base::MessageLoop::current());
1346 DragFileItems(files, icon->image(), web_contents()->GetNativeView());
1348 args->ThrowError("Must specify either 'file' or 'files' option");
1352 void WebContents::CapturePage(mate::Arguments* args) {
1354 base::Callback<void(const gfx::Image&)> callback;
1356 if (!(args->Length() == 1 && args->GetNext(&callback)) &&
1357 !(args->Length() == 2 && args->GetNext(&rect)
1358 && args->GetNext(&callback))) {
1363 const auto view = web_contents()->GetRenderWidgetHostView();
1364 const auto host = view ? view->GetRenderWidgetHost() : nullptr;
1365 if (!view || !host) {
1366 callback.Run(gfx::Image());
1370 // Capture full page if user doesn't specify a |rect|.
1371 const gfx::Size view_size = rect.IsEmpty() ? view->GetViewBounds().size() :
1374 // By default, the requested bitmap size is the view size in screen
1375 // coordinates. However, if there's more pixel detail available on the
1376 // current system, increase the requested bitmap size to capture it all.
1377 gfx::Size bitmap_size = view_size;
1378 const gfx::NativeView native_view = view->GetNativeView();
1380 display::Screen::GetScreen()->GetDisplayNearestWindow(native_view)
1381 .device_scale_factor();
1383 bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
1385 host->CopyFromBackingStore(gfx::Rect(rect.origin(), view_size),
1387 base::Bind(&OnCapturePageDone, callback),
1388 kBGRA_8888_SkColorType);
1391 void WebContents::OnCursorChange(const content::WebCursor& cursor) {
1392 content::WebCursor::CursorInfo info;
1393 cursor.GetCursorInfo(&info);
1395 if (cursor.IsCustom()) {
1396 Emit("cursor-changed", CursorTypeToString(info),
1397 gfx::Image::CreateFrom1xBitmap(info.custom_image),
1398 info.image_scale_factor,
1399 gfx::Size(info.custom_image.width(), info.custom_image.height()),
1402 Emit("cursor-changed", CursorTypeToString(info));
1406 void WebContents::SetSize(const SetSizeParams& params) {
1407 if (guest_delegate_)
1408 guest_delegate_->SetSize(params);
1411 bool WebContents::IsGuest() const {
1412 return type_ == WEB_VIEW;
1415 bool WebContents::IsOffScreen() const {
1416 return type_ == OFF_SCREEN;
1419 void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) {
1420 mate::Handle<NativeImage> image =
1421 NativeImage::Create(isolate(), gfx::Image::CreateFrom1xBitmap(bitmap));
1422 Emit("paint", dirty_rect, image);
1425 void WebContents::StartPainting() {
1429 auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1430 web_contents()->GetRenderWidgetHostView());
1432 osr_rwhv->SetPainting(true);
1435 void WebContents::StopPainting() {
1439 auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1440 web_contents()->GetRenderWidgetHostView());
1442 osr_rwhv->SetPainting(false);
1445 bool WebContents::IsPainting() const {
1449 const auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1450 web_contents()->GetRenderWidgetHostView());
1451 return osr_rwhv && osr_rwhv->IsPainting();
1454 void WebContents::SetFrameRate(int frame_rate) {
1458 auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1459 web_contents()->GetRenderWidgetHostView());
1461 osr_rwhv->SetFrameRate(frame_rate);
1464 int WebContents::GetFrameRate() const {
1468 const auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1469 web_contents()->GetRenderWidgetHostView());
1470 return osr_rwhv ? osr_rwhv->GetFrameRate() : 0;
1473 void WebContents::Invalidate() {
1477 auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1478 web_contents()->GetRenderWidgetHostView());
1480 osr_rwhv->Invalidate();
1483 v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
1484 WebContentsPreferences* web_preferences =
1485 WebContentsPreferences::FromWebContents(web_contents());
1486 return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
1489 v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() {
1491 return Window::From(isolate(), owner_window());
1493 return v8::Null(isolate());
1496 int32_t WebContents::ID() const {
1497 return weak_map_id();
1500 v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
1501 return v8::Local<v8::Value>::New(isolate, session_);
1504 content::WebContents* WebContents::HostWebContents() {
1507 return embedder_->web_contents();
1510 void WebContents::SetEmbedder(const WebContents* embedder) {
1512 NativeWindow* owner_window = nullptr;
1513 auto relay = NativeWindowRelay::FromWebContents(embedder->web_contents());
1515 owner_window = relay->window.get();
1518 SetOwnerWindow(owner_window);
1520 content::RenderWidgetHostView* rwhv =
1521 web_contents()->GetRenderWidgetHostView();
1529 v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
1530 if (devtools_web_contents_.IsEmpty())
1531 return v8::Null(isolate);
1533 return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
1536 v8::Local<v8::Value> WebContents::Debugger(v8::Isolate* isolate) {
1537 if (debugger_.IsEmpty()) {
1538 auto handle = atom::api::Debugger::Create(isolate, web_contents());
1539 debugger_.Reset(isolate, handle.ToV8());
1541 return v8::Local<v8::Value>::New(isolate, debugger_);
1545 void WebContents::BuildPrototype(v8::Isolate* isolate,
1546 v8::Local<v8::FunctionTemplate> prototype) {
1547 prototype->SetClassName(mate::StringToV8(isolate, "WebContents"));
1548 mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
1550 .SetMethod("getId", &WebContents::GetID)
1551 .SetMethod("getProcessId", &WebContents::GetProcessID)
1552 .SetMethod("equal", &WebContents::Equal)
1553 .SetMethod("_loadURL", &WebContents::LoadURL)
1554 .SetMethod("downloadURL", &WebContents::DownloadURL)
1555 .SetMethod("_getURL", &WebContents::GetURL)
1556 .SetMethod("getTitle", &WebContents::GetTitle)
1557 .SetMethod("isLoading", &WebContents::IsLoading)
1558 .SetMethod("isLoadingMainFrame", &WebContents::IsLoadingMainFrame)
1559 .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
1560 .SetMethod("_stop", &WebContents::Stop)
1561 .SetMethod("_goBack", &WebContents::GoBack)
1562 .SetMethod("_goForward", &WebContents::GoForward)
1563 .SetMethod("_goToOffset", &WebContents::GoToOffset)
1564 .SetMethod("isCrashed", &WebContents::IsCrashed)
1565 .SetMethod("setUserAgent", &WebContents::SetUserAgent)
1566 .SetMethod("getUserAgent", &WebContents::GetUserAgent)
1567 .SetMethod("savePage", &WebContents::SavePage)
1568 .SetMethod("openDevTools", &WebContents::OpenDevTools)
1569 .SetMethod("closeDevTools", &WebContents::CloseDevTools)
1570 .SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
1571 .SetMethod("isDevToolsFocused", &WebContents::IsDevToolsFocused)
1572 .SetMethod("enableDeviceEmulation",
1573 &WebContents::EnableDeviceEmulation)
1574 .SetMethod("disableDeviceEmulation",
1575 &WebContents::DisableDeviceEmulation)
1576 .SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
1577 .SetMethod("inspectElement", &WebContents::InspectElement)
1578 .SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
1579 .SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
1580 .SetMethod("undo", &WebContents::Undo)
1581 .SetMethod("redo", &WebContents::Redo)
1582 .SetMethod("cut", &WebContents::Cut)
1583 .SetMethod("copy", &WebContents::Copy)
1584 .SetMethod("paste", &WebContents::Paste)
1585 .SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
1586 .SetMethod("delete", &WebContents::Delete)
1587 .SetMethod("selectAll", &WebContents::SelectAll)
1588 .SetMethod("unselect", &WebContents::Unselect)
1589 .SetMethod("replace", &WebContents::Replace)
1590 .SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
1591 .SetMethod("findInPage", &WebContents::FindInPage)
1592 .SetMethod("stopFindInPage", &WebContents::StopFindInPage)
1593 .SetMethod("focus", &WebContents::Focus)
1594 .SetMethod("isFocused", &WebContents::IsFocused)
1595 .SetMethod("tabTraverse", &WebContents::TabTraverse)
1596 .SetMethod("_send", &WebContents::SendIPCMessage)
1597 .SetMethod("sendInputEvent", &WebContents::SendInputEvent)
1598 .SetMethod("beginFrameSubscription",
1599 &WebContents::BeginFrameSubscription)
1600 .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
1601 .SetMethod("startDrag", &WebContents::StartDrag)
1602 .SetMethod("setSize", &WebContents::SetSize)
1603 .SetMethod("isGuest", &WebContents::IsGuest)
1604 .SetMethod("isOffscreen", &WebContents::IsOffScreen)
1605 .SetMethod("startPainting", &WebContents::StartPainting)
1606 .SetMethod("stopPainting", &WebContents::StopPainting)
1607 .SetMethod("isPainting", &WebContents::IsPainting)
1608 .SetMethod("setFrameRate", &WebContents::SetFrameRate)
1609 .SetMethod("getFrameRate", &WebContents::GetFrameRate)
1610 .SetMethod("invalidate", &WebContents::Invalidate)
1611 .SetMethod("getType", &WebContents::GetType)
1612 .SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
1613 .SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
1614 .SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
1615 .SetMethod("unregisterServiceWorker",
1616 &WebContents::UnregisterServiceWorker)
1617 .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
1618 .SetMethod("print", &WebContents::Print)
1619 .SetMethod("_printToPDF", &WebContents::PrintToPDF)
1620 .SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
1621 .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
1622 .SetMethod("showDefinitionForSelection",
1623 &WebContents::ShowDefinitionForSelection)
1624 .SetMethod("copyImageAt", &WebContents::CopyImageAt)
1625 .SetMethod("capturePage", &WebContents::CapturePage)
1626 .SetMethod("setEmbedder", &WebContents::SetEmbedder)
1627 .SetProperty("id", &WebContents::ID)
1628 .SetProperty("session", &WebContents::Session)
1629 .SetProperty("hostWebContents", &WebContents::HostWebContents)
1630 .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents)
1631 .SetProperty("debugger", &WebContents::Debugger);
1634 AtomBrowserContext* WebContents::GetBrowserContext() const {
1635 return static_cast<AtomBrowserContext*>(web_contents()->GetBrowserContext());
1638 void WebContents::OnRendererMessage(const base::string16& channel,
1639 const base::ListValue& args) {
1640 // webContents.emit(channel, new Event(), args...);
1641 Emit(base::UTF16ToUTF8(channel), args);
1644 void WebContents::OnRendererMessageSync(const base::string16& channel,
1645 const base::ListValue& args,
1646 IPC::Message* message) {
1647 // webContents.emit(channel, new Event(sender, message), args...);
1648 EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args);
1652 mate::Handle<WebContents> WebContents::CreateFrom(
1653 v8::Isolate* isolate, content::WebContents* web_contents) {
1654 // We have an existing WebContents object in JS.
1655 auto existing = TrackableObject::FromWrappedClass(isolate, web_contents);
1657 return mate::CreateHandle(isolate, static_cast<WebContents*>(existing));
1659 // Otherwise create a new WebContents wrapper object.
1660 return mate::CreateHandle(isolate, new WebContents(isolate, web_contents,
1664 mate::Handle<WebContents> WebContents::CreateFrom(
1665 v8::Isolate* isolate, content::WebContents* web_contents, Type type) {
1666 // Otherwise create a new WebContents wrapper object.
1667 return mate::CreateHandle(isolate, new WebContents(isolate, web_contents,
1672 mate::Handle<WebContents> WebContents::Create(
1673 v8::Isolate* isolate, const mate::Dictionary& options) {
1674 return mate::CreateHandle(isolate, new WebContents(isolate, options));
1683 using atom::api::WebContents;
1685 void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
1686 v8::Local<v8::Context> context, void* priv) {
1687 v8::Isolate* isolate = context->GetIsolate();
1688 mate::Dictionary dict(isolate, exports);
1689 dict.Set("WebContents", WebContents::GetConstructor(isolate)->GetFunction());
1690 dict.SetMethod("create", &WebContents::Create);
1691 dict.SetMethod("fromId", &mate::TrackableObject<WebContents>::FromWeakMapID);
1692 dict.SetMethod("getAllWebContents",
1693 &mate::TrackableObject<WebContents>::GetAll);
1698 NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_web_contents, Initialize)