View::GetVisibleBounds (not)clipping

179 views
Skip to first unread message

Jakub Lason

unread,
Aug 27, 2024, 7:42:08 AMAug 27
to chromi...@chromium.org
Hi,

View::GetVisibleBounds seems not to take any clipping/layers into account. Is that intentional? In the most simple case when the view has a clipping path set it will always return the entire view's bounds as a visible rect. 

/K

Peter Kasting

unread,
Aug 27, 2024, 11:00:27 AMAug 27
to ku...@opera.com, chromi...@chromium.org
On Tue, Aug 27, 2024 at 4:39 AM Jakub Lason <ku...@opera.com> wrote:
View::GetVisibleBounds seems not to take any clipping/layers into account. Is that intentional? In the most simple case when the view has a clipping path set it will always return the entire view's bounds as a visible rect.

Historically clipping paths have mostly been used for e.g. rounded corners and other shape tweaks that don't actually affect the bounds rect. While it would certainly be possible to make the visible bounds calculation intersect with the clip's bounding rect, I would worry about both unintended effects, and a false sense of security around e.g. events in the clipped-off area going where you expect.

What sort of use case do you have? Maybe this is an XY problem.

PK

Jakub Lason

unread,
Aug 27, 2024, 3:23:15 PMAug 27
to Peter Kasting, chromi...@chromium.org
It's an issue with NativeViewHost and it becomes problematic when the same setup of views gives you different visual results.

Assuming you have following view structure:

+ View0 (size:50x50)
    |
    + View1 (size:200x200) with established layer
        |
        +  NativeViewHost (a WebView for example) (size:200x200)
        +  Button (size:200x200)


With such structure the View1 is not clipped by the View0 because it establishes a separate layer. The Button descendant contributes to the View1's layer and it is not clipped by the View0 as well. However, unlike the button the NativeViewHost clips itself to the size of View0 (by setting the hosted NativeView's bounds) as this is what GetVisibleBounds returns. OTOH, if you explicitly apply a clip path to the View1 it will clip the view itself including the button descendant but not the NativeView hosted by the NativeViewHost as the rect recturned by GetVisibleBounds ignores view's clip settings. In the end we have sibling views where one is clipped by its incestor and the other one is not.

Here's the example code and the visual output:

    auto* outer = container->AddChildView(std::make_unique<views::View>());
  outer->SetBounds(0, 0, 200, 200);
  outer->SetBorder(views::CreateSolidBorder(1, SK_ColorMAGENTA));

  auto* inner = outer->AddChildView(std::make_unique<views::View>());
  inner->SetBounds(0, 0, 400, 400);
  inner->SetBackground(views::CreateSolidBackground(SK_ColorYELLOW));
  inner->SetPaintToLayer();

  webview_ = inner->AddChildView(std::make_unique<WebView>(browser_context_));
  webview_->GetWebContents()->SetDelegate(this);
  webview_->SetBounds(0, 0, 400, 400);

  auto* b = inner->AddChildView(std::make_unique<views::MdTextButton>());
  b->SetText(u"Test");
  b->SetBounds(300, 300, 50, 50);

  webview_->LoadInitialURL(GURL("http://www.google.com/"));


image.png

/K

Peter Kasting

unread,
Aug 27, 2024, 3:38:09 PMAug 27
to Jakub Lason, chromi...@chromium.org
On Tue, Aug 27, 2024 at 12:19 PM Jakub Lason <ku...@opera.com> wrote:
It's an issue with NativeViewHost and it becomes problematic when the same setup of views gives you different visual results.

Assuming you have following view structure:

+ View0 (size:50x50)
    |
    + View1 (size:200x200) with established layer
        |
        +  NativeViewHost (a WebView for example) (size:200x200)
        +  Button (size:200x200)


With such structure the View1 is not clipped by the View0 because it establishes a separate layer. The Button descendant contributes to the View1's layer and it is not clipped by the View0 as well. However, unlike the button the NativeViewHost clips itself to the size of View0 (by setting the hosted NativeView's bounds) as this is what GetVisibleBounds returns. OTOH, if you explicitly apply a clip path to the View1 it will clip the view itself including the button descendant but not the NativeView hosted by the NativeViewHost as the rect recturned by GetVisibleBounds ignores view's clip settings. In the end we have sibling views where one is clipped by its incestor and the other one is not.

Definitely seems problematic.

Drawing to a layer to extend past your parent's bounds is always going to be fraught (can have platform-specific weird things happen if this places you outside the window), so if there's a way to avoid it, I'd do that. That doesn't fix this issue, though.

I assume NativeViewHost is not so much needing to clip itself as to clip the NativeView it's hosting. And I assume it's using GetVisibleBounds() because it wants to take transforms etc. into account. In which case it might make sense to fold clips in there too, since I assume the transforms it accounts for are layer-based just like the clip is. I suggest you reach out to vollick@ (knows how to triage layers/compositing questions) and copy dpranke@ (Views team member who wants to spin up more knowledge on layers and compositing).

PK
Reply all
Reply to author
Forward
0 new messages