// Copyright (c) 2017 GitHub, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #include "shell/browser/api/electron_api_browser_view.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" // nogncheck #include "content/public/browser/render_widget_host_view.h" #include "shell/browser/api/electron_api_base_window.h" #include "shell/browser/api/electron_api_web_contents.h" #include "shell/browser/browser.h" #include "shell/browser/native_browser_view.h" #include "shell/browser/ui/drag_util.h" #include "shell/browser/web_contents_preferences.h" #include "shell/common/color_util.h" #include "shell/common/gin_converters/gfx_converter.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/node_includes.h" #include "shell/common/options_switches.h" #include "ui/base/hit_test.h" #include "ui/gfx/geometry/rect.h" namespace gin { template <> struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Local val, electron::AutoResizeFlags* auto_resize_flags) { gin_helper::Dictionary params; if (!ConvertFromV8(isolate, val, ¶ms)) { return false; } uint8_t flags = 0; bool width = false; if (params.Get("width", &width) && width) { flags |= electron::kAutoResizeWidth; } bool height = false; if (params.Get("height", &height) && height) { flags |= electron::kAutoResizeHeight; } bool horizontal = false; if (params.Get("horizontal", &horizontal) && horizontal) { flags |= electron::kAutoResizeHorizontal; } bool vertical = false; if (params.Get("vertical", &vertical) && vertical) { flags |= electron::kAutoResizeVertical; } *auto_resize_flags = static_cast(flags); return true; } }; } // namespace gin namespace { int32_t GetNextId() { static int32_t next_id = 1; return next_id++; } } // namespace namespace electron::api { gin::WrapperInfo BrowserView::kWrapperInfo = {gin::kEmbedderNativeGin}; BrowserView::BrowserView(gin::Arguments* args, const gin_helper::Dictionary& options) : id_(GetNextId()) { gin_helper::Dictionary web_preferences = gin::Dictionary::CreateEmpty(args->isolate()); options.Get(options::kWebPreferences, &web_preferences); web_preferences.Set("type", "browserView"); v8::Local value; // Copy the webContents option to webPreferences. if (options.Get("webContents", &value)) { web_preferences.SetHidden("webContents", value); } auto web_contents = WebContents::CreateFromWebPreferences(args->isolate(), web_preferences); web_contents_.Reset(args->isolate(), web_contents.ToV8()); api_web_contents_ = web_contents.get(); api_web_contents_->AddObserver(this); Observe(web_contents->web_contents()); view_.reset( NativeBrowserView::Create(api_web_contents_->inspectable_web_contents())); } void BrowserView::SetOwnerWindow(BaseWindow* window) { // Ensure WebContents and BrowserView owner windows are in sync. if (web_contents()) web_contents()->SetOwnerWindow(window ? window->window() : nullptr); owner_window_ = window ? window->GetWeakPtr() : nullptr; } int BrowserView::NonClientHitTest(const gfx::Point& point) { gfx::Rect bounds = GetBounds(); gfx::Point local_point(point.x() - bounds.x(), point.y() - bounds.y()); SkRegion* region = api_web_contents_->draggable_region(); if (region && region->contains(local_point.x(), local_point.y())) return HTCAPTION; return HTNOWHERE; } BrowserView::~BrowserView() { if (web_contents()) { // destroy() called without closing WebContents web_contents()->RemoveObserver(this); web_contents()->Destroy(); } } void BrowserView::WebContentsDestroyed() { if (owner_window()) owner_window()->window()->RemoveDraggableRegionProvider(this); api_web_contents_ = nullptr; web_contents_.Reset(); Unpin(); } void BrowserView::OnCloseContents() { api_web_contents_ = nullptr; } // static gin::Handle BrowserView::New(gin_helper::ErrorThrower thrower, gin::Arguments* args) { if (!Browser::Get()->is_ready()) { thrower.ThrowError("Cannot create BrowserView before app is ready"); return gin::Handle(); } gin::Dictionary options = gin::Dictionary::CreateEmpty(args->isolate()); args->GetNext(&options); auto handle = gin::CreateHandle(args->isolate(), new BrowserView(args, options)); handle->Pin(args->isolate()); return handle; } void BrowserView::SetAutoResize(AutoResizeFlags flags) { view_->SetAutoResizeFlags(flags); } void BrowserView::SetBounds(const gfx::Rect& bounds) { view_->SetBounds(bounds); } gfx::Rect BrowserView::GetBounds() { return view_->GetBounds(); } void BrowserView::SetBackgroundColor(const std::string& color_name) { SkColor color = ParseCSSColor(color_name); view_->SetBackgroundColor(color); if (web_contents()) { auto* wc = web_contents()->web_contents(); wc->SetPageBaseBackgroundColor(ParseCSSColor(color_name)); auto* const rwhv = wc->GetRenderWidgetHostView(); if (rwhv) { rwhv->SetBackgroundColor(color); static_cast(rwhv) ->SetContentBackgroundColor(color); } // Ensure new color is stored in webPreferences, otherwise // the color will be reset on the next load via HandleNewRenderFrame. auto* web_preferences = WebContentsPreferences::From(wc); if (web_preferences) web_preferences->SetBackgroundColor(color); } } v8::Local BrowserView::GetWebContents(v8::Isolate* isolate) { if (web_contents_.IsEmpty()) { return v8::Null(isolate); } return v8::Local::New(isolate, web_contents_); } // static void BrowserView::FillObjectTemplate(v8::Isolate* isolate, v8::Local templ) { gin::ObjectTemplateBuilder(isolate, GetClassName(), templ) .SetMethod("setAutoResize", &BrowserView::SetAutoResize) .SetMethod("setBounds", &BrowserView::SetBounds) .SetMethod("getBounds", &BrowserView::GetBounds) .SetMethod("setBackgroundColor", &BrowserView::SetBackgroundColor) .SetProperty("webContents", &BrowserView::GetWebContents) .Build(); } const char* BrowserView::GetTypeName() { return GetClassName(); } } // namespace electron::api namespace { using electron::api::BrowserView; void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); gin_helper::Dictionary dict(isolate, exports); dict.Set("BrowserView", BrowserView::GetConstructor(context)); } } // namespace NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_browser_view, Initialize)