feat: customize border radius of Views (#42320)
* feat: add View#setBorderRadius test: initial setBorderRadius tests fix: robustly set border radius chore: add PAUSE_CAPTURE_TESTS for easier screencap dev feat: add view border radius support test: view border radius refactor: cleanup view code * maybe delay capture to fix tests? * refactor: retry screen captures in an attempt to fix flakiness * refactor: ScreenCapture constructor no longer async * increase screen capture timeout, feels a little short * refactor: move rounded rect util into chromium_src * skip some capture tests on mas
This commit is contained in:
parent
cbd11bb605
commit
778d3098a0
15 changed files with 261 additions and 90 deletions
|
@ -10,6 +10,7 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "ash/style/rounded_rect_cutout_path_builder.h"
|
||||
#include "gin/data_object_builder.h"
|
||||
#include "gin/wrappable.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
|
@ -338,6 +339,38 @@ void View::SetBackgroundColor(std::optional<WrappedSkColor> color) {
|
|||
view_->SetBackground(color ? views::CreateSolidBackground(*color) : nullptr);
|
||||
}
|
||||
|
||||
void View::SetBorderRadius(int radius) {
|
||||
border_radius_ = radius;
|
||||
ApplyBorderRadius();
|
||||
}
|
||||
|
||||
void View::ApplyBorderRadius() {
|
||||
if (!border_radius_.has_value() || !view_)
|
||||
return;
|
||||
|
||||
auto size = view_->bounds().size();
|
||||
|
||||
// Restrict border radius to the constraints set in the path builder class.
|
||||
// If the constraints are exceeded, the builder will crash.
|
||||
int radius;
|
||||
{
|
||||
float r = border_radius_.value() * 1.f;
|
||||
r = std::min(r, size.width() / 2.f);
|
||||
r = std::min(r, size.height() / 2.f);
|
||||
r = std::max(r, 0.f);
|
||||
radius = std::floor(r);
|
||||
}
|
||||
|
||||
// RoundedRectCutoutPathBuilder has a minimum size of 32 x 32.
|
||||
if (radius > 0 && size.width() >= 32 && size.height() >= 32) {
|
||||
auto builder = ash::RoundedRectCutoutPathBuilder(gfx::SizeF(size));
|
||||
builder.CornerRadius(radius);
|
||||
view_->SetClipPath(builder.Build());
|
||||
} else {
|
||||
view_->SetClipPath(SkPath());
|
||||
}
|
||||
}
|
||||
|
||||
void View::SetVisible(bool visible) {
|
||||
if (!view_)
|
||||
return;
|
||||
|
@ -345,6 +378,7 @@ void View::SetVisible(bool visible) {
|
|||
}
|
||||
|
||||
void View::OnViewBoundsChanged(views::View* observed_view) {
|
||||
ApplyBorderRadius();
|
||||
Emit("bounds-changed");
|
||||
}
|
||||
|
||||
|
@ -393,6 +427,7 @@ void View::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setBounds", &View::SetBounds)
|
||||
.SetMethod("getBounds", &View::GetBounds)
|
||||
.SetMethod("setBackgroundColor", &View::SetBackgroundColor)
|
||||
.SetMethod("setBorderRadius", &View::SetBorderRadius)
|
||||
.SetMethod("setLayout", &View::SetLayout)
|
||||
.SetMethod("setVisible", &View::SetVisible);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class View : public gin_helper::EventEmitter<View>,
|
|||
void SetLayout(v8::Isolate* isolate, v8::Local<v8::Object> value);
|
||||
std::vector<v8::Local<v8::Value>> GetChildren();
|
||||
void SetBackgroundColor(std::optional<WrappedSkColor> color);
|
||||
void SetBorderRadius(int radius);
|
||||
void SetVisible(bool visible);
|
||||
|
||||
// views::ViewObserver
|
||||
|
@ -44,6 +45,7 @@ class View : public gin_helper::EventEmitter<View>,
|
|||
void OnViewIsDeleting(views::View* observed_view) override;
|
||||
|
||||
views::View* view() const { return view_; }
|
||||
std::optional<int> border_radius() const { return border_radius_; }
|
||||
|
||||
// disable copy
|
||||
View(const View&) = delete;
|
||||
|
@ -58,9 +60,11 @@ class View : public gin_helper::EventEmitter<View>,
|
|||
void set_delete_view(bool should) { delete_view_ = should; }
|
||||
|
||||
private:
|
||||
void ApplyBorderRadius();
|
||||
void ReorderChildView(gin::Handle<View> child, size_t index);
|
||||
|
||||
std::vector<v8::Global<v8::Object>> child_views_;
|
||||
std::optional<int> border_radius_;
|
||||
|
||||
bool delete_view_ = true;
|
||||
raw_ptr<views::View> view_ = nullptr;
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "shell/common/options_switches.h"
|
||||
#include "third_party/skia/include/core/SkRegion.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/gfx/geometry/rounded_corners_f.h"
|
||||
#include "ui/views/controls/webview/webview.h"
|
||||
#include "ui/views/layout/flex_layout_types.h"
|
||||
#include "ui/views/view_class_properties.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
@ -65,6 +67,25 @@ void WebContentsView::SetBackgroundColor(std::optional<WrappedSkColor> color) {
|
|||
}
|
||||
}
|
||||
|
||||
void WebContentsView::SetBorderRadius(int radius) {
|
||||
View::SetBorderRadius(radius);
|
||||
ApplyBorderRadius();
|
||||
}
|
||||
|
||||
void WebContentsView::ApplyBorderRadius() {
|
||||
if (border_radius().has_value() && api_web_contents_ && view()->GetWidget()) {
|
||||
auto* web_view = api_web_contents_->inspectable_web_contents()
|
||||
->GetView()
|
||||
->contents_web_view();
|
||||
|
||||
// WebView won't exist for offscreen rendering.
|
||||
if (web_view) {
|
||||
web_view->holder()->SetCornerRadii(
|
||||
gfx::RoundedCornersF(border_radius().value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int WebContentsView::NonClientHitTest(const gfx::Point& point) {
|
||||
if (api_web_contents_) {
|
||||
gfx::Point local_point(point);
|
||||
|
@ -93,6 +114,7 @@ void WebContentsView::OnViewAddedToWidget(views::View* observed_view) {
|
|||
// because that's handled in the WebContents dtor called prior.
|
||||
api_web_contents_->SetOwnerWindow(native_window);
|
||||
native_window->AddDraggableRegionProvider(this);
|
||||
ApplyBorderRadius();
|
||||
}
|
||||
|
||||
void WebContentsView::OnViewRemovedFromWidget(views::View* observed_view) {
|
||||
|
@ -198,6 +220,7 @@ void WebContentsView::BuildPrototype(
|
|||
prototype->SetClassName(gin::StringToV8(isolate, "WebContentsView"));
|
||||
gin_helper::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
.SetMethod("setBackgroundColor", &WebContentsView::SetBackgroundColor)
|
||||
.SetMethod("setBorderRadius", &WebContentsView::SetBorderRadius)
|
||||
.SetProperty("webContents", &WebContentsView::GetWebContents);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ class WebContentsView : public View,
|
|||
// Public APIs.
|
||||
gin::Handle<WebContents> GetWebContents(v8::Isolate* isolate);
|
||||
void SetBackgroundColor(std::optional<WrappedSkColor> color);
|
||||
void SetBorderRadius(int radius);
|
||||
|
||||
int NonClientHitTest(const gfx::Point& point) override;
|
||||
|
||||
|
@ -57,6 +58,8 @@ class WebContentsView : public View,
|
|||
private:
|
||||
static gin_helper::WrappableBase* New(gin_helper::Arguments* args);
|
||||
|
||||
void ApplyBorderRadius();
|
||||
|
||||
// Keep a reference to v8 wrapper.
|
||||
v8::Global<v8::Value> web_contents_;
|
||||
raw_ptr<api::WebContents> api_web_contents_;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue