views: Add support for absolute positioned overlay views.

To test:
Run `cefclient.exe --use-views --hide-frame --hide-controls`
Add `--enable-chrome-runtime` for the same behavior using the Chrome location
bar instead of a text field.
This commit is contained in:
Marshall Greenblatt
2021-08-27 21:55:15 -04:00
parent 6f6072b857
commit 4a44e16a09
96 changed files with 3875 additions and 230 deletions

View File

@@ -0,0 +1,15 @@
// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#include "libcef/browser/chrome/views/chrome_views_util.h"
#include "libcef/browser/views/view_util.h"
namespace cef {
bool IsCefView(views::View* view) {
return view_util::GetFor(view, /*find_known_parent=*/false) != nullptr;
}
} // namespace cef

View File

@@ -0,0 +1,20 @@
// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_VIEWS_H_
#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_VIEWS_H_
#pragma once
namespace views {
class View;
}
namespace cef {
// Returns true if |view| is a CefView.
bool IsCefView(views::View* view);
} // namespace cef
#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_VIEWS_H_

View File

@@ -0,0 +1,330 @@
// Copyright 2021 The Chromium Embedded Framework Authors. Portions copyright
// 2011 The Chromium Authors. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.
#include "libcef/browser/views/overlay_view_host.h"
#include "libcef/browser/views/view_util.h"
#include "libcef/browser/views/window_view.h"
#include "base/i18n/rtl.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/theme_copying_widget.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/compositor/layer.h"
#if defined(USE_AURA)
#include "ui/aura/window.h"
#include "ui/views/view_constants_aura.h"
#endif
namespace {
class CefOverlayControllerImpl : public CefOverlayController {
public:
CefOverlayControllerImpl(CefOverlayViewHost* host, CefRefPtr<CefView> view)
: host_(host), view_(view) {}
bool IsValid() override {
// View validity implies that CefOverlayViewHost is still valid, because the
// Widget that it owns (and that owns the View) is still valid.
return view_ && view_->IsValid();
}
bool IsSame(CefRefPtr<CefOverlayController> that) override {
return that && that->GetContentsView()->IsSame(view_);
}
CefRefPtr<CefView> GetContentsView() override { return view_; }
CefRefPtr<CefWindow> GetWindow() override {
if (IsValid()) {
return view_util::GetWindowFor(host_->window_view()->GetWidget());
}
return nullptr;
}
cef_docking_mode_t GetDockingMode() override {
if (IsValid()) {
return host_->docking_mode();
}
return CEF_DOCKING_MODE_TOP_LEFT;
}
void Destroy() override {
if (IsValid()) {
host_->Destroy();
view_ = nullptr;
}
}
void SetBounds(const CefRect& bounds) override {
if (IsValid() && host_->docking_mode() == CEF_DOCKING_MODE_CUSTOM) {
host_->SetOverlayBounds(
gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
}
}
CefRect GetBounds() override {
if (IsValid()) {
const auto& bounds = host_->bounds();
return CefRect(bounds.x(), bounds.y(), bounds.width(), bounds.height());
}
return CefRect();
}
CefRect GetBoundsInScreen() override {
if (IsValid()) {
const auto& bounds = host_->widget()->GetWindowBoundsInScreen();
return CefRect(bounds.x(), bounds.y(), bounds.width(), bounds.height());
}
return CefRect();
}
void SetSize(const CefSize& size) override {
if (IsValid() && host_->docking_mode() == CEF_DOCKING_MODE_CUSTOM) {
// Update the size without changing the origin.
const auto& origin = host_->bounds().origin();
host_->SetOverlayBounds(
gfx::Rect(origin, gfx::Size(size.width, size.height)));
}
}
CefSize GetSize() override {
const auto& bounds = GetBounds();
return CefSize(bounds.width, bounds.height);
}
void SetPosition(const CefPoint& position) override {
if (IsValid() && host_->docking_mode() == CEF_DOCKING_MODE_CUSTOM) {
// Update the origin without changing the size.
const auto& size = host_->bounds().size();
host_->SetOverlayBounds(
gfx::Rect(gfx::Point(position.x, position.y), size));
}
}
CefPoint GetPosition() override {
const auto& bounds = GetBounds();
return CefPoint(bounds.x, bounds.y);
}
void SetInsets(const CefInsets& insets) override {
if (IsValid() && host_->docking_mode() != CEF_DOCKING_MODE_CUSTOM) {
host_->SetOverlayInsets(insets);
}
}
CefInsets GetInsets() override {
if (IsValid()) {
return host_->insets();
}
return CefInsets();
}
void SizeToPreferredSize() override {
if (IsValid()) {
if (host_->docking_mode() == CEF_DOCKING_MODE_CUSTOM) {
// Update the size without changing the origin.
const auto& origin = host_->bounds().origin();
const auto& preferred_size = host_->view()->GetPreferredSize();
host_->SetOverlayBounds(gfx::Rect(origin, preferred_size));
} else {
host_->MoveIfNecessary();
}
}
}
void SetVisible(bool visible) override {
if (IsValid()) {
if (visible) {
host_->MoveIfNecessary();
host_->widget()->Show();
} else {
host_->widget()->Hide();
}
}
}
bool IsVisible() override {
if (IsValid()) {
return host_->widget()->IsVisible();
}
return false;
}
bool IsDrawn() override { return IsVisible(); }
private:
CefOverlayViewHost* const host_;
CefRefPtr<CefView> view_;
IMPLEMENT_REFCOUNTING(CefOverlayControllerImpl);
DISALLOW_COPY_AND_ASSIGN(CefOverlayControllerImpl);
};
} // namespace
CefOverlayViewHost::CefOverlayViewHost(CefWindowView* window_view,
cef_docking_mode_t docking_mode)
: window_view_(window_view), docking_mode_(docking_mode) {}
void CefOverlayViewHost::Init(views::View* widget_view,
CefRefPtr<CefView> view) {
DCHECK(view);
// Match the logic in CEF_PANEL_IMPL_D::AddChildView().
auto controls_view = view->IsAttached()
? base::WrapUnique(view_util::GetFor(view))
: view_util::PassOwnership(view);
DCHECK(controls_view.get());
cef_controller_ = new CefOverlayControllerImpl(this, view);
// Initialize the Widget.
widget_ = std::make_unique<ThemeCopyingWidget>(window_view_->GetWidget());
views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
params.delegate = this;
params.name = "CefOverlayViewHost";
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.parent = window_view_->GetWidget()->GetNativeView();
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
params.activatable = views::Widget::InitParams::Activatable::kNo;
widget_->Init(std::move(params));
view_ = widget_->GetContentsView()->AddChildView(std::move(controls_view));
// Make the Widget background transparent. The View might still be opaque.
if (widget_->GetCompositor()) {
widget_->GetCompositor()->SetBackgroundColor(SK_ColorTRANSPARENT);
}
#if defined(USE_AURA)
// See matching logic in view_util::GetWindowFor.
widget_->GetNativeView()->SetProperty(views::kHostViewKey, widget_view);
#endif
if (cef::IsChromeRuntimeEnabled()) {
// Some attributes associated with a Chrome toolbar are located via the
// Widget. See matching logic in BrowserView::AddedToWidget.
auto browser_view = BrowserView::GetBrowserViewForNativeWindow(
view_util::GetNativeWindow(window_view_->GetWidget()));
if (browser_view) {
widget_->SetNativeWindowProperty(BrowserView::kBrowserViewKey,
browser_view);
}
}
// Set the initial bounds after the View has been added to the Widget.
// Otherwise, preferred size won't calculate correctly.
gfx::Rect bounds;
if (docking_mode_ == CEF_DOCKING_MODE_CUSTOM) {
if (view_->size().IsEmpty()) {
// Size to the preferred size to start.
view_->SizeToPreferredSize();
}
// Top-left origin with existing size.
bounds = gfx::Rect(gfx::Point(), view_->size());
} else {
bounds = ComputeBounds();
}
SetOverlayBounds(bounds);
// Register for future bounds change notifications.
view_->AddObserver(this);
// Initially hidden.
widget_->Hide();
}
void CefOverlayViewHost::Destroy() {
if (widget_ && !widget_->IsClosed()) {
// Remove the child View immediately. It may be reused by the client.
auto view = view_util::GetFor(view_, /*find_known_parent=*/false);
widget_->GetContentsView()->RemoveChildView(view_);
if (view) {
view_util::ResumeOwnership(view);
}
widget_->Close();
}
}
void CefOverlayViewHost::MoveIfNecessary() {
if (bounds_changing_ || docking_mode_ == CEF_DOCKING_MODE_CUSTOM) {
return;
}
SetOverlayBounds(ComputeBounds());
}
void CefOverlayViewHost::SetOverlayBounds(const gfx::Rect& bounds) {
// Avoid re-entrancy of this method.
if (bounds_changing_)
return;
gfx::Rect new_bounds = bounds;
// Keep the result inside the widget.
new_bounds.Intersect(window_view_->bounds());
if (new_bounds == bounds_)
return;
bounds_changing_ = true;
bounds_ = new_bounds;
if (view_->size() != bounds_.size()) {
view_->SetSize(bounds_.size());
}
widget_->SetBounds(bounds_);
bounds_changing_ = false;
}
void CefOverlayViewHost::SetOverlayInsets(const CefInsets& insets) {
if (insets == insets_)
return;
insets_ = insets;
MoveIfNecessary();
}
void CefOverlayViewHost::OnViewBoundsChanged(views::View* observed_view) {
MoveIfNecessary();
}
gfx::Rect CefOverlayViewHost::ComputeBounds() const {
// This method is only used with corner docking.
DCHECK_NE(docking_mode_, CEF_DOCKING_MODE_CUSTOM);
// Find the area we have to work with.
const auto& widget_bounds = window_view_->bounds();
// Ask the view how large an area it needs to draw on.
const auto& prefsize = view_->GetPreferredSize();
// Swap left/right docking with RTL.
const bool is_rtl = base::i18n::IsRTL();
// Dock to the correct corner, considering insets in the docking corner only.
int x = widget_bounds.x();
int y = widget_bounds.y();
if (((docking_mode_ == CEF_DOCKING_MODE_TOP_RIGHT ||
docking_mode_ == CEF_DOCKING_MODE_BOTTOM_RIGHT) &&
!is_rtl) ||
((docking_mode_ == CEF_DOCKING_MODE_TOP_LEFT ||
docking_mode_ == CEF_DOCKING_MODE_BOTTOM_LEFT) &&
is_rtl)) {
x += widget_bounds.width() - prefsize.width() - insets_.right;
} else {
x += insets_.left;
}
if (docking_mode_ == CEF_DOCKING_MODE_BOTTOM_LEFT ||
docking_mode_ == CEF_DOCKING_MODE_BOTTOM_RIGHT) {
y += widget_bounds.height() - prefsize.height() - insets_.bottom;
} else {
y += insets_.top;
}
return gfx::Rect(x, y, prefsize.width(), prefsize.height());
}

View File

@@ -0,0 +1,79 @@
// Copyright 2021 The Chromium Embedded Framework Authors. Portions copyright
// 2011 The Chromium Authors. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_VIEWS_OVERLAY_VIEW_HOST_H_
#define CEF_LIBCEF_BROWSER_VIEWS_OVERLAY_VIEW_HOST_H_
#pragma once
#include <memory>
#include "include/views/cef_overlay_controller.h"
#include "include/views/cef_view.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "ui/views/view_observer.h"
#include "ui/views/widget/widget_delegate.h"
class CefWindowView;
// Host class for a child Widget that behaves as an overlay control. Based on
// Chrome's DropdownBarHost.
class CefOverlayViewHost : public views::WidgetDelegate,
public views::ViewObserver {
public:
// |window_view| is the top-level view that contains this overlay.
CefOverlayViewHost(CefWindowView* window_view,
cef_docking_mode_t docking_mode);
// Initializes the CefOverlayViewHost. This creates the Widget that |view|
// paints into. |host_view| is the view whose position in the |window_view_|
// view hierarchy determines the z-order of the widget relative to views with
// layers and views with associated NativeViews.
void Init(views::View* host_view, CefRefPtr<CefView> view);
void Destroy();
void MoveIfNecessary();
void SetOverlayBounds(const gfx::Rect& bounds);
void SetOverlayInsets(const CefInsets& insets);
// views::ViewObserver methods:
void OnViewBoundsChanged(views::View* observed_view) override;
cef_docking_mode_t docking_mode() const { return docking_mode_; }
CefRefPtr<CefOverlayController> controller() const { return cef_controller_; }
CefWindowView* window_view() const { return window_view_; }
views::Widget* widget() const { return widget_.get(); }
views::View* view() const { return view_; }
gfx::Rect bounds() const { return bounds_; }
CefInsets insets() const { return insets_; }
private:
gfx::Rect ComputeBounds() const;
// The CefWindowView that created us.
CefWindowView* const window_view_;
const cef_docking_mode_t docking_mode_;
// Our view, which is responsible for drawing the UI.
views::View* view_ = nullptr;
// The Widget implementation that is created and maintained by the overlay.
// It contains |view_|.
std::unique_ptr<views::Widget> widget_;
CefRefPtr<CefOverlayController> cef_controller_;
gfx::Rect bounds_;
bool bounds_changing_ = false;
CefInsets insets_;
DISALLOW_COPY_AND_ASSIGN(CefOverlayViewHost);
};
#endif // CEF_LIBCEF_BROWSER_VIEWS_OVERLAY_VIEW_HOST_H_

View File

@@ -299,6 +299,7 @@
#include "base/logging.h"
#include "base/values.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/view.h"
// Helpers for template boiler-plate.
@@ -384,6 +385,8 @@ CEF_VIEW_IMPL_T class CefViewImpl : public CefViewAdapter, public CefViewClass {
CefSize GetSize() override;
void SetPosition(const CefPoint& position) override;
CefPoint GetPosition() override;
void SetInsets(const CefInsets& insets) override;
CefInsets GetInsets() override;
CefSize GetPreferredSize() override;
void SizeToPreferredSize() override;
CefSize GetMinimumSize() override;
@@ -571,6 +574,20 @@ CEF_VIEW_IMPL_T CefPoint CEF_VIEW_IMPL_D::GetPosition() {
return CefPoint(bounds.x, bounds.y);
}
CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetInsets(const CefInsets& insets) {
CEF_REQUIRE_VALID_RETURN_VOID();
gfx::Insets gfx_insets(insets.top, insets.left, insets.bottom, insets.right);
root_view()->SetBorder(
gfx_insets.IsEmpty() ? nullptr : views::CreateEmptyBorder(gfx_insets));
}
CEF_VIEW_IMPL_T CefInsets CEF_VIEW_IMPL_D::GetInsets() {
CEF_REQUIRE_VALID_RETURN(CefInsets());
const auto insets = root_view()->GetInsets();
return CefInsets(insets.top(), insets.left(), insets.bottom(),
insets.right());
}
CEF_VIEW_IMPL_T CefSize CEF_VIEW_IMPL_D::GetPreferredSize() {
CEF_REQUIRE_VALID_RETURN(CefSize());
const gfx::Size& size = root_view()->GetPreferredSize();

View File

@@ -20,6 +20,11 @@
#include "ui/display/win/screen_win.h"
#endif
#if defined(USE_AURA)
#include "ui/aura/window.h"
#include "ui/views/view_constants_aura.h"
#endif
namespace view_util {
namespace {
@@ -160,6 +165,18 @@ void ResumeOwnership(CefRefPtr<CefView> view) {
CefRefPtr<CefWindow> GetWindowFor(views::Widget* widget) {
CefRefPtr<CefWindow> window;
#if defined(USE_AURA)
// Retrieve the parent Widget for an overlay.
if (widget) {
// See matching logic in CefOverlayViewHost::Init.
auto widget_view =
widget->GetNativeView()->GetProperty(views::kHostViewKey);
if (widget_view) {
widget = widget_view->GetWidget();
}
}
#endif // defined(USE_AURA)
if (widget) {
// The views::WidgetDelegate should be a CefWindowView and |content_view|
// should be the same CefWindowView. However, just in case the views::Widget

View File

@@ -156,6 +156,13 @@ CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::Layout() {
// If Layout() did not provide a size then use the preferred size.
if (ParentClass::size().IsEmpty())
ParentClass::SizeToPreferredSize();
if (cef_delegate()) {
const auto new_bounds = ParentClass::bounds();
CefRect new_rect(new_bounds.x(), new_bounds.y(), new_bounds.width(),
new_bounds.height());
cef_delegate()->OnLayoutChanged(GetCefView(), new_rect);
}
}
CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::ViewHierarchyChanged(
@@ -202,8 +209,9 @@ CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyChildViewChanged(
// Only notify for children that have a known CEF root view. For example,
// don't notify when ScrollView adds child scroll bars.
CefRefPtr<CefView> child = view_util::GetFor(details.child, false);
if (child)
if (child) {
cef_delegate()->OnChildViewChanged(GetCefView(), details.is_add, child);
}
}
CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyParentViewChanged(
@@ -217,10 +225,11 @@ CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyParentViewChanged(
return;
// The immediate parent might be an intermediate view so find the closest
// known CEF root view.
// known CEF root view. |parent| might be nullptr for overlays.
CefRefPtr<CefView> parent = view_util::GetFor(details.parent, true);
DCHECK(parent);
cef_delegate()->OnParentViewChanged(GetCefView(), details.is_add, parent);
if (parent) {
cef_delegate()->OnParentViewChanged(GetCefView(), details.is_add, parent);
}
}
#endif // CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_

View File

@@ -12,6 +12,7 @@
#include "libcef/browser/views/view_util.h"
#include "libcef/browser/views/window_view.h"
#include "base/i18n/rtl.h"
#include "ui/base/test/ui_controls.h"
#include "ui/compositor/compositor.h"
#include "ui/gfx/geometry/rect.h"
@@ -278,6 +279,15 @@ CefRefPtr<CefImage> CefWindowImpl::GetWindowAppIcon() {
return nullptr;
}
CefRefPtr<CefOverlayController> CefWindowImpl::AddOverlayView(
CefRefPtr<CefView> view,
cef_docking_mode_t docking_mode) {
CEF_REQUIRE_VALID_RETURN(nullptr);
if (root_view())
return root_view()->AddOverlayView(view, docking_mode);
return nullptr;
}
void CefWindowImpl::GetDebugInfo(base::DictionaryValue* info,
bool include_children) {
ParentClass::GetDebugInfo(info, include_children);

View File

@@ -58,6 +58,9 @@ class CefWindowImpl
CefRefPtr<CefImage> GetWindowIcon() override;
void SetWindowAppIcon(CefRefPtr<CefImage> image) override;
CefRefPtr<CefImage> GetWindowAppIcon() override;
CefRefPtr<CefOverlayController> AddOverlayView(
CefRefPtr<CefView> view,
cef_docking_mode_t docking_mode) override;
void ShowMenu(CefRefPtr<CefMenuModel> menu_model,
const CefPoint& screen_point,
cef_menu_anchor_position_t anchor_position) override;

View File

@@ -312,6 +312,7 @@ void CefWindowView::CreateWidget() {
#endif
widget->Init(std::move(params));
widget->AddObserver(this);
// |widget| should now be associated with |this|.
DCHECK_EQ(widget, GetWidget());
@@ -465,6 +466,11 @@ void CefWindowView::ViewHierarchyChanged(
ParentClass::ViewHierarchyChanged(details);
}
void CefWindowView::OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) {
MoveOverlaysIfNecessary();
}
display::Display CefWindowView::GetDisplay() const {
const views::Widget* widget = GetWidget();
if (widget) {
@@ -500,6 +506,39 @@ void CefWindowView::SetWindowAppIcon(CefRefPtr<CefImage> window_app_icon) {
widget->UpdateWindowIcon();
}
CefRefPtr<CefOverlayController> CefWindowView::AddOverlayView(
CefRefPtr<CefView> view,
cef_docking_mode_t docking_mode) {
DCHECK(view.get());
DCHECK(view->IsValid());
if (!view.get() || !view->IsValid())
return nullptr;
views::Widget* widget = GetWidget();
if (widget) {
// Owned by the View hierarchy. Acts as a z-order reference for the overlay.
auto overlay_host_view = AddChildView(std::make_unique<views::View>());
overlay_hosts_.push_back(
std::make_unique<CefOverlayViewHost>(this, docking_mode));
auto& overlay_host = overlay_hosts_.back();
overlay_host->Init(overlay_host_view, view);
return overlay_host->controller();
}
return nullptr;
}
void CefWindowView::MoveOverlaysIfNecessary() {
if (overlay_hosts_.empty())
return;
for (auto& overlay_host : overlay_hosts_) {
overlay_host->MoveIfNecessary();
}
}
void CefWindowView::SetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) {
if (regions.empty()) {

View File

@@ -6,19 +6,24 @@
#define CEF_LIBCEF_BROWSER_VIEWS_WINDOW_VIEW_H_
#pragma once
#include <vector>
#include "include/views/cef_window.h"
#include "include/views/cef_window_delegate.h"
#include "libcef/browser/views/overlay_view_host.h"
#include "libcef/browser/views/panel_view.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/display/display.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/widget_observer.h"
// Manages the views-based root window. This object will be deleted
// automatically when the associated root window is destroyed.
class CefWindowView
: public CefPanelView<views::WidgetDelegateView, CefWindowDelegate> {
: public CefPanelView<views::WidgetDelegateView, CefWindowDelegate>,
public views::WidgetObserver {
public:
typedef CefPanelView<views::WidgetDelegateView, CefWindowDelegate>
ParentClass;
@@ -70,6 +75,10 @@ class CefWindowView
void ViewHierarchyChanged(
const views::ViewHierarchyChangedDetails& details) override;
// views::WidgetObserver methods:
void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) override;
// Returns the Display containing this Window.
display::Display GetDisplay() const;
@@ -89,6 +98,10 @@ class CefWindowView
void SetWindowAppIcon(CefRefPtr<CefImage> window_app_icon);
CefRefPtr<CefImage> window_app_icon() const { return window_app_icon_; }
CefRefPtr<CefOverlayController> AddOverlayView(
CefRefPtr<CefView> view,
cef_docking_mode_t docking_mode);
// Set/get the draggable regions.
void SetDraggableRegions(const std::vector<CefDraggableRegion>& regions);
SkRegion* draggable_region() const { return draggable_region_.get(); }
@@ -100,6 +113,8 @@ class CefWindowView
// Called when removed from the Widget and before |this| is deleted.
void DeleteDelegate();
void MoveOverlaysIfNecessary();
// Not owned by this object.
Delegate* window_delegate_;
@@ -112,6 +127,9 @@ class CefWindowView
std::unique_ptr<SkRegion> draggable_region_;
// Hosts for overlay widgets.
std::vector<std::unique_ptr<CefOverlayViewHost>> overlay_hosts_;
DISALLOW_COPY_AND_ASSIGN(CefWindowView);
};

View File

@@ -0,0 +1,11 @@
// Copyright 2021 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "include/cef_i18n_util.h"
#include "base/i18n/rtl.h"
bool CefIsRTL() {
return base::i18n::IsRTL();
}