commit fe16ae088c03b008d8af634302d5b3ae4f9b7cec
parent 40fae03a754652c2f50e582698646bd2fb3563a1
Author: Hiroyuki Ikezoe <hikezoe.birchill@mozilla.com>
Date: Tue, 2 Dec 2025 09:49:20 +0000
Bug 1999432 - Focibly use WhereToScroll::Nearest for zoom-to-focused-input for position:fixed elements. r=layout-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D272119
Diffstat:
5 files changed, 92 insertions(+), 8 deletions(-)
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
@@ -3165,7 +3165,7 @@ nsDOMWindowUtils::ZoomToFocusedInput() {
caretInfo.frame, caretInfo.caretRectRelativeToTextFrame,
ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotVisible),
ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotVisible),
- ScrollFlags::ScrollOverflowHidden);
+ ScrollFlags::ScrollOverflowHidden | ScrollFlags::ForZoomToFocusedInput);
}
RefPtr<Document> document = presShell->GetDocument();
diff --git a/gfx/layers/apz/test/mochitest/helper_zoomToFocusedInput_for_position_fixed.html b/gfx/layers/apz/test/mochitest/helper_zoomToFocusedInput_for_position_fixed.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <title>Tests that zoomToFocuedInput doesn't align position:fixed elements at the center of the visual viewport</title>
+ <script src="apz_test_utils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+</head>
+<style>
+@font-face {
+ font-family: Ahem;
+ src: url("/tests/layout/base/tests/Ahem.ttf");
+}
+body {
+ margin: 0px;
+ padding: 0px;
+}
+input {
+ width: 100%;
+ height: 40px;
+ border: none;
+ padding: 0px;
+ position: fixed;
+ bottom: 0px;
+ /*
+ * Use the same size of the element height to easily calculate expected
+ position since zoom-to-focused-input tries to align the caret position
+ rather than the input element.
+ */
+ font: 40px/1 Ahem;
+}
+</style>
+<body>
+<div style="width: 100vw; height: 100vh; background: blue;"></div>
+<input id="target" type="text"/>
+<div style="width: 100vw; height: 200vh; background: green;"></div>
+<script>
+async function test() {
+ is(window.scrollY, 0, "The initial scroll offset should be 0");
+ is(visualViewport.scale, 2.0, "The document should get scaled by 2.0");
+ is(visualViewport.pageLeft, 0, "The initial visual viewport pageLeft should be 0");
+
+ const input = document.querySelector("#target");
+ const inputRect = input.getBoundingClientRect();
+
+ // Focus to the input element without scrolling.
+ const focusPromise = new Promise(resolve => {
+ input.addEventListener("focus", resolve);
+ });
+ input.focus({ preventScroll: true });
+ await focusPromise;
+
+ // Invoke zoom-to-focused-input.
+ const utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.zoomToFocusedInput();
+
+ await promiseApzFlushedRepaints();
+
+ // Calculate the expected position.
+ const centerOfTarget = inputRect.y + inputRect.height;
+ const expected = centerOfTarget - visualViewport.height;
+
+ isfuzzy(visualViewport.pageTop, expected, 1.0,
+ "The input element is aligned at the bottom of the visual viewport");
+}
+
+SpecialPowers.getDOMWindowUtils(window).setResolutionAndScaleTo(2.0);
+waitUntilApzStable()
+.then(test)
+.then(subtestDone, subtestFailed);
+</script>
+</body>
+</html>
diff --git a/gfx/layers/apz/test/mochitest/test_group_zoomToFocusedInput.html b/gfx/layers/apz/test/mochitest/test_group_zoomToFocusedInput.html
@@ -38,6 +38,9 @@ var subtests = [
},
{"file": "helper_zoomToFocusedInput_content_visibility_auto.html", prefs},
{"file": "helper_zoomToFocusedInput_to_cursor.html", prefs},
+ {"file": "helper_zoomToFocusedInput_for_position_fixed.html",
+ "prefs": [...prefs,
+ ["layout.scroll_fixed_content_into_view_visually", true]]},
];
// These tests rely on mobile viewport sizing, so only run them on
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
@@ -3810,13 +3810,19 @@ void PresShell::ScrollFrameIntoVisualViewport(
nscoord unusedRangeMinOutparam;
nscoord unusedRangeMaxOutparam;
nscoord x = ComputeWhereToScroll(
- aHorizontal.mWhereToScroll, layoutOffset.x, aPositionFixedRect.x,
- aPositionFixedRect.XMost(), visibleRect.x, visibleRect.XMost(),
- &unusedRangeMinOutparam, &unusedRangeMaxOutparam);
+ aScrollFlags & ScrollFlags::ForZoomToFocusedInput
+ ? WhereToScroll::Nearest
+ : aHorizontal.mWhereToScroll,
+ layoutOffset.x, aPositionFixedRect.x, aPositionFixedRect.XMost(),
+ visibleRect.x, visibleRect.XMost(), &unusedRangeMinOutparam,
+ &unusedRangeMaxOutparam);
nscoord y = ComputeWhereToScroll(
- aVertical.mWhereToScroll, layoutOffset.y, aPositionFixedRect.y,
- aPositionFixedRect.YMost(), visibleRect.y, visibleRect.YMost(),
- &unusedRangeMinOutparam, &unusedRangeMaxOutparam);
+ aScrollFlags & ScrollFlags::ForZoomToFocusedInput
+ ? WhereToScroll::Nearest
+ : aVertical.mWhereToScroll,
+ layoutOffset.y, aPositionFixedRect.y, aPositionFixedRect.YMost(),
+ visibleRect.y, visibleRect.YMost(), &unusedRangeMinOutparam,
+ &unusedRangeMaxOutparam);
layoutOffset.x += x;
layoutOffset.y += y;
diff --git a/layout/base/PresShellForwards.h b/layout/base/PresShellForwards.h
@@ -147,11 +147,12 @@ enum class ScrollFlags : uint8_t {
ScrollSmoothAuto = 1 << 4,
TriggeredByScript = 1 << 5,
AxesAreLogical = 1 << 6,
+ ForZoomToFocusedInput = 1 << 7,
// NOTE: `Anchor` means here is "scrolling to an anchor", not "CSS scroll
// anchoring".
AnchorScrollFlags =
ScrollOverflowHidden | ScrollNoParentFrames | TriggeredByScript,
- ALL_BITS = (1 << 7) - 1,
+ ALL_BITS = (1 << 8) - 1,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ScrollFlags)