Commit c6f0a71b authored by Thomas Lukaszewicz's avatar Thomas Lukaszewicz Committed by Commit Bot

Added support for clip path to Views painting to Layers.

Views with backing Layers that set a |clip_path_| will now create
a ViewMaskLayer object that masks the area designated by the clip.
The View Layer and all child Layers will be masked by the
ViewLayerMask.

Made some small changes to the original set_clip_path() setter and
calling functions.

Bug: None
Change-Id: Id746a72042d9f114144db01e289a603abe5afe9a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2031640Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Commit-Queue: Thomas Lukaszewicz <tluk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#739105}
parent b6b54d44
...@@ -123,7 +123,7 @@ void AmbientAssistantContainerView::InitLayout() { ...@@ -123,7 +123,7 @@ void AmbientAssistantContainerView::InitLayout() {
constexpr int kClipCircleRadius = kAvatarImageSizeDip / 2; constexpr int kClipCircleRadius = kAvatarImageSizeDip / 2;
circular_mask.addCircle(kClipCircleRadius, kClipCircleRadius, circular_mask.addCircle(kClipCircleRadius, kClipCircleRadius,
kClipCircleRadius); kClipCircleRadius);
avatar_view_->set_clip_path(circular_mask); avatar_view_->SetClipPath(circular_mask);
} }
} // namespace ash } // namespace ash
...@@ -800,7 +800,7 @@ void LockScreenMediaControlsView::SetArtwork( ...@@ -800,7 +800,7 @@ void LockScreenMediaControlsView::SetArtwork(
session_artwork_->SetImage(*img); session_artwork_->SetImage(*img);
Layout(); Layout();
session_artwork_->set_clip_path(GetArtworkClipPath()); session_artwork_->SetClipPath(GetArtworkClipPath());
} }
SkPath LockScreenMediaControlsView::GetArtworkClipPath() const { SkPath LockScreenMediaControlsView::GetArtworkClipPath() const {
......
...@@ -155,7 +155,7 @@ class AutoclickScrollButton : public CustomShapeButton, ...@@ -155,7 +155,7 @@ class AutoclickScrollButton : public CustomShapeButton,
} }
SetPreferredSize(size_); SetPreferredSize(size_);
set_clip_path(CreateCustomShapePath(gfx::Rect(GetPreferredSize()))); SetClipPath(CreateCustomShapePath(gfx::Rect(GetPreferredSize())));
SetEventTargeter(std::make_unique<views::ViewTargeter>(this)); SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
} }
......
...@@ -161,12 +161,12 @@ void AutofillPopupBaseView::RemoveWidgetObservers() { ...@@ -161,12 +161,12 @@ void AutofillPopupBaseView::RemoveWidgetObservers() {
views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
} }
void AutofillPopupBaseView::SetClipPath() { void AutofillPopupBaseView::UpdateClipPath() {
SkRect local_bounds = gfx::RectToSkRect(GetLocalBounds()); SkRect local_bounds = gfx::RectToSkRect(GetLocalBounds());
SkScalar radius = SkIntToScalar(GetCornerRadius()); SkScalar radius = SkIntToScalar(GetCornerRadius());
SkPath clip_path; SkPath clip_path;
clip_path.addRoundRect(local_bounds, radius, radius); clip_path.addRoundRect(local_bounds, radius, radius);
set_clip_path(clip_path); SetClipPath(clip_path);
} }
void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() { void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() {
...@@ -184,7 +184,7 @@ void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() { ...@@ -184,7 +184,7 @@ void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() {
GetWidget()->SetBounds(popup_bounds); GetWidget()->SetBounds(popup_bounds);
Layout(); Layout();
SetClipPath(); UpdateClipPath();
SchedulePaint(); SchedulePaint();
} }
......
...@@ -55,7 +55,7 @@ class AutofillPopupBaseView : public views::WidgetDelegateView, ...@@ -55,7 +55,7 @@ class AutofillPopupBaseView : public views::WidgetDelegateView,
// Ensure the child views are not rendered beyond the bubble border // Ensure the child views are not rendered beyond the bubble border
// boundaries. Should be overridden together with CreateBorder. // boundaries. Should be overridden together with CreateBorder.
void SetClipPath(); void UpdateClipPath();
// Update size of popup and paint (virtual for testing). // Update size of popup and paint (virtual for testing).
virtual void DoUpdateBoundsAndRedrawPopup(); virtual void DoUpdateBoundsAndRedrawPopup();
......
...@@ -1258,7 +1258,7 @@ void AutofillPopupViewNativeViews::DoUpdateBoundsAndRedrawPopup() { ...@@ -1258,7 +1258,7 @@ void AutofillPopupViewNativeViews::DoUpdateBoundsAndRedrawPopup() {
popup_bounds.Inset(-GetWidget()->GetRootView()->border()->GetInsets()); popup_bounds.Inset(-GetWidget()->GetRootView()->border()->GetInsets());
GetWidget()->SetBounds(popup_bounds); GetWidget()->SetBounds(popup_bounds);
SetClipPath(); UpdateClipPath();
SchedulePaint(); SchedulePaint();
} }
......
...@@ -618,8 +618,8 @@ void NotificationViewMD::Layout() { ...@@ -618,8 +618,8 @@ void NotificationViewMD::Layout() {
bounds.set_height(bounds.height() * 2); bounds.set_height(bounds.height() * 2);
path.addRoundRect(gfx::RectToSkRect(bounds), kCornerRadius, kCornerRadius); path.addRoundRect(gfx::RectToSkRect(bounds), kCornerRadius, kCornerRadius);
action_buttons_row_->set_clip_path(path); action_buttons_row_->SetClipPath(path);
inline_reply_->set_clip_path(path); inline_reply_->SetClipPath(path);
} }
// The animation is needed to run inside of the border. // The animation is needed to run inside of the border.
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/scoped_observer.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
...@@ -40,7 +41,6 @@ ...@@ -40,7 +41,6 @@
#include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/interpolated_transform.h" #include "ui/gfx/interpolated_transform.h"
#include "ui/gfx/scoped_canvas.h" #include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h" #include "ui/gfx/transform.h"
#include "ui/native_theme/native_theme.h" #include "ui/native_theme/native_theme.h"
#include "ui/views/accessibility/ax_event_manager.h" #include "ui/views/accessibility/ax_event_manager.h"
...@@ -117,6 +117,66 @@ class ScopedChildrenLock { ...@@ -117,6 +117,66 @@ class ScopedChildrenLock {
} // namespace internal } // namespace internal
////////////////////////////////////////////////////////////////////////////////
// ViewMaskLayer
// This class is responsible for creating a masking layer for a view that paints
// to a layer. It tracks the size of the layer it is masking.
class VIEWS_EXPORT ViewMaskLayer : public ui::LayerDelegate,
public ViewObserver {
public:
// Note that |observed_view| must outlive the ViewMaskLayer instance.
ViewMaskLayer(const SkPath& path, View* observed_view);
ViewMaskLayer(const ViewMaskLayer& mask_layer) = delete;
ViewMaskLayer& operator=(const ViewMaskLayer& mask_layer) = delete;
~ViewMaskLayer() override;
ui::Layer* layer() { return &layer_; }
private:
// ui::LayerDelegate:
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override;
void OnPaintLayer(const ui::PaintContext& context) override;
// views::ViewObserver:
void OnViewBoundsChanged(View* observed_view) override;
ScopedObserver<View, ViewObserver> observed_view_{this};
SkPath path_;
ui::Layer layer_;
};
ViewMaskLayer::ViewMaskLayer(const SkPath& path, View* observed_view)
: path_{path} {
layer_.set_delegate(this);
layer_.SetFillsBoundsOpaquely(false);
layer_.SetName("ViewMaskLayer");
observed_view_.Add(observed_view);
OnViewBoundsChanged(observed_view);
}
ViewMaskLayer::~ViewMaskLayer() {
layer_.set_delegate(nullptr);
}
void ViewMaskLayer::OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) {}
void ViewMaskLayer::OnPaintLayer(const ui::PaintContext& context) {
cc::PaintFlags flags;
flags.setAlpha(255);
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setAntiAlias(true);
ui::PaintRecorder recorder(context, layer()->size());
recorder.canvas()->DrawPath(path_, flags);
}
void ViewMaskLayer::OnViewBoundsChanged(View* observed_view) {
layer_.SetBounds(observed_view->GetLocalBounds());
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// View, public: // View, public:
...@@ -516,6 +576,12 @@ gfx::Transform View::GetTransform() const { ...@@ -516,6 +576,12 @@ gfx::Transform View::GetTransform() const {
return transform; return transform;
} }
void View::SetClipPath(const SkPath& path) {
clip_path_ = path;
if (layer())
CreateMaskLayer();
}
void View::SetTransform(const gfx::Transform& transform) { void View::SetTransform(const gfx::Transform& transform) {
if (transform.IsIdentity()) { if (transform.IsIdentity()) {
if (layer()) if (layer())
...@@ -549,6 +615,9 @@ void View::SetPaintToLayer(ui::LayerType layer_type) { ...@@ -549,6 +615,9 @@ void View::SetPaintToLayer(ui::LayerType layer_type) {
// |CreateOrDestroyLayer()| is therefore not necessary. // |CreateOrDestroyLayer()| is therefore not necessary.
CreateLayer(layer_type); CreateLayer(layer_type);
if (!clip_path_.isEmpty() && !mask_layer_)
CreateMaskLayer();
// Notify the parent chain about the layer change. // Notify the parent chain about the layer change.
NotifyParentsOfLayerChange(); NotifyParentsOfLayerChange();
} }
...@@ -1766,6 +1835,8 @@ void View::DestroyLayerImpl(LayerChangeNotifyBehavior notify_parents) { ...@@ -1766,6 +1835,8 @@ void View::DestroyLayerImpl(LayerChangeNotifyBehavior notify_parents) {
new_parent->Add(child); new_parent->Add(child);
} }
mask_layer_.reset();
LayerOwner::DestroyLayer(); LayerOwner::DestroyLayer();
if (new_parent) if (new_parent)
...@@ -2626,6 +2697,12 @@ void View::ReparentLayer(ui::Layer* parent_layer) { ...@@ -2626,6 +2697,12 @@ void View::ReparentLayer(ui::Layer* parent_layer) {
MoveLayerToParent(layer(), LayerOffsetData(layer()->device_scale_factor())); MoveLayerToParent(layer(), LayerOffsetData(layer()->device_scale_factor()));
} }
void View::CreateMaskLayer() {
DCHECK(layer());
mask_layer_ = std::make_unique<views::ViewMaskLayer>(clip_path_, this);
layer()->SetMaskLayer(mask_layer_->layer());
}
// Input ----------------------------------------------------------------------- // Input -----------------------------------------------------------------------
bool View::ProcessMousePressed(const ui::MouseEvent& event) { bool View::ProcessMousePressed(const ui::MouseEvent& event) {
......
...@@ -80,8 +80,9 @@ class DragController; ...@@ -80,8 +80,9 @@ class DragController;
class FocusManager; class FocusManager;
class FocusTraversable; class FocusTraversable;
class LayoutManager; class LayoutManager;
class ViewAccessibility;
class ScrollView; class ScrollView;
class ViewAccessibility;
class ViewMaskLayer;
class ViewObserver; class ViewObserver;
class Widget; class Widget;
class WordLookupClient; class WordLookupClient;
...@@ -596,7 +597,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, ...@@ -596,7 +597,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
gfx::Transform GetTransform() const; gfx::Transform GetTransform() const;
// Clipping is done relative to the view's local bounds. // Clipping is done relative to the view's local bounds.
void set_clip_path(const SkPath& path) { clip_path_ = path; } void SetClipPath(const SkPath& path);
const SkPath& clip_path() const { return clip_path_; }
// Sets the transform to the supplied transform. // Sets the transform to the supplied transform.
void SetTransform(const gfx::Transform& transform); void SetTransform(const gfx::Transform& transform);
...@@ -1787,6 +1789,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, ...@@ -1787,6 +1789,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
void SetLayerBounds(const gfx::Size& size_in_dip, void SetLayerBounds(const gfx::Size& size_in_dip,
const LayerOffsetData& layer_offset_data); const LayerOffsetData& layer_offset_data);
// Creates a mask layer for the current view using |clip_path_|.
void CreateMaskLayer();
// Input --------------------------------------------------------------------- // Input ---------------------------------------------------------------------
bool ProcessMousePressed(const ui::MouseEvent& event); bool ProcessMousePressed(const ui::MouseEvent& event);
...@@ -1922,8 +1927,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, ...@@ -1922,8 +1927,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Transformations ----------------------------------------------------------- // Transformations -----------------------------------------------------------
// Painting will be clipped to this path. TODO(estade): this doesn't work for // Painting will be clipped to this path.
// layers.
SkPath clip_path_; SkPath clip_path_;
// Layout -------------------------------------------------------------------- // Layout --------------------------------------------------------------------
...@@ -1979,6 +1983,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, ...@@ -1979,6 +1983,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// beneath. // beneath.
std::vector<ui::Layer*> layers_beneath_; std::vector<ui::Layer*> layers_beneath_;
// If painting to a layer |mask_layer_| will mask the current layer and all
// child layers to within the |clip_path_|.
std::unique_ptr<views::ViewMaskLayer> mask_layer_;
// Accelerators -------------------------------------------------------------- // Accelerators --------------------------------------------------------------
// Focus manager accelerators registered on. // Focus manager accelerators registered on.
......
...@@ -251,7 +251,7 @@ void NonClientView::Layout() { ...@@ -251,7 +251,7 @@ void NonClientView::Layout() {
SkPath client_clip; SkPath client_clip;
if (frame_view_->GetClientMask(client_view_->size(), &client_clip)) if (frame_view_->GetClientMask(client_view_->size(), &client_clip))
client_view_->set_clip_path(client_clip); client_view_->SetClipPath(client_clip);
if (overlay_view_) if (overlay_view_)
overlay_view_->SetBoundsRect(GetLocalBounds()); overlay_view_->SetBoundsRect(GetLocalBounds());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment