[iOS][actor-login] Update `CheckViewAreaVisible` to match Blink [chromium/src : main]

0 views
Skip to first unread message

Ginny Huang (Gerrit)

unread,
Jul 7, 2026, 6:10:47 PM (yesterday) Jul 7
to Vincent Boisselle, android-bu...@system.gserviceaccount.com, chromium...@chromium.org, browser-comp...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
Attention needed from Vincent Boisselle

Ginny Huang voted

Auto-Submit+1
Commit-Queue+1
Open in Gerrit

Related details

Attention is currently required from:
  • Vincent Boisselle
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: I8293ac31a005133cf2eee68da5460e7ed9c4844e
Gerrit-Change-Number: 8047322
Gerrit-PatchSet: 7
Gerrit-Owner: Ginny Huang <ginny...@chromium.org>
Gerrit-Reviewer: Ginny Huang <ginny...@chromium.org>
Gerrit-Reviewer: Vincent Boisselle <vi...@google.com>
Gerrit-Attention: Vincent Boisselle <vi...@google.com>
Gerrit-Comment-Date: Tue, 07 Jul 2026 22:10:40 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy

Vincent Boisselle (Gerrit)

unread,
11:54 AM (11 hours ago) 11:54 AM
to Ginny Huang, Chromium LUCI CQ, android-bu...@system.gserviceaccount.com, chromium...@chromium.org, browser-comp...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
Attention needed from Ginny Huang

Vincent Boisselle added 19 comments

File components/password_manager/ios/resources/password_controller.ts
Line 663, Patchset 7 (Latest):
Vincent Boisselle . unresolved

The commit message refers to this as `getContainingBlock`, but the function is named `getContainingBlockForElement`. Consider updating the commit message or function name for consistency.

Line 664, Patchset 7 (Latest): // Handles cases when the nearest containing block might be further up in the
Vincent Boisselle . unresolved

Potential TODO

idk how we want to deal with shadow roots, they are actually ignored by the model afaik so might not be worth considering them at this point but maybe later on once we incorporate shadow dom into the annotated page content

Note: If `element` is inside a Shadow Root (Web Component), `element.parentElement` is `null` (since its parent is a `ShadowRoot`, which is not an `Element`). This will prevent `getContainingBlockForElement` from traversing past shadow boundaries to check clipping on the host element or host ancestors. Consider using `(element.assignedSlot || element.parentElement || (element.getRootNode() as ShadowRoot)?.host) as Element | null` if form elements inside Shadow DOM need to be supported.

Line 667, Patchset 7 (Latest): const containerStyle = window.getComputedStyle(container);
Vincent Boisselle . unresolved

Put the logic to determine whether the container is eligible in a function that returns a boolean which will control the loop, makes the flow easier to read

