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/lib/bluetooth_chooser.h"
17 #include "atom/browser/native_window.h"
18 #include "atom/browser/net/atom_network_delegate.h"
19 #include "atom/browser/osr/osr_output_device.h"
20 #include "atom/browser/osr/osr_render_widget_host_view.h"
21 #include "atom/browser/osr/osr_web_contents_view.h"
22 #include "atom/browser/ui/drag_util.h"
23 #include "atom/browser/web_contents_permission_helper.h"
24 #include "atom/browser/web_contents_preferences.h"
25 #include "atom/browser/web_contents_zoom_controller.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 "chrome/browser/ssl/security_state_tab_helper.h"
49 #include "content/browser/renderer_host/render_widget_host_impl.h"
50 #include "content/browser/web_contents/web_contents_impl.h"
51 #include "content/common/view_messages.h"
52 #include "content/public/browser/favicon_status.h"
53 #include "content/public/browser/native_web_keyboard_event.h"
54 #include "content/public/browser/navigation_details.h"
55 #include "content/public/browser/navigation_entry.h"
56 #include "content/public/browser/navigation_handle.h"
57 #include "content/public/browser/plugin_service.h"
58 #include "content/public/browser/render_frame_host.h"
59 #include "content/public/browser/render_process_host.h"
60 #include "content/public/browser/render_view_host.h"
61 #include "content/public/browser/render_widget_host.h"
62 #include "content/public/browser/render_widget_host_view.h"
63 #include "content/public/browser/resource_request_details.h"
64 #include "content/public/browser/service_worker_context.h"
65 #include "content/public/browser/site_instance.h"
66 #include "content/public/browser/storage_partition.h"
67 #include "content/public/browser/web_contents.h"
68 #include "content/public/common/context_menu_params.h"
69 #include "native_mate/dictionary.h"
70 #include "native_mate/object_template_builder.h"
71 #include "net/url_request/url_request_context.h"
72 #include "third_party/WebKit/public/platform/WebInputEvent.h"
73 #include "third_party/WebKit/public/web/WebFindOptions.h"
74 #include "ui/display/screen.h"
76 #if !defined(OS_MACOSX)
77 #include "ui/aura/window.h"
80 #include "atom/common/node_includes.h"
84 struct PrintSettings {
86 bool print_background;
94 struct Converter<atom::SetSizeParams> {
95 static bool FromV8(v8::Isolate* isolate,
96 v8::Local<v8::Value> val,
97 atom::SetSizeParams* out) {
98 mate::Dictionary params;
99 if (!ConvertFromV8(isolate, val, ¶ms))
102 if (params.Get("enableAutoSize", &autosize))
103 out->enable_auto_size.reset(new bool(true));
105 if (params.Get("min", &size))
106 out->min_size.reset(new gfx::Size(size));
107 if (params.Get("max", &size))
108 out->max_size.reset(new gfx::Size(size));
109 if (params.Get("normal", &size))
110 out->normal_size.reset(new gfx::Size(size));
116 struct Converter<PrintSettings> {
117 static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
118 PrintSettings* out) {
119 mate::Dictionary dict;
120 if (!ConvertFromV8(isolate, val, &dict))
122 dict.Get("silent", &(out->silent));
123 dict.Get("printBackground", &(out->print_background));
129 struct Converter<WindowOpenDisposition> {
130 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
131 WindowOpenDisposition val) {
132 std::string disposition = "other";
134 case WindowOpenDisposition::CURRENT_TAB:
135 disposition = "default";
137 case WindowOpenDisposition::NEW_FOREGROUND_TAB:
138 disposition = "foreground-tab";
140 case WindowOpenDisposition::NEW_BACKGROUND_TAB:
141 disposition = "background-tab";
143 case WindowOpenDisposition::NEW_POPUP:
144 case WindowOpenDisposition::NEW_WINDOW:
145 disposition = "new-window";
147 case WindowOpenDisposition::SAVE_TO_DISK:
148 disposition = "save-to-disk";
153 return mate::ConvertToV8(isolate, disposition);
158 struct Converter<content::SavePageType> {
159 static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
160 content::SavePageType* out) {
161 std::string save_type;
162 if (!ConvertFromV8(isolate, val, &save_type))
164 save_type = base::ToLowerASCII(save_type);
165 if (save_type == "htmlonly") {
166 *out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
167 } else if (save_type == "htmlcomplete") {
168 *out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
169 } else if (save_type == "mhtml") {
170 *out = content::SAVE_PAGE_TYPE_AS_MHTML;
179 struct Converter<atom::api::WebContents::Type> {
180 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
181 atom::api::WebContents::Type val) {
182 using Type = atom::api::WebContents::Type;
183 std::string type = "";
185 case Type::BACKGROUND_PAGE: type = "backgroundPage"; break;
186 case Type::BROWSER_WINDOW: type = "window"; break;
187 case Type::REMOTE: type = "remote"; break;
188 case Type::WEB_VIEW: type = "webview"; break;
189 case Type::OFF_SCREEN: type = "offscreen"; break;
192 return mate::ConvertToV8(isolate, type);
195 static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
196 atom::api::WebContents::Type* out) {
197 using Type = atom::api::WebContents::Type;
199 if (!ConvertFromV8(isolate, val, &type))
201 if (type == "webview") {
202 *out = Type::WEB_VIEW;
203 } else if (type == "backgroundPage") {
204 *out = Type::BACKGROUND_PAGE;
205 } else if (type == "offscreen") {
206 *out = Type::OFF_SCREEN;
223 content::ServiceWorkerContext* GetServiceWorkerContext(
224 const content::WebContents* web_contents) {
225 auto context = web_contents->GetBrowserContext();
226 auto site_instance = web_contents->GetSiteInstance();
227 if (!context || !site_instance)
230 auto storage_partition =
231 content::BrowserContext::GetStoragePartition(context, site_instance);
232 if (!storage_partition)
235 return storage_partition->GetServiceWorkerContext();
238 // Called when CapturePage is done.
239 void OnCapturePageDone(base::Callback<void(const gfx::Image&)> callback,
240 const SkBitmap& bitmap,
241 content::ReadbackResponse response) {
242 callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
247 WebContents::WebContents(v8::Isolate* isolate,
248 content::WebContents* web_contents,
250 : content::WebContentsObserver(web_contents),
252 zoom_controller_(nullptr),
255 background_throttling_(true),
256 enable_devtools_(true) {
257 if (type == REMOTE) {
258 web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
260 AttachAsUserData(web_contents);
262 const mate::Dictionary options = mate::Dictionary::CreateEmpty(isolate);
263 auto session = Session::CreateFrom(isolate, GetBrowserContext());
264 session_.Reset(isolate, session.ToV8());
265 InitWithSessionAndOptions(isolate, web_contents, session, options);
269 WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
270 : embedder_(nullptr),
271 zoom_controller_(nullptr),
272 type_(BROWSER_WINDOW),
274 background_throttling_(true),
275 enable_devtools_(true) {
277 options.Get("backgroundThrottling", &background_throttling_);
279 // FIXME(zcbenz): We should read "type" parameter for better design, but
280 // on Windows we have encountered a compiler bug that if we read "type"
281 // from |options| and then set |type_|, a memory corruption will happen
282 // and Electron will soon crash.
283 // Remvoe this after we upgraded to use VS 2015 Update 3.
285 if (options.Get("isGuest", &b) && b)
287 else if (options.Get("isBackgroundPage", &b) && b)
288 type_ = BACKGROUND_PAGE;
289 else if (options.Get("offscreen", &b) && b)
292 // Whether to enable DevTools.
293 options.Get("devTools", &enable_devtools_);
295 // Obtain the session.
296 std::string partition;
297 mate::Handle<api::Session> session;
298 if (options.Get("session", &session)) {
299 } else if (options.Get("partition", &partition)) {
300 session = Session::FromPartition(isolate, partition);
302 // Use the default session if not specified.
303 session = Session::FromPartition(isolate, "");
305 session_.Reset(isolate, session.ToV8());
307 content::WebContents* web_contents;
309 scoped_refptr<content::SiteInstance> site_instance =
310 content::SiteInstance::CreateForURL(
311 session->browser_context(), GURL("chrome-guest://fake-host"));
312 content::WebContents::CreateParams params(
313 session->browser_context(), site_instance);
314 guest_delegate_.reset(new WebViewGuestDelegate);
315 params.guest_delegate = guest_delegate_.get();
316 web_contents = content::WebContents::Create(params);
317 } else if (IsOffScreen()) {
318 bool transparent = false;
319 options.Get("transparent", &transparent);
321 content::WebContents::CreateParams params(session->browser_context());
322 auto* view = new OffScreenWebContentsView(
323 transparent, base::Bind(&WebContents::OnPaint, base::Unretained(this)));
325 params.delegate_view = view;
327 web_contents = content::WebContents::Create(params);
328 view->SetWebContents(web_contents);
330 content::WebContents::CreateParams params(session->browser_context());
331 web_contents = content::WebContents::Create(params);
334 InitWithSessionAndOptions(isolate, web_contents, session, options);
337 void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
338 content::WebContents *web_contents,
339 mate::Handle<api::Session> session,
340 const mate::Dictionary& options) {
341 Observe(web_contents);
342 InitWithWebContents(web_contents, session->browser_context());
344 managed_web_contents()->GetView()->SetDelegate(this);
346 // Save the preferences in C++.
347 new WebContentsPreferences(web_contents, options);
349 // Initialize permission helper.
350 WebContentsPermissionHelper::CreateForWebContents(web_contents);
351 // Initialize security state client.
352 SecurityStateTabHelper::CreateForWebContents(web_contents);
353 // Initialize zoom controller.
354 WebContentsZoomController::CreateForWebContents(web_contents);
355 zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents);
357 if (options.Get(options::kZoomFactor, &zoom_factor))
358 zoom_controller_->SetDefaultZoomFactor(zoom_factor);
360 web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
363 guest_delegate_->Initialize(this);
365 NativeWindow* owner_window = nullptr;
366 if (options.Get("embedder", &embedder_) && embedder_) {
367 // New WebContents's owner_window is the embedder's owner_window.
369 NativeWindowRelay::FromWebContents(embedder_->web_contents());
371 owner_window = relay->window.get();
374 SetOwnerWindow(owner_window);
378 AttachAsUserData(web_contents);
381 WebContents::~WebContents() {
382 // The destroy() is called.
383 if (managed_web_contents()) {
384 // For webview we need to tell content module to do some cleanup work before
386 if (type_ == WEB_VIEW)
387 guest_delegate_->Destroy();
389 // The WebContentsDestroyed will not be called automatically because we
390 // unsubscribe from webContents before destroying it. So we have to manually
391 // call it here to make sure "destroyed" event is emitted.
392 RenderViewDeleted(web_contents()->GetRenderViewHost());
393 WebContentsDestroyed();
397 bool WebContents::DidAddMessageToConsole(content::WebContents* source,
399 const base::string16& message,
401 const base::string16& source_id) {
402 if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) {
405 Emit("console-message", level, message, line_no, source_id);
410 void WebContents::OnCreateWindow(
411 const GURL& target_url,
412 const std::string& frame_name,
413 WindowOpenDisposition disposition,
414 const std::vector<std::string>& features,
415 const scoped_refptr<content::ResourceRequestBodyImpl>& body) {
416 if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
417 Emit("-new-window", target_url, frame_name, disposition, features, body);
419 Emit("new-window", target_url, frame_name, disposition, features);
422 void WebContents::WebContentsCreated(content::WebContents* source_contents,
423 int opener_render_process_id,
424 int opener_render_frame_id,
425 const std::string& frame_name,
426 const GURL& target_url,
427 content::WebContents* new_contents) {
428 v8::Locker locker(isolate());
429 v8::HandleScope handle_scope(isolate());
430 auto api_web_contents = CreateFrom(isolate(), new_contents, BROWSER_WINDOW);
431 Emit("-web-contents-created", api_web_contents, target_url, frame_name);
434 void WebContents::AddNewContents(content::WebContents* source,
435 content::WebContents* new_contents,
436 WindowOpenDisposition disposition,
437 const gfx::Rect& initial_rect,
440 v8::Locker locker(isolate());
441 v8::HandleScope handle_scope(isolate());
442 auto api_web_contents = CreateFrom(isolate(), new_contents);
443 if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
444 initial_rect.x(), initial_rect.y(), initial_rect.width(),
445 initial_rect.height())) {
446 api_web_contents->DestroyWebContents();
450 content::WebContents* WebContents::OpenURLFromTab(
451 content::WebContents* source,
452 const content::OpenURLParams& params) {
453 if (params.disposition != WindowOpenDisposition::CURRENT_TAB) {
454 if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
455 Emit("-new-window", params.url, "", params.disposition);
457 Emit("new-window", params.url, "", params.disposition);
461 // Give user a chance to cancel navigation.
462 if (Emit("will-navigate", params.url))
465 // Don't load the URL if the web contents was marked as destroyed from a
466 // will-navigate event listener
470 return CommonWebContentsDelegate::OpenURLFromTab(source, params);
473 void WebContents::BeforeUnloadFired(content::WebContents* tab,
475 bool* proceed_to_fire_unload) {
476 if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
477 *proceed_to_fire_unload = proceed;
479 *proceed_to_fire_unload = true;
482 void WebContents::MoveContents(content::WebContents* source,
483 const gfx::Rect& pos) {
487 void WebContents::CloseContents(content::WebContents* source) {
490 if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
491 owner_window()->CloseContents(source);
494 void WebContents::ActivateContents(content::WebContents* source) {
498 void WebContents::UpdateTargetURL(content::WebContents* source,
500 Emit("update-target-url", url);
503 bool WebContents::IsPopupOrPanel(const content::WebContents* source) const {
504 return type_ == BROWSER_WINDOW;
507 void WebContents::HandleKeyboardEvent(
508 content::WebContents* source,
509 const content::NativeWebKeyboardEvent& event) {
510 if (type_ == WEB_VIEW && embedder_) {
511 // Send the unhandled keyboard events back to the embedder.
512 embedder_->HandleKeyboardEvent(source, event);
514 // Go to the default keyboard handling.
515 CommonWebContentsDelegate::HandleKeyboardEvent(source, event);
519 bool WebContents::PreHandleKeyboardEvent(
520 content::WebContents* source,
521 const content::NativeWebKeyboardEvent& event,
522 bool* is_keyboard_shortcut) {
523 if (event.type == blink::WebInputEvent::Type::RawKeyDown
524 || event.type == blink::WebInputEvent::Type::KeyUp)
525 return Emit("before-input-event", event);
530 void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
531 const GURL& origin) {
532 auto permission_helper =
533 WebContentsPermissionHelper::FromWebContents(source);
534 auto callback = base::Bind(&WebContents::OnEnterFullscreenModeForTab,
535 base::Unretained(this), source, origin);
536 permission_helper->RequestFullscreenPermission(callback);
539 void WebContents::OnEnterFullscreenModeForTab(content::WebContents* source,
544 CommonWebContentsDelegate::EnterFullscreenModeForTab(source, origin);
545 Emit("enter-html-full-screen");
548 void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
549 CommonWebContentsDelegate::ExitFullscreenModeForTab(source);
550 Emit("leave-html-full-screen");
553 void WebContents::RendererUnresponsive(
554 content::WebContents* source,
555 const content::WebContentsUnresponsiveState& unresponsive_state) {
556 Emit("unresponsive");
557 if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
558 owner_window()->RendererUnresponsive(source);
561 void WebContents::RendererResponsive(content::WebContents* source) {
563 if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
564 owner_window()->RendererResponsive(source);
567 bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) {
568 if (params.custom_context.is_pepper_menu) {
569 Emit("pepper-context-menu", std::make_pair(params, web_contents()));
570 web_contents()->NotifyContextMenuClosed(params.custom_context);
572 Emit("context-menu", std::make_pair(params, web_contents()));
578 bool WebContents::OnGoToEntryOffset(int offset) {
583 void WebContents::FindReply(content::WebContents* web_contents,
585 int number_of_matches,
586 const gfx::Rect& selection_rect,
587 int active_match_ordinal,
592 v8::Locker locker(isolate());
593 v8::HandleScope handle_scope(isolate());
594 mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate());
595 result.Set("requestId", request_id);
596 result.Set("matches", number_of_matches);
597 result.Set("selectionArea", selection_rect);
598 result.Set("activeMatchOrdinal", active_match_ordinal);
599 result.Set("finalUpdate", final_update); // Deprecate after 2.0
600 Emit("found-in-page", result);
603 bool WebContents::CheckMediaAccessPermission(
604 content::WebContents* web_contents,
605 const GURL& security_origin,
606 content::MediaStreamType type) {
610 void WebContents::RequestMediaAccessPermission(
611 content::WebContents* web_contents,
612 const content::MediaStreamRequest& request,
613 const content::MediaResponseCallback& callback) {
614 auto permission_helper =
615 WebContentsPermissionHelper::FromWebContents(web_contents);
616 permission_helper->RequestMediaAccessPermission(request, callback);
619 void WebContents::RequestToLockMouse(
620 content::WebContents* web_contents,
622 bool last_unlocked_by_target) {
623 auto permission_helper =
624 WebContentsPermissionHelper::FromWebContents(web_contents);
625 permission_helper->RequestPointerLockPermission(user_gesture);
628 std::unique_ptr<content::BluetoothChooser> WebContents::RunBluetoothChooser(
629 content::RenderFrameHost* frame,
630 const content::BluetoothChooser::EventHandler& event_handler) {
631 std::unique_ptr<BluetoothChooser> bluetooth_chooser(
632 new BluetoothChooser(this, event_handler));
633 return std::move(bluetooth_chooser);
636 void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
637 // Do nothing, we override this method just to avoid compilation error since
638 // there are two virtual functions named BeforeUnloadFired.
641 void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) {
642 const auto impl = content::RenderWidgetHostImpl::FromID(
643 render_view_host->GetProcess()->GetID(),
644 render_view_host->GetRoutingID());
646 impl->disable_hidden_ = !background_throttling_;
649 void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
650 Emit("render-view-deleted", render_view_host->GetProcess()->GetID());
653 void WebContents::RenderProcessGone(base::TerminationStatus status) {
654 Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
657 void WebContents::PluginCrashed(const base::FilePath& plugin_path,
658 base::ProcessId plugin_pid) {
659 content::WebPluginInfo info;
660 auto plugin_service = content::PluginService::GetInstance();
661 plugin_service->GetPluginInfoByPath(plugin_path, &info);
662 Emit("plugin-crashed", info.name, info.version);
665 void WebContents::MediaStartedPlaying(const MediaPlayerInfo& video_type,
666 const MediaPlayerId& id) {
667 Emit("media-started-playing");
670 void WebContents::MediaStoppedPlaying(const MediaPlayerInfo& video_type,
671 const MediaPlayerId& id) {
672 Emit("media-paused");
675 void WebContents::DidChangeThemeColor(SkColor theme_color) {
676 Emit("did-change-theme-color", atom::ToRGBHex(theme_color));
679 void WebContents::DocumentLoadedInFrame(
680 content::RenderFrameHost* render_frame_host) {
681 if (!render_frame_host->GetParent())
685 void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
686 const GURL& validated_url) {
687 bool is_main_frame = !render_frame_host->GetParent();
688 Emit("did-frame-finish-load", is_main_frame);
691 Emit("did-finish-load");
694 void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
697 const base::string16& error_description,
698 bool was_ignored_by_handler) {
699 bool is_main_frame = !render_frame_host->GetParent();
700 Emit("did-fail-load", error_code, error_description, url, is_main_frame);
703 void WebContents::DidStartLoading() {
704 Emit("did-start-loading");
707 void WebContents::DidStopLoading() {
708 Emit("did-stop-loading");
711 void WebContents::DidGetResourceResponseStart(
712 const content::ResourceRequestDetails& details) {
713 Emit("did-get-response-details",
714 details.socket_address.IsEmpty(),
716 details.original_url,
717 details.http_response_code,
720 details.headers.get(),
721 ResourceTypeToString(details.resource_type));
724 void WebContents::DidGetRedirectForResourceRequest(
725 const content::ResourceRedirectDetails& details) {
726 Emit("did-get-redirect-request",
729 (details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME),
730 details.http_response_code,
733 details.headers.get());
736 void WebContents::DidFinishNavigation(
737 content::NavigationHandle* navigation_handle) {
738 bool is_main_frame = navigation_handle->IsInMainFrame();
739 if (navigation_handle->HasCommitted() && !navigation_handle->IsErrorPage()) {
740 auto url = navigation_handle->GetURL();
741 bool is_in_page = navigation_handle->IsSamePage();
742 if (is_main_frame && !is_in_page) {
743 Emit("did-navigate", url);
744 } else if (is_in_page) {
745 Emit("did-navigate-in-page", url, is_main_frame);
748 auto url = navigation_handle->GetURL();
749 int code = navigation_handle->GetNetErrorCode();
750 auto description = net::ErrorToShortString(code);
751 Emit("did-fail-provisional-load", code, description, url, is_main_frame);
753 // Do not emit "did-fail-load" for canceled requests.
754 if (code != net::ERR_ABORTED)
755 Emit("did-fail-load", code, description, url, is_main_frame);
759 void WebContents::TitleWasSet(content::NavigationEntry* entry,
762 Emit("-page-title-updated", entry->GetTitle(), explicit_set);
764 Emit("-page-title-updated", "", explicit_set);
767 void WebContents::DidUpdateFaviconURL(
768 const std::vector<content::FaviconURL>& urls) {
769 std::set<GURL> unique_urls;
770 for (const auto& iter : urls) {
771 if (iter.icon_type != content::FaviconURL::FAVICON)
773 const GURL& url = iter.icon_url;
775 unique_urls.insert(url);
777 Emit("page-favicon-updated", unique_urls);
780 void WebContents::DevToolsReloadPage() {
781 Emit("devtools-reload-page");
784 void WebContents::DevToolsFocused() {
785 Emit("devtools-focused");
788 void WebContents::DevToolsOpened() {
789 v8::Locker locker(isolate());
790 v8::HandleScope handle_scope(isolate());
791 auto handle = WebContents::CreateFrom(
792 isolate(), managed_web_contents()->GetDevToolsWebContents());
793 devtools_web_contents_.Reset(isolate(), handle.ToV8());
795 // Set inspected tabID.
796 base::FundamentalValue tab_id(ID());
797 managed_web_contents()->CallClientFunction(
798 "DevToolsAPI.setInspectedTabId", &tab_id, nullptr, nullptr);
800 // Inherit owner window in devtools.
802 handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(),
805 Emit("devtools-opened");
808 void WebContents::DevToolsClosed() {
809 v8::Locker locker(isolate());
810 v8::HandleScope handle_scope(isolate());
811 devtools_web_contents_.Reset();
813 Emit("devtools-closed");
816 bool WebContents::OnMessageReceived(const IPC::Message& message) {
818 IPC_BEGIN_MESSAGE_MAP(WebContents, message)
819 IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
820 IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
821 OnRendererMessageSync)
822 IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_SetTemporaryZoomLevel,
823 OnSetTemporaryZoomLevel)
824 IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_GetZoomLevel,
826 IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
828 IPC_MESSAGE_UNHANDLED(handled = false)
829 IPC_END_MESSAGE_MAP()
834 // There are three ways of destroying a webContents:
835 // 1. call webContents.destroy();
836 // 2. garbage collection;
837 // 3. user closes the window of webContents;
838 // For webview only #1 will happen, for BrowserWindow both #1 and #3 may
839 // happen. The #2 should never happen for webContents, because webview is
840 // managed by GuestViewManager, and BrowserWindow's webContents is managed
842 // For #1, the destructor will do the cleanup work and we only need to make
843 // sure "destroyed" event is emitted. For #3, the content::WebContents will
844 // be destroyed on close, and WebContentsDestroyed would be called for it, so
845 // we need to make sure the api::WebContents is also deleted.
846 void WebContents::WebContentsDestroyed() {
847 // This event is only for internal use, which is emitted when WebContents is
849 Emit("will-destroy");
851 // Cleanup relationships with other parts.
854 // We can not call Destroy here because we need to call Emit first, but we
855 // also do not want any method to be used, so just mark as destroyed here.
860 // Destroy the native class in next tick.
861 base::ThreadTaskRunnerHandle::Get()->PostTask(
862 FROM_HERE, GetDestroyClosure());
865 void WebContents::NavigationEntryCommitted(
866 const content::LoadCommittedDetails& details) {
867 Emit("navigation-entry-commited", details.entry->GetURL(),
868 details.is_in_page, details.did_replace_entry);
871 int64_t WebContents::GetID() const {
872 int64_t process_id = web_contents()->GetRenderProcessHost()->GetID();
873 int64_t routing_id = web_contents()->GetRoutingID();
874 int64_t rv = (process_id << 32) + routing_id;
878 int WebContents::GetProcessID() const {
879 return web_contents()->GetRenderProcessHost()->GetID();
882 WebContents::Type WebContents::GetType() const {
886 bool WebContents::Equal(const WebContents* web_contents) const {
887 return GetID() == web_contents->GetID();
890 void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
891 if (!url.is_valid() || url.spec().size() > url::kMaxURLChars) {
892 Emit("did-fail-load",
893 static_cast<int>(net::ERR_INVALID_URL),
894 net::ErrorToShortString(net::ERR_INVALID_URL),
895 url.possibly_invalid_spec(),
900 content::NavigationController::LoadURLParams params(url);
903 if (options.Get("httpReferrer", &http_referrer))
904 params.referrer = content::Referrer(http_referrer.GetAsReferrer(),
905 blink::WebReferrerPolicyDefault);
907 std::string user_agent;
908 if (options.Get("userAgent", &user_agent))
909 web_contents()->SetUserAgentOverride(user_agent);
911 std::string extra_headers;
912 if (options.Get("extraHeaders", &extra_headers))
913 params.extra_headers = extra_headers;
915 scoped_refptr<content::ResourceRequestBodyImpl> body;
916 if (options.Get("postData", &body)) {
917 params.post_data = body;
918 params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST;
921 GURL base_url_for_data_url;
922 if (options.Get("baseURLForDataURL", &base_url_for_data_url)) {
923 params.base_url_for_data_url = base_url_for_data_url;
924 params.load_type = content::NavigationController::LOAD_TYPE_DATA;
927 params.transition_type = ui::PAGE_TRANSITION_TYPED;
928 params.should_clear_history_list = true;
929 params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
930 web_contents()->GetController().LoadURLWithParams(params);
932 // Set the background color of RenderWidgetHostView.
933 // We have to call it right after LoadURL because the RenderViewHost is only
934 // created after loading a page.
935 const auto view = web_contents()->GetRenderWidgetHostView();
937 WebContentsPreferences* web_preferences =
938 WebContentsPreferences::FromWebContents(web_contents());
939 std::string color_name;
940 if (web_preferences->web_preferences()->GetString(options::kBackgroundColor,
942 view->SetBackgroundColor(ParseHexColor(color_name));
944 view->SetBackgroundColor(SK_ColorTRANSPARENT);
949 void WebContents::DownloadURL(const GURL& url) {
950 auto browser_context = web_contents()->GetBrowserContext();
951 auto download_manager =
952 content::BrowserContext::GetDownloadManager(browser_context);
954 download_manager->DownloadUrl(
955 content::DownloadUrlParameters::CreateForWebContentsMainFrame(
956 web_contents(), url));
959 GURL WebContents::GetURL() const {
960 return web_contents()->GetURL();
963 base::string16 WebContents::GetTitle() const {
964 return web_contents()->GetTitle();
967 bool WebContents::IsLoading() const {
968 return web_contents()->IsLoading();
971 bool WebContents::IsLoadingMainFrame() const {
972 // Comparing site instances works because Electron always creates a new site
973 // instance when navigating, regardless of origin. See AtomBrowserClient.
974 return (web_contents()->GetLastCommittedURL().is_empty() ||
975 web_contents()->GetSiteInstance() !=
976 web_contents()->GetPendingSiteInstance()) && IsLoading();
979 bool WebContents::IsWaitingForResponse() const {
980 return web_contents()->IsWaitingForResponse();
983 void WebContents::Stop() {
984 web_contents()->Stop();
987 void WebContents::GoBack() {
988 atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
989 web_contents()->GetController().GoBack();
992 void WebContents::GoForward() {
993 atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
994 web_contents()->GetController().GoForward();
997 void WebContents::GoToOffset(int offset) {
998 atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
999 web_contents()->GetController().GoToOffset(offset);
1002 bool WebContents::IsCrashed() const {
1003 return web_contents()->IsCrashed();
1006 void WebContents::SetUserAgent(const std::string& user_agent,
1007 mate::Arguments* args) {
1008 web_contents()->SetUserAgentOverride(user_agent);
1011 std::string WebContents::GetUserAgent() {
1012 return web_contents()->GetUserAgentOverride();
1015 bool WebContents::SavePage(const base::FilePath& full_file_path,
1016 const content::SavePageType& save_type,
1017 const SavePageHandler::SavePageCallback& callback) {
1018 auto handler = new SavePageHandler(web_contents(), callback);
1019 return handler->Handle(full_file_path, save_type);
1022 void WebContents::OpenDevTools(mate::Arguments* args) {
1023 if (type_ == REMOTE)
1026 if (!enable_devtools_)
1030 if (type_ == WEB_VIEW || !owner_window()) {
1032 } else if (args && args->Length() == 1) {
1033 bool detach = false;
1034 mate::Dictionary options;
1035 if (args->GetNext(&options)) {
1036 options.Get("mode", &state);
1038 // TODO(kevinsawicki) Remove in 2.0
1039 options.Get("detach", &detach);
1040 if (state.empty() && detach)
1044 managed_web_contents()->SetDockState(state);
1045 managed_web_contents()->ShowDevTools();
1048 void WebContents::CloseDevTools() {
1049 if (type_ == REMOTE)
1052 managed_web_contents()->CloseDevTools();
1055 bool WebContents::IsDevToolsOpened() {
1056 if (type_ == REMOTE)
1059 return managed_web_contents()->IsDevToolsViewShowing();
1062 bool WebContents::IsDevToolsFocused() {
1063 if (type_ == REMOTE)
1066 return managed_web_contents()->GetView()->IsDevToolsViewFocused();
1069 void WebContents::EnableDeviceEmulation(
1070 const blink::WebDeviceEmulationParams& params) {
1071 if (type_ == REMOTE)
1074 Send(new ViewMsg_EnableDeviceEmulation(routing_id(), params));
1077 void WebContents::DisableDeviceEmulation() {
1078 if (type_ == REMOTE)
1081 Send(new ViewMsg_DisableDeviceEmulation(routing_id()));
1084 void WebContents::ToggleDevTools() {
1085 if (IsDevToolsOpened())
1088 OpenDevTools(nullptr);
1091 void WebContents::InspectElement(int x, int y) {
1092 if (type_ == REMOTE)
1095 if (!enable_devtools_)
1098 if (!managed_web_contents()->GetDevToolsWebContents())
1099 OpenDevTools(nullptr);
1100 managed_web_contents()->InspectElement(x, y);
1103 void WebContents::InspectServiceWorker() {
1104 if (type_ == REMOTE)
1107 if (!enable_devtools_)
1110 for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
1111 if (agent_host->GetType() ==
1112 content::DevToolsAgentHost::kTypeServiceWorker) {
1113 OpenDevTools(nullptr);
1114 managed_web_contents()->AttachTo(agent_host);
1120 void WebContents::HasServiceWorker(
1121 const base::Callback<void(bool)>& callback) {
1122 auto context = GetServiceWorkerContext(web_contents());
1126 context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(),
1131 void WebContents::UnregisterServiceWorker(
1132 const base::Callback<void(bool)>& callback) {
1133 auto context = GetServiceWorkerContext(web_contents());
1137 context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(),
1141 void WebContents::SetAudioMuted(bool muted) {
1142 web_contents()->SetAudioMuted(muted);
1145 bool WebContents::IsAudioMuted() {
1146 return web_contents()->IsAudioMuted();
1149 void WebContents::Print(mate::Arguments* args) {
1150 PrintSettings settings = { false, false };
1151 if (args->Length() == 1 && !args->GetNext(&settings)) {
1156 printing::PrintViewManagerBasic::FromWebContents(web_contents())->
1157 PrintNow(web_contents()->GetMainFrame(),
1159 settings.print_background);
1162 void WebContents::PrintToPDF(const base::DictionaryValue& setting,
1163 const PrintToPDFCallback& callback) {
1164 printing::PrintPreviewMessageHandler::FromWebContents(web_contents())->
1165 PrintToPDF(setting, callback);
1168 void WebContents::AddWorkSpace(mate::Arguments* args,
1169 const base::FilePath& path) {
1171 args->ThrowError("path cannot be empty");
1174 DevToolsAddFileSystem(path);
1177 void WebContents::RemoveWorkSpace(mate::Arguments* args,
1178 const base::FilePath& path) {
1180 args->ThrowError("path cannot be empty");
1183 DevToolsRemoveFileSystem(path);
1186 void WebContents::Undo() {
1187 web_contents()->Undo();
1190 void WebContents::Redo() {
1191 web_contents()->Redo();
1194 void WebContents::Cut() {
1195 web_contents()->Cut();
1198 void WebContents::Copy() {
1199 web_contents()->Copy();
1202 void WebContents::Paste() {
1203 web_contents()->Paste();
1206 void WebContents::PasteAndMatchStyle() {
1207 web_contents()->PasteAndMatchStyle();
1210 void WebContents::Delete() {
1211 web_contents()->Delete();
1214 void WebContents::SelectAll() {
1215 web_contents()->SelectAll();
1218 void WebContents::Unselect() {
1219 web_contents()->Unselect();
1222 void WebContents::Replace(const base::string16& word) {
1223 web_contents()->Replace(word);
1226 void WebContents::ReplaceMisspelling(const base::string16& word) {
1227 web_contents()->ReplaceMisspelling(word);
1230 uint32_t WebContents::FindInPage(mate::Arguments* args) {
1231 uint32_t request_id = GetNextRequestId();
1232 base::string16 search_text;
1233 blink::WebFindOptions options;
1234 if (!args->GetNext(&search_text) || search_text.empty()) {
1235 args->ThrowError("Must provide a non-empty search content");
1239 args->GetNext(&options);
1241 web_contents()->Find(request_id, search_text, options);
1245 void WebContents::StopFindInPage(content::StopFindAction action) {
1246 web_contents()->StopFinding(action);
1249 void WebContents::ShowDefinitionForSelection() {
1250 #if defined(OS_MACOSX)
1251 const auto view = web_contents()->GetRenderWidgetHostView();
1253 view->ShowDefinitionForSelection();
1257 void WebContents::CopyImageAt(int x, int y) {
1258 const auto host = web_contents()->GetMainFrame();
1260 host->CopyImageAt(x, y);
1263 void WebContents::Focus() {
1264 web_contents()->Focus();
1267 #if !defined(OS_MACOSX)
1268 bool WebContents::IsFocused() const {
1269 auto view = web_contents()->GetRenderWidgetHostView();
1270 if (!view) return false;
1272 if (GetType() != BACKGROUND_PAGE) {
1273 auto window = web_contents()->GetNativeView()->GetToplevelWindow();
1274 if (window && !window->IsVisible())
1278 return view->HasFocus();
1282 void WebContents::TabTraverse(bool reverse) {
1283 web_contents()->FocusThroughTabTraversal(reverse);
1286 bool WebContents::SendIPCMessage(bool all_frames,
1287 const base::string16& channel,
1288 const base::ListValue& args) {
1289 return Send(new AtomViewMsg_Message(routing_id(), all_frames, channel, args));
1292 void WebContents::SendInputEvent(v8::Isolate* isolate,
1293 v8::Local<v8::Value> input_event) {
1294 const auto view = web_contents()->GetRenderWidgetHostView();
1297 const auto host = view->GetRenderWidgetHost();
1301 int type = mate::GetWebInputEventType(isolate, input_event);
1302 if (blink::WebInputEvent::isMouseEventType(type)) {
1303 blink::WebMouseEvent mouse_event;
1304 if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) {
1305 host->ForwardMouseEvent(mouse_event);
1308 } else if (blink::WebInputEvent::isKeyboardEventType(type)) {
1309 content::NativeWebKeyboardEvent keyboard_event;
1310 if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) {
1311 host->ForwardKeyboardEvent(keyboard_event);
1314 } else if (type == blink::WebInputEvent::MouseWheel) {
1315 blink::WebMouseWheelEvent mouse_wheel_event;
1316 if (mate::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) {
1317 host->ForwardWheelEvent(mouse_wheel_event);
1322 isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
1323 isolate, "Invalid event object")));
1326 void WebContents::BeginFrameSubscription(mate::Arguments* args) {
1327 bool only_dirty = false;
1328 FrameSubscriber::FrameCaptureCallback callback;
1330 args->GetNext(&only_dirty);
1331 if (!args->GetNext(&callback)) {
1336 const auto view = web_contents()->GetRenderWidgetHostView();
1338 std::unique_ptr<FrameSubscriber> frame_subscriber(new FrameSubscriber(
1339 isolate(), view, callback, only_dirty));
1340 view->BeginFrameSubscription(std::move(frame_subscriber));
1344 void WebContents::EndFrameSubscription() {
1345 const auto view = web_contents()->GetRenderWidgetHostView();
1347 view->EndFrameSubscription();
1350 void WebContents::StartDrag(const mate::Dictionary& item,
1351 mate::Arguments* args) {
1352 base::FilePath file;
1353 std::vector<base::FilePath> files;
1354 if (!item.Get("files", &files) && item.Get("file", &file)) {
1355 files.push_back(file);
1358 mate::Handle<NativeImage> icon;
1359 if (!item.Get("icon", &icon) && !file.empty()) {
1360 // TODO(zcbenz): Set default icon from file.
1364 if (icon.IsEmpty()) {
1365 args->ThrowError("Must specify 'icon' option");
1369 #if defined(OS_MACOSX)
1370 // NSWindow.dragImage requires a non-empty NSImage
1371 if (icon->image().IsEmpty()) {
1372 args->ThrowError("Must specify non-empty 'icon' option");
1378 if (!files.empty()) {
1379 base::MessageLoop::ScopedNestableTaskAllower allow(
1380 base::MessageLoop::current());
1381 DragFileItems(files, icon->image(), web_contents()->GetNativeView());
1383 args->ThrowError("Must specify either 'file' or 'files' option");
1387 void WebContents::CapturePage(mate::Arguments* args) {
1389 base::Callback<void(const gfx::Image&)> callback;
1391 if (!(args->Length() == 1 && args->GetNext(&callback)) &&
1392 !(args->Length() == 2 && args->GetNext(&rect)
1393 && args->GetNext(&callback))) {
1398 const auto view = web_contents()->GetRenderWidgetHostView();
1399 const auto host = view ? view->GetRenderWidgetHost() : nullptr;
1400 if (!view || !host) {
1401 callback.Run(gfx::Image());
1405 // Capture full page if user doesn't specify a |rect|.
1406 const gfx::Size view_size = rect.IsEmpty() ? view->GetViewBounds().size() :
1409 // By default, the requested bitmap size is the view size in screen
1410 // coordinates. However, if there's more pixel detail available on the
1411 // current system, increase the requested bitmap size to capture it all.
1412 gfx::Size bitmap_size = view_size;
1413 const gfx::NativeView native_view = view->GetNativeView();
1415 display::Screen::GetScreen()->GetDisplayNearestWindow(native_view)
1416 .device_scale_factor();
1418 bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
1420 host->CopyFromBackingStore(gfx::Rect(rect.origin(), view_size),
1422 base::Bind(&OnCapturePageDone, callback),
1423 kBGRA_8888_SkColorType);
1426 void WebContents::OnCursorChange(const content::WebCursor& cursor) {
1427 content::WebCursor::CursorInfo info;
1428 cursor.GetCursorInfo(&info);
1430 if (cursor.IsCustom()) {
1431 Emit("cursor-changed", CursorTypeToString(info),
1432 gfx::Image::CreateFrom1xBitmap(info.custom_image),
1433 info.image_scale_factor,
1434 gfx::Size(info.custom_image.width(), info.custom_image.height()),
1437 Emit("cursor-changed", CursorTypeToString(info));
1441 void WebContents::SetSize(const SetSizeParams& params) {
1442 if (guest_delegate_)
1443 guest_delegate_->SetSize(params);
1446 bool WebContents::IsGuest() const {
1447 return type_ == WEB_VIEW;
1450 bool WebContents::IsOffScreen() const {
1451 return type_ == OFF_SCREEN;
1454 void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) {
1455 mate::Handle<NativeImage> image =
1456 NativeImage::Create(isolate(), gfx::Image::CreateFrom1xBitmap(bitmap));
1457 Emit("paint", dirty_rect, image);
1460 void WebContents::StartPainting() {
1464 auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1465 web_contents()->GetRenderWidgetHostView());
1467 osr_rwhv->SetPainting(true);
1470 void WebContents::StopPainting() {
1474 auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1475 web_contents()->GetRenderWidgetHostView());
1477 osr_rwhv->SetPainting(false);
1480 bool WebContents::IsPainting() const {
1484 const auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1485 web_contents()->GetRenderWidgetHostView());
1486 return osr_rwhv && osr_rwhv->IsPainting();
1489 void WebContents::SetFrameRate(int frame_rate) {
1493 auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1494 web_contents()->GetRenderWidgetHostView());
1496 osr_rwhv->SetFrameRate(frame_rate);
1499 int WebContents::GetFrameRate() const {
1503 const auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1504 web_contents()->GetRenderWidgetHostView());
1505 return osr_rwhv ? osr_rwhv->GetFrameRate() : 0;
1508 void WebContents::Invalidate() {
1509 if (IsOffScreen()) {
1510 auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
1511 web_contents()->GetRenderWidgetHostView());
1513 osr_rwhv->Invalidate();
1515 const auto window = owner_window();
1517 window->Invalidate();
1521 void WebContents::SetZoomLevel(double level) {
1522 zoom_controller_->SetZoomLevel(level);
1525 double WebContents::GetZoomLevel() {
1526 return zoom_controller_->GetZoomLevel();
1529 void WebContents::SetZoomFactor(double factor) {
1530 auto level = content::ZoomFactorToZoomLevel(factor);
1531 SetZoomLevel(level);
1534 double WebContents::GetZoomFactor() {
1535 auto level = GetZoomLevel();
1536 return content::ZoomLevelToZoomFactor(level);
1539 void WebContents::OnSetTemporaryZoomLevel(double level,
1540 IPC::Message* reply_msg) {
1541 zoom_controller_->SetTemporaryZoomLevel(level);
1542 double new_level = zoom_controller_->GetZoomLevel();
1543 AtomViewHostMsg_SetTemporaryZoomLevel::WriteReplyParams(reply_msg, new_level);
1547 void WebContents::OnGetZoomLevel(IPC::Message* reply_msg) {
1548 AtomViewHostMsg_GetZoomLevel::WriteReplyParams(reply_msg, GetZoomLevel());
1552 v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
1553 WebContentsPreferences* web_preferences =
1554 WebContentsPreferences::FromWebContents(web_contents());
1555 return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
1558 v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() {
1560 return Window::From(isolate(), owner_window());
1562 return v8::Null(isolate());
1565 int32_t WebContents::ID() const {
1566 return weak_map_id();
1569 v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
1570 return v8::Local<v8::Value>::New(isolate, session_);
1573 content::WebContents* WebContents::HostWebContents() {
1576 return embedder_->web_contents();
1579 void WebContents::SetEmbedder(const WebContents* embedder) {
1581 NativeWindow* owner_window = nullptr;
1582 auto relay = NativeWindowRelay::FromWebContents(embedder->web_contents());
1584 owner_window = relay->window.get();
1587 SetOwnerWindow(owner_window);
1589 content::RenderWidgetHostView* rwhv =
1590 web_contents()->GetRenderWidgetHostView();
1598 v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
1599 if (devtools_web_contents_.IsEmpty())
1600 return v8::Null(isolate);
1602 return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
1605 v8::Local<v8::Value> WebContents::Debugger(v8::Isolate* isolate) {
1606 if (debugger_.IsEmpty()) {
1607 auto handle = atom::api::Debugger::Create(isolate, web_contents());
1608 debugger_.Reset(isolate, handle.ToV8());
1610 return v8::Local<v8::Value>::New(isolate, debugger_);
1614 void WebContents::BuildPrototype(v8::Isolate* isolate,
1615 v8::Local<v8::FunctionTemplate> prototype) {
1616 prototype->SetClassName(mate::StringToV8(isolate, "WebContents"));
1617 mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
1619 .SetMethod("getId", &WebContents::GetID)
1620 .SetMethod("getProcessId", &WebContents::GetProcessID)
1621 .SetMethod("equal", &WebContents::Equal)
1622 .SetMethod("_loadURL", &WebContents::LoadURL)
1623 .SetMethod("downloadURL", &WebContents::DownloadURL)
1624 .SetMethod("_getURL", &WebContents::GetURL)
1625 .SetMethod("getTitle", &WebContents::GetTitle)
1626 .SetMethod("isLoading", &WebContents::IsLoading)
1627 .SetMethod("isLoadingMainFrame", &WebContents::IsLoadingMainFrame)
1628 .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
1629 .SetMethod("_stop", &WebContents::Stop)
1630 .SetMethod("_goBack", &WebContents::GoBack)
1631 .SetMethod("_goForward", &WebContents::GoForward)
1632 .SetMethod("_goToOffset", &WebContents::GoToOffset)
1633 .SetMethod("isCrashed", &WebContents::IsCrashed)
1634 .SetMethod("setUserAgent", &WebContents::SetUserAgent)
1635 .SetMethod("getUserAgent", &WebContents::GetUserAgent)
1636 .SetMethod("savePage", &WebContents::SavePage)
1637 .SetMethod("openDevTools", &WebContents::OpenDevTools)
1638 .SetMethod("closeDevTools", &WebContents::CloseDevTools)
1639 .SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
1640 .SetMethod("isDevToolsFocused", &WebContents::IsDevToolsFocused)
1641 .SetMethod("enableDeviceEmulation",
1642 &WebContents::EnableDeviceEmulation)
1643 .SetMethod("disableDeviceEmulation",
1644 &WebContents::DisableDeviceEmulation)
1645 .SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
1646 .SetMethod("inspectElement", &WebContents::InspectElement)
1647 .SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
1648 .SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
1649 .SetMethod("undo", &WebContents::Undo)
1650 .SetMethod("redo", &WebContents::Redo)
1651 .SetMethod("cut", &WebContents::Cut)
1652 .SetMethod("copy", &WebContents::Copy)
1653 .SetMethod("paste", &WebContents::Paste)
1654 .SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
1655 .SetMethod("delete", &WebContents::Delete)
1656 .SetMethod("selectAll", &WebContents::SelectAll)
1657 .SetMethod("unselect", &WebContents::Unselect)
1658 .SetMethod("replace", &WebContents::Replace)
1659 .SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
1660 .SetMethod("findInPage", &WebContents::FindInPage)
1661 .SetMethod("stopFindInPage", &WebContents::StopFindInPage)
1662 .SetMethod("focus", &WebContents::Focus)
1663 .SetMethod("isFocused", &WebContents::IsFocused)
1664 .SetMethod("tabTraverse", &WebContents::TabTraverse)
1665 .SetMethod("_send", &WebContents::SendIPCMessage)
1666 .SetMethod("sendInputEvent", &WebContents::SendInputEvent)
1667 .SetMethod("beginFrameSubscription",
1668 &WebContents::BeginFrameSubscription)
1669 .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
1670 .SetMethod("startDrag", &WebContents::StartDrag)
1671 .SetMethod("setSize", &WebContents::SetSize)
1672 .SetMethod("isGuest", &WebContents::IsGuest)
1673 .SetMethod("isOffscreen", &WebContents::IsOffScreen)
1674 .SetMethod("startPainting", &WebContents::StartPainting)
1675 .SetMethod("stopPainting", &WebContents::StopPainting)
1676 .SetMethod("isPainting", &WebContents::IsPainting)
1677 .SetMethod("setFrameRate", &WebContents::SetFrameRate)
1678 .SetMethod("getFrameRate", &WebContents::GetFrameRate)
1679 .SetMethod("invalidate", &WebContents::Invalidate)
1680 .SetMethod("setZoomLevel", &WebContents::SetZoomLevel)
1681 .SetMethod("_getZoomLevel", &WebContents::GetZoomLevel)
1682 .SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
1683 .SetMethod("_getZoomFactor", &WebContents::GetZoomFactor)
1684 .SetMethod("getType", &WebContents::GetType)
1685 .SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
1686 .SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
1687 .SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
1688 .SetMethod("unregisterServiceWorker",
1689 &WebContents::UnregisterServiceWorker)
1690 .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
1691 .SetMethod("print", &WebContents::Print)
1692 .SetMethod("_printToPDF", &WebContents::PrintToPDF)
1693 .SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
1694 .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
1695 .SetMethod("showDefinitionForSelection",
1696 &WebContents::ShowDefinitionForSelection)
1697 .SetMethod("copyImageAt", &WebContents::CopyImageAt)
1698 .SetMethod("capturePage", &WebContents::CapturePage)
1699 .SetMethod("setEmbedder", &WebContents::SetEmbedder)
1700 .SetProperty("id", &WebContents::ID)
1701 .SetProperty("session", &WebContents::Session)
1702 .SetProperty("hostWebContents", &WebContents::HostWebContents)
1703 .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents)
1704 .SetProperty("debugger", &WebContents::Debugger);
1707 AtomBrowserContext* WebContents::GetBrowserContext() const {
1708 return static_cast<AtomBrowserContext*>(web_contents()->GetBrowserContext());
1711 void WebContents::OnRendererMessage(const base::string16& channel,
1712 const base::ListValue& args) {
1713 // webContents.emit(channel, new Event(), args...);
1714 Emit(base::UTF16ToUTF8(channel), args);
1717 void WebContents::OnRendererMessageSync(const base::string16& channel,
1718 const base::ListValue& args,
1719 IPC::Message* message) {
1720 // webContents.emit(channel, new Event(sender, message), args...);
1721 EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args);
1725 mate::Handle<WebContents> WebContents::CreateFrom(
1726 v8::Isolate* isolate, content::WebContents* web_contents) {
1727 // We have an existing WebContents object in JS.
1728 auto existing = TrackableObject::FromWrappedClass(isolate, web_contents);
1730 return mate::CreateHandle(isolate, static_cast<WebContents*>(existing));
1732 // Otherwise create a new WebContents wrapper object.
1733 return mate::CreateHandle(isolate, new WebContents(isolate, web_contents,
1737 mate::Handle<WebContents> WebContents::CreateFrom(
1738 v8::Isolate* isolate, content::WebContents* web_contents, Type type) {
1739 // Otherwise create a new WebContents wrapper object.
1740 return mate::CreateHandle(isolate, new WebContents(isolate, web_contents,
1745 mate::Handle<WebContents> WebContents::Create(
1746 v8::Isolate* isolate, const mate::Dictionary& options) {
1747 return mate::CreateHandle(isolate, new WebContents(isolate, options));
1756 using atom::api::WebContents;
1758 void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
1759 v8::Local<v8::Context> context, void* priv) {
1760 v8::Isolate* isolate = context->GetIsolate();
1761 mate::Dictionary dict(isolate, exports);
1762 dict.Set("WebContents", WebContents::GetConstructor(isolate)->GetFunction());
1763 dict.SetMethod("create", &WebContents::Create);
1764 dict.SetMethod("fromId", &mate::TrackableObject<WebContents>::FromWeakMapID);
1765 dict.SetMethod("getAllWebContents",
1766 &mate::TrackableObject<WebContents>::GetAll);
1771 NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_web_contents, Initialize)