Line 669, Patchset 7 (Latest): if (position === 'absolute' && containerStyle.position !== 'static') {
Vincent Boisselle . unresolved

this condition is true in 99% of the cases with a small exception

"For normal flow elements ( position other than fixed and absolute ), the containing block is the parent element (unless the parent does not generate a box, e.g. display: contents )."

Line 669, Patchset 7 (Latest): if (position === 'absolute' && containerStyle.position !== 'static') {
Vincent Boisselle . unresolved

Comment out the reason why these conditions make the container eligible

Line 674, Patchset 7 (Latest): if (containerStyle.transform !== 'none' ||
Vincent Boisselle . unresolved

Comment out the reason why these conditions make the container eligible

Line 683, Patchset 7 (Latest): const contain = containerStyle.contain;
Vincent Boisselle . unresolved

Avoid using `(containerStyle as any).webkitBackdropFilter`. You can use `containerStyle.getPropertyValue(-webkit-backdrop-filter)` to access `-webkit-backdrop-filter` in a type-safe manner without casting to `any`.

Line 684, Patchset 7 (Latest): if (contain &&
Vincent Boisselle . unresolved

Comment out the reason why these conditions make the container eligible

Line 690, Patchset 7 (Latest): const willChange = containerStyle.willChange;
Vincent Boisselle . unresolved

Comment out the reason why these conditions make the container eligible

Line 693, Patchset 7 (Latest): willChange.includes('perspective') || willChange.includes('filter') ||
Vincent Boisselle . unresolved

Per CSS Containment 3, `container-type: inline-size` or `size` (CSS Container Queries) also establishes layout containment and creates a containing block for `position: absolute` descendants. Consider adding `containerStyle.containerType !== none`.

Line 724, Patchset 7 (Latest):
Vincent Boisselle . unresolved

Note: Ancestors with CSS `clip-path` or `mask` clip all descendants (including `position: absolute` or `fixed` elements) regardless of whether the ancestor is a containing block. Consider checking if `containerStyle.clipPath !== none` or `containerStyle.mask !== none` / `webkitMask !== none` in the clipping check.

Line 732, Patchset 7 (Latest): if (bottom <= top || right <= left) {
Vincent Boisselle . unresolved

comment out what this check does

Line 735, Patchset 7 (Latest):
Vincent Boisselle . unresolved

`clippingElement.getBoundingClientRect()` returns the border-box (including border and scrollbar width). However, CSS `overflow` clips content at the padding-box boundary. If an overflow container has a border (e.g., `border: 10px solid black`), content in the border area will not be properly clipped.

Consider using `clientTop`, `clientLeft`, `clientWidth`, and `clientHeight` to compute the padding-box:
```typescript
const clipLeft = clipBox.left + clippingElement.clientLeft;
const clipTop = clipBox.top + clippingElement.clientTop;
const clipRight = clipLeft + clippingElement.clientWidth;
const clipBottom = clipTop + clippingElement.clientHeight;
```

Line 744, Patchset 7 (Latest):function scrollAndCheckViewAreaVisible(fieldIdentifier: number): boolean {
Vincent Boisselle . unresolved

Consider adding a visual occlusion check (e.g., for fixed headers, cookie banners, or modal overlays covering the field) using `document.elementFromPoint`:
Once the clipped `visibleRect` is calculated, you can sample its center point `(centerX, centerY)` to verify that the top-most element at that point is the target element (or its descendant / associated `<label>`):
```typescript
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const hitElement = document.elementFromPoint(centerX, centerY);
const isNotOccluded = hitElement && (element.contains(hitElement) || (hitElement instanceof HTMLLabelElement && hitElement.control === element));
```
This provides a lightweight occlusion check for single-element visibility without needing complex z-order tree computations.

Line 753, Patchset 7 (Latest): let block = getContainingBlockForElement(element);
Vincent Boisselle . unresolved

could rename "container"

Line 754, Patchset 7 (Latest): let rect: DOMRect|null = element.getBoundingClientRect();
Vincent Boisselle . unresolved

elementRect

Line 755, Patchset 7 (Latest): while (block && rect) {
Vincent Boisselle . unresolved

Explain what this while loop does, it basically clips the element with all the eligible containers

it can clip as long as there is rect and a block (container) to clip on

Line 758, Patchset 7 (Latest): }
Vincent Boisselle . unresolved

Need a TODO somehwere about testing as we really want to test this :)

Testing / Coverage: Consider adding unit test or integration test coverage for `scrollAndCheckViewAreaVisible` to prevent regressions and verify containing-block clipping (e.g., testing `position: absolute` elements, elements inside `overflow: hidden` containers, and elements outside the viewport).

Line 762, Patchset 7 (Latest):
Vincent Boisselle . unresolved

Consider extracting a generic `clipRect(rect: DOMRect, clipBox: {left: number, top: number, right: number, bottom: number}): DOMRect | null` helper.

This would allow reusing the exact same rectangle intersection math for both `clipRectWithElement` and the final viewport check:

```typescript
function clipRect(
rect: DOMRect,
clipBox: {left: number, top: number, right: number, bottom: number}): DOMRect|null {
const left = Math.max(rect.left, clipBox.left);
const right = Math.min(rect.right, clipBox.right);
const top = Math.max(rect.top, clipBox.top);
const bottom = Math.min(rect.bottom, clipBox.bottom);
  if (bottom <= top || right <= left) {
return null;
}
return new DOMRect(left, top, right - left, bottom - top);
}
```
Then in `scrollAndCheckViewAreaVisible`:
```typescript
const viewportBox = {
left: 0,
top: 0,
right: window.innerWidth || document.documentElement.clientWidth,
bottom: window.innerHeight || document.documentElement.clientHeight,
};
return clipRect(rect, viewportBox) !== null;
```
Open in Gerrit

Related details

Attention is currently required from:
  • Ginny Huang
Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I8293ac31a005133cf2eee68da5460e7ed9c4844e
    Gerrit-Change-Number: 8047322
    Gerrit-PatchSet: 7
    Gerrit-Owner: Ginny Huang <ginny...@chromium.org>
    Gerrit-Reviewer: Ginny Huang <ginny...@chromium.org>
    Gerrit-Reviewer: Vincent Boisselle <vi...@google.com>
    Gerrit-Attention: Ginny Huang <ginny...@chromium.org>
    Gerrit-Comment-Date: Wed, 08 Jul 2026 15:54:03 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Ginny Huang (Gerrit)

    unread,
    6:36 PM (4 hours ago) 6:36 PM
    to Chromium LUCI CQ, Vincent Boisselle, android-bu...@system.gserviceaccount.com, chromium...@chromium.org, browser-comp...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
    Attention needed from Vincent Boisselle

    Ginny Huang voted and added 19 comments

    Votes added by Ginny Huang

    Auto-Submit+1
    Commit-Queue+1

    19 comments

    File components/password_manager/ios/resources/password_controller.ts
    Line 663, Patchset 7:
    Vincent Boisselle . resolved

    The commit message refers to this as `getContainingBlock`, but the function is named `getContainingBlockForElement`. Consider updating the commit message or function name for consistency.

    Ginny Huang

    Rewritten the function

    Line 664, Patchset 7: // Handles cases when the nearest containing block might be further up in the
    Vincent Boisselle . resolved

    Potential TODO

    idk how we want to deal with shadow roots, they are actually ignored by the model afaik so might not be worth considering them at this point but maybe later on once we incorporate shadow dom into the annotated page content

    Note: If `element` is inside a Shadow Root (Web Component), `element.parentElement` is `null` (since its parent is a `ShadowRoot`, which is not an `Element`). This will prevent `getContainingBlockForElement` from traversing past shadow boundaries to check clipping on the host element or host ancestors. Consider using `(element.assignedSlot || element.parentElement || (element.getRootNode() as ShadowRoot)?.host) as Element | null` if form elements inside Shadow DOM need to be supported.

    Ginny Huang

    Bug created.

    Line 667, Patchset 7: const containerStyle = window.getComputedStyle(container);
    Vincent Boisselle . resolved

    Put the logic to determine whether the container is eligible in a function that returns a boolean which will control the loop, makes the flow easier to read

    Ginny Huang

    Done

    Line 669, Patchset 7: if (position === 'absolute' && containerStyle.position !== 'static') {
    Vincent Boisselle . resolved

    this condition is true in 99% of the cases with a small exception

    "For normal flow elements ( position other than fixed and absolute ), the containing block is the parent element (unless the parent does not generate a box, e.g. display: contents )."

    Ginny Huang

    Done

    Line 669, Patchset 7: if (position === 'absolute' && containerStyle.position !== 'static') {
    Vincent Boisselle . resolved

    Comment out the reason why these conditions make the container eligible

    Ginny Huang

    Done

    Line 674, Patchset 7: if (containerStyle.transform !== 'none' ||
    Vincent Boisselle . resolved

    Comment out the reason why these conditions make the container eligible

    Ginny Huang

    Done

    Line 683, Patchset 7: const contain = containerStyle.contain;
    Vincent Boisselle . resolved

    Avoid using `(containerStyle as any).webkitBackdropFilter`. You can use `containerStyle.getPropertyValue(-webkit-backdrop-filter)` to access `-webkit-backdrop-filter` in a type-safe manner without casting to `any`.

    Ginny Huang

    Done

    Line 684, Patchset 7: if (contain &&
    Vincent Boisselle . resolved

    Comment out the reason why these conditions make the container eligible

    Ginny Huang

    Done

    Line 690, Patchset 7: const willChange = containerStyle.willChange;
    Vincent Boisselle . resolved

    Comment out the reason why these conditions make the container eligible

    Ginny Huang

    Done

    Line 693, Patchset 7: willChange.includes('perspective') || willChange.includes('filter') ||
    Vincent Boisselle . unresolved

    Per CSS Containment 3, `container-type: inline-size` or `size` (CSS Container Queries) also establishes layout containment and creates a containing block for `position: absolute` descendants. Consider adding `containerStyle.containerType !== none`.

    Ginny Huang

    It's not mentioned in https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Display/Containing_block and I personally tried and see that they work similarly as "none". Do you have a source?

    Line 724, Patchset 7:
    Vincent Boisselle . resolved

    Note: Ancestors with CSS `clip-path` or `mask` clip all descendants (including `position: absolute` or `fixed` elements) regardless of whether the ancestor is a containing block. Consider checking if `containerStyle.clipPath !== none` or `containerStyle.mask !== none` / `webkitMask !== none` in the clipping check.

    Ginny Huang

    Done

    Line 732, Patchset 7: if (bottom <= top || right <= left) {
    Vincent Boisselle . resolved

    comment out what this check does

    Ginny Huang

    Done

    Line 735, Patchset 7:
    Vincent Boisselle . resolved

    `clippingElement.getBoundingClientRect()` returns the border-box (including border and scrollbar width). However, CSS `overflow` clips content at the padding-box boundary. If an overflow container has a border (e.g., `border: 10px solid black`), content in the border area will not be properly clipped.

    Consider using `clientTop`, `clientLeft`, `clientWidth`, and `clientHeight` to compute the padding-box:
    ```typescript
    const clipLeft = clipBox.left + clippingElement.clientLeft;
    const clipTop = clipBox.top + clippingElement.clientTop;
    const clipRight = clipLeft + clippingElement.clientWidth;
    const clipBottom = clipTop + clippingElement.clientHeight;
    ```

    Ginny Huang

    Done

    Line 744, Patchset 7:function scrollAndCheckViewAreaVisible(fieldIdentifier: number): boolean {
    Vincent Boisselle . resolved

    Consider adding a visual occlusion check (e.g., for fixed headers, cookie banners, or modal overlays covering the field) using `document.elementFromPoint`:
    Once the clipped `visibleRect` is calculated, you can sample its center point `(centerX, centerY)` to verify that the top-most element at that point is the target element (or its descendant / associated `<label>`):
    ```typescript
    const centerX = rect.left + rect.width / 2;
    const centerY = rect.top + rect.height / 2;
    const hitElement = document.elementFromPoint(centerX, centerY);
    const isNotOccluded = hitElement && (element.contains(hitElement) || (hitElement instanceof HTMLLabelElement && hitElement.control === element));
    ```
    This provides a lightweight occlusion check for single-element visibility without needing complex z-order tree computations.

    Ginny Huang

    Done

    Line 753, Patchset 7: let block = getContainingBlockForElement(element);
    Vincent Boisselle . resolved

    could rename "container"

    Ginny Huang

    Refactored so this does not apply anymore

    Line 754, Patchset 7: let rect: DOMRect|null = element.getBoundingClientRect();
    Vincent Boisselle . unresolved

    elementRect

    Ginny Huang

    I don't think `elementRect` is accurate, as it will be keep clipped to the intersection of element and its container ancestors.

    Line 755, Patchset 7: while (block && rect) {
    Vincent Boisselle . resolved

    Explain what this while loop does, it basically clips the element with all the eligible containers

    it can clip as long as there is rect and a block (container) to clip on

    Ginny Huang

    Done

    Vincent Boisselle . unresolved

    Need a TODO somehwere about testing as we really want to test this :)

    Testing / Coverage: Consider adding unit test or integration test coverage for `scrollAndCheckViewAreaVisible` to prevent regressions and verify containing-block clipping (e.g., testing `position: absolute` elements, elements inside `overflow: hidden` containers, and elements outside the viewport).

    Ginny Huang

    Do we have tests for other JS methods in this file?

    Line 762, Patchset 7:
    Vincent Boisselle . resolved

    Consider extracting a generic `clipRect(rect: DOMRect, clipBox: {left: number, top: number, right: number, bottom: number}): DOMRect | null` helper.

    This would allow reusing the exact same rectangle intersection math for both `clipRectWithElement` and the final viewport check:

    ```typescript
    function clipRect(
    rect: DOMRect,
    clipBox: {left: number, top: number, right: number, bottom: number}): DOMRect|null {
    const left = Math.max(rect.left, clipBox.left);
    const right = Math.min(rect.right, clipBox.right);
    const top = Math.max(rect.top, clipBox.top);
    const bottom = Math.min(rect.bottom, clipBox.bottom);
      if (bottom <= top || right <= left) {
    return null;
    }
    return new DOMRect(left, top, right - left, bottom - top);
    }
    ```
    Then in `scrollAndCheckViewAreaVisible`:
    ```typescript
    const viewportBox = {
    left: 0,
    top: 0,
    right: window.innerWidth || document.documentElement.clientWidth,
    bottom: window.innerHeight || document.documentElement.clientHeight,
    };
    return clipRect(rect, viewportBox) !== null;
    ```
    Ginny Huang

    Done

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Vincent Boisselle
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I8293ac31a005133cf2eee68da5460e7ed9c4844e
    Gerrit-Change-Number: 8047322
    Gerrit-PatchSet: 9
    Gerrit-Owner: Ginny Huang <ginny...@chromium.org>
    Gerrit-Reviewer: Ginny Huang <ginny...@chromium.org>
    Gerrit-Reviewer: Vincent Boisselle <vi...@google.com>
    Gerrit-Attention: Vincent Boisselle <vi...@google.com>
    Gerrit-Comment-Date: Wed, 08 Jul 2026 22:36:20 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    Comment-In-Reply-To: Vincent Boisselle <vi...@google.com>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy
    Reply all
    Reply to author
    Forward
    0 new messages