Skip to content

paint: Use viewport meta tag's min-scale and max-scale to clamp pinch zoom#40098

Merged
mrobinson merged 3 commits into
servo:mainfrom
shubhamg13:clamp_pinch_zoom
Apr 3, 2026
Merged

paint: Use viewport meta tag's min-scale and max-scale to clamp pinch zoom#40098
mrobinson merged 3 commits into
servo:mainfrom
shubhamg13:clamp_pinch_zoom

Conversation

@shubhamg13
Copy link
Copy Markdown
Member

@shubhamg13 shubhamg13 commented Oct 23, 2025

Note: Targeting Mobile devices only.

Clamp Pinch Zoom factor using viewport' scale range parsed from <meta> tag.

Behavior in Servo with this PR

Zoom Type Device Type Meta Supported Range
Pinch Zoom Mobile Yes Parsed from
Pinch Zoom Desktop No Default

Observed behavior in Chrome:

Device Type Viewport Meta Support (pref) Pinch Zoom (No Reflow) Zoom (using keyboard)
Mobile (Android) Yes Clamped within Viewport Meta Range Applied to Pinch Zoom*
Desktop (Touch Screen) No Clamped within Default Range Same as Zoom (using menu)

References from Chromium:

Testing: New WPT Test Added: wpt/visual-viewport/viewport-scale-clamped.html

Fixes: #40390 (Observed Inconsistent behavior with Chrome Android)

@shubhamg13 shubhamg13 requested a review from mrobinson as a code owner October 23, 2025 08:58
@servo-highfive servo-highfive added the S-awaiting-review There is new code that needs to be reviewed. label Oct 23, 2025
@shubhamg13
Copy link
Copy Markdown
Member Author

#39868 (comment) @mrobinson

In addition, stop clamping the pinch zoom by the page zoom clamp values.
They aren't meant for that. Instead set up some reasonable clamping
values for pinch zoom in the compositor.

I compared the behavior on Android and OHOS device, they use viewport values and restrict the pinch zoom accordingly.

cc: @xiaochengh

Copy link
Copy Markdown
Member

@mrobinson mrobinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just needs a bit of justification:

Comment on lines +844 to +851
if let Some(viewport) = self.viewport_description.as_ref() {
requested_pinch_zoom = viewport.clamp_page_zoom(requested_pinch_zoom);
}

let old_zoom =
std::mem::replace(&mut self.pinch_zoom, PinchZoomFactor::new(new_pinch_zoom));
let old_zoom = std::mem::replace(
&mut self.pinch_zoom,
PinchZoomFactor::new(requested_pinch_zoom),
);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when you combine pinch zoom and page zoom on these devices? Where in the specification does it mention that this should the non-layout viewport? Failing that, can you somehow explain the reasoning used by the other browsers and what their general strategy is with clamping values from the viewport metatag (an internal bug report or link to the code would suffice to)?

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splitting the scenarios observed on Chrome:

  1. Mobile Devices: Supports Viewport Meta via pref, and when pinch zoom it is clamped as per meta viewport. When page zoomed using zoom option aka desktop zoom, it has range from 50% to 300% using slider.
  2. Desktop Devices: Doesn't support Viewport Meta via pref, no pinch zoom only desktop zoom using preset values range from 25% to 500%.
  3. Desktop Devices (with touch screen): Doesn't support Viewport Meta via pref, when pinch zoom, since no viewport meta parsed it gets clamped in default range and when desktop style zoom applied, it uses preset value range from 25% to 500%.

@mrobinson I have added the table for more clarity. Tell me know if you have any other concerns.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shubhamg13 Some clarification:

When I ask how pinch zoom / page zoom interact here. I mean to ask whether or not combining pinch zoom and page zoom affect the clamping. For instance if page zoom is 2x, does that mean that we should clamp pinch zoom to [min_zoom / 2, max_zoom / 2]? If you first apply a page zoom, does it change the range of available pinch zoom values?

In addition, I'm looking for some justification to explain why this change is necessary. FWIW, I believe you that it is, but it just needs to reasoned so that it does not regress again. For example, the viewport meta tag was changed to only affect the page zoom viewport in #40055 and this change undoes some of that work. You also proposed a related change, so I'm pretty confused. We just need to be clear on what viewport it should affect. It seems quite odd that parts of the meta tag affect the layout viewport and others the visual viewport.

So we either need:

  1. Specification text that describes how this is supposed to work.
  2. In the case that this is underspecified either:
    1. A link to a bug from another browser where the implementation and what viewport it affects is discussed.
    2. A link to the code which shows how this works in other browsers.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I ask how pinch zoom / page zoom interact here. I mean to ask whether or not combining pinch zoom and page zoom affect the clamping. For instance if page zoom is 2x, does that mean that we should clamp pinch zoom to [min_zoom / 2, max_zoom / 2]? If you first apply a page zoom, does it change the range of available pinch zoom values?

No they aren't combined. They are applied irrespective of each other having their separate clamping range.

And this change is required due to inconsistency observed as compared to Chrome.

P.S: I'll try to find some reference.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2. A link to the code which shows how this works in other browsers.

  1. Here, In chromium PinchZoom is applied by first fetching the current page_scale, and applying magnify_delta over that.
  2. Inside, it is clamped here.
  3. And I further backtracked, its range comes from viewport_description

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you call "Desktop Zoom" in the table above is typically called "page zoom" and that's what we call it in Servo. I'm not sure how you were able to test this in the mobile version of Chrome as it no longer seems to be enabled in the Chrome browser. What did you do to test this? I am skeptical that it would be adjust the pinch zoom as these are very different concepts. Maybe whatever you were doing to test was adjusting the pinch zoom?

Safari for iOS does support reflowing style page zoom. I can try to see what its behavior is.

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how you were able to test this in the mobile version of Chrome as it no longer seems to be enabled in the Chrome browser. What did you do to test this?

Updated table headings, PTAL.

  • Zoom (using menu): Click on More Menu (⋮) -> Zoom
  • Zoom (using keyboard) on Mobile: Connect Bluetooth Keyboard

Let me know what scenarios steps you are suspicious about.

Safari for iOS does support reflowing style page zoom. I can try to see what its behavior is.

  • Safari and Chrome on iOS uses WebKit.

  • On the other hand Chrome Desktop and Chrome Android use Blink.

IMHO our comparison should be with Blink Engine, right?

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mrobinson Chrome even provides an override switch to zoom where websites prevent zoom.

Reference 1

Reference 2

  1. Websites can only control via <viewport> meta
  2. They control pinch-zoom via this toogle switch.

When user enabled force enable zoom, we should always allow pinch-zoom [1]

@servo-highfive servo-highfive added S-needs-code-changes Changes have not yet been made that were requested by a reviewer. S-needs-rebase There are merge conflict errors. and removed S-awaiting-review There is new code that needs to be reviewed. labels Oct 23, 2025
@servo-highfive servo-highfive added S-awaiting-review There is new code that needs to be reviewed. and removed S-needs-code-changes Changes have not yet been made that were requested by a reviewer. S-needs-rebase There are merge conflict errors. labels Oct 24, 2025
@shubhamg13 shubhamg13 requested a review from mrobinson October 24, 2025 07:27
@shubhamg13 shubhamg13 force-pushed the clamp_pinch_zoom branch 3 times, most recently from bfc53e1 to c36a956 Compare October 31, 2025 06:41
@shubhamg13 shubhamg13 force-pushed the clamp_pinch_zoom branch 2 times, most recently from ddb132d to 398c14e Compare January 29, 2026 06:31
@shubhamg13
Copy link
Copy Markdown
Member Author

Please help to review

Comment thread components/paint/pinch_zoom.rs Outdated
Comment thread components/paint/pinch_zoom.rs Outdated
Comment thread components/paint/pinch_zoom.rs Outdated
@shubhamg13 shubhamg13 marked this pull request as draft January 30, 2026 04:39
@shubhamg13 shubhamg13 force-pushed the clamp_pinch_zoom branch 2 times, most recently from a303c1a to bf8e887 Compare January 30, 2026 07:19
@shubhamg13 shubhamg13 requested a review from mrobinson January 30, 2026 07:21
@shubhamg13 shubhamg13 marked this pull request as ready for review January 30, 2026 07:21
Comment thread components/paint/webview_renderer.rs Outdated
Comment thread components/paint/webview_renderer.rs Outdated

/// Constrains a zoom value within the allowed scale range
pub fn clamp_page_zoom(&self, zoom: f32) -> f32 {
pub fn clamp_zoom(&self, zoom: f32) -> f32 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please name this to be explicit ie clamp_pinch_zoom.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using it for both the zooms now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where in the specification does it say that it should be used to clamp both values? Everything that I have read suggests that it should be used to clamp the visual viewport (pinch zoom / page scale). If you clamp both values separately, I do not think this will have the correct behavior when both a page zoom and pinch zoom are applied -- which was my original question.

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just use the fallback behavior for clamping by using DEFAULT. Yes they should be different indeed.

In Chrome they have page Zoom Range of 0.25 to 50.0. But In Servo our Range was 0.1 and 10.0 as you didn't agree for this here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If they should be separate, let's separate these concepts fully. If we still need to clamp the page zoom range via a hardcoded set of values create two new constants:

  • MINIMUM_PAGE_ZOOM
  • MAXIMUM_PAGE_ZOOM

in the code unit that needs to clamp page zoom. Then we can stop clamping page zoom at all using the ViewportDescription.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure will do, What range do you suggest for this...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just maintain the current behavior for page zooms.

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Reverting changes for I made with page zoom.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything that I have read suggests that it should be used to clamp the visual viewport (pinch zoom / page scale).

With this conclusion of yours and coming to sole and primary goal of this PR. Please take a look and review

P.S: Sorry for lot of back and forth changes. I removed all the unrelated changes.

Comment thread components/paint/webview_renderer.rs Outdated
let new_page_zoom = self
.viewport_description
.unwrap_or_default()
.clamp_zoom(new_page_zoom);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you clamping page zoom here as this change is about making the viewport metatag clamp pinch zoom. Why would it clamp both values? If page zoom needs to be clamped it should certain be a separate set of values as these concepts are distinct aren't they?

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically it does same thing,

  • For Desktop (Meta not Parsed):, use Defualt Values
  • For Mobile (Meta Parsed): use Meta Values

Same as Chrome and ChromeAndroid

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty unconvinced by this, but I would change my mind if you could justify this choice by helping my understand how the specification says we should do this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look over the table for observed behavior in Chrome (Firefox also has same behavior)

There seems no explicit specs for this, I found inconsistent behavior with chrome that's it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no specification, let's keep this simple. Can we only use the <meta viewport> tag to clamp pinch zoom and nothing else?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's the goal.

Comment thread components/paint/webview_renderer.rs Outdated
Comment on lines +707 to +710
let new_factor = self
.viewport_description
.unwrap_or_default()
.clamp_zoom(factor * new_pinch_zoom.zoom_factor().get());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are clamping each individual pinch zoom delta here rather than the final value. This will lead to incorrect results. You need to figure out what the final value will be and clamp that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am clamping delta*existing_zoom_factor

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I think you were on the right track before clamping inside of PinchZoom. Theoretically there could be some other caller to PinchZoom::zoom() and the behavior should be consistent.

Comment thread components/shared/paint/viewport_description.rs Outdated
@servo-highfive servo-highfive removed the S-awaiting-review There is new code that needs to be reviewed. label Jan 30, 2026
@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

@shubhamg13
Copy link
Copy Markdown
Member Author

shubhamg13 commented Mar 27, 2026

#40098 (comment)

Everything that I have read suggests that it should be used to clamp the visual viewport (pinch zoom / page scale).

#40098 (comment)

Can we only use the tag to clamp pinch zoom and nothing else?

@mrobinson
Summing up to your prior achieved conclusion, I'm resolving all the irrelevant comments.

And coming to sole and only purpose of this PR. Please take a look and review.

P.S: Sorry for lot of back and forth changes. I removed all the unrelated changes.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

✍ Updated existing upstream WPT pull request (web-platform-tests/wpt#58805) title and body.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

3 similar comments
@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

Comment thread components/paint/pinch_zoom.rs Outdated
Comment thread components/paint/pinch_zoom.rs Outdated
Comment thread components/paint/webview_renderer.rs Outdated
Comment thread components/paint/webview_renderer.rs Outdated
<script> promise_test(async () => {
const x = 200, y = 200;
const initialScale = window.visualViewport.scale;
// Perform pinch zoom
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there other tests that perform a pinch zoom like this? If so this is probably fine, but otherwise this should likely be a Servo-only test.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

✍ Updated existing upstream WPT pull request (web-platform-tests/wpt#58805) title and body.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we Please add it to MQ again. I detected one false positive.

@@ -1,3 +1,7 @@
[pointerevent_touch-action_two-finger_interaction.html]
expected: TIMEOUT
Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this was false positive as Servo doesn't support touch-action due to which this was removed from MQ.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea why the test starts to fail now though? It doesn't seem to be using the viewport metatag, so it seems that this change if modifying the behavior of Servo even when the viewport metatag isn't used -- which seems wrong.

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this PR the clamp range is 0.1 to 10.0 so this is affecting the test. Adding the workaround back.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not allow pinch zooming to values below 1 by default.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, when I enable it in here #43688. I will add a check for same.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 3, 2026

🔨 Triggering try run (#23936449766) for Linux (WPT)

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 3, 2026

Test results for linux-wpt from try job (#23936449766):

Flaky unexpected result (29)
  • OK /FileAPI/url/url-with-fetch.any.html (#21517)
    • FAIL [expected PASS] subtest: Revoke blob URL after calling fetch, fetch should succeed

      promise_test: Unhandled rejection with value: object "TypeError: Network error: Blob URL store error: InvalidFileID"
      

  • OK /IndexedDB/idbtransaction-oncomplete.any.worker.html (#42804)
    • FAIL [expected PASS] subtest: IDBTransaction - complete event

      assert_array_equals: lengths differ, expected array ["upgradeneeded", "complete", "success", "opencursor"] length 4, got ["upgradeneeded", "complete", "success"] length 3
      

  • OK /_mozilla/css/offset_properties_inline.html (#40543)
    • FAIL [expected PASS] subtest: offsetTop

      assert_equals: offsetTop of #inline-1 should be 0. expected 0 but got -1
      

    • FAIL [expected PASS] subtest: offsetLeft

      assert_equals: offsetLeft of #inline-2 should be 40. expected 40 but got 25
      

  • CRASH [expected ERROR] /_webgl/conformance2/misc/uninitialized-test-2.html (#41656)
  • FAIL [expected PASS] /css/css-backgrounds/background-size-042.html
  • OK /css/css-cascade/layer-font-face-override.html (#35935)
    • PASS [expected FAIL] subtest: @font-face override update with appended sheet 1
    • PASS [expected FAIL] subtest: @font-face override update with appended sheet 2
  • FAIL [expected PASS] /css/css-ui/appearance-menulist-button-001.html
  • OK /fetch/metadata/generated/css-font-face.sub.tentative.html (#34624)
    • PASS [expected FAIL] subtest: sec-fetch-storage-access - Not sent to non-trustworthy same-site destination
  • OK /fetch/metadata/window-open.https.sub.html (#40339)
    • FAIL [expected PASS] subtest: Cross-site window, forced, reloaded

      The operation is insecure.
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-window-open.html (#28691)
    • FAIL [expected PASS] subtest: load event does not fire on window.open('about:blank')

      assert_unreached: load should not be fired Reached unreachable code
      

  • CRASH [expected TIMEOUT] /html/browsers/browsing-the-web/navigating-across-documents/javascript-url-no-beforeunload.window.html
  • OK /html/browsers/history/the-history-interface/traverse_the_history_5.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • OK /html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html (#39694)
    • PASS [expected FAIL] subtest: Meta refresh is blocked by the allow-scripts sandbox flag at its creation time, not when refresh comes due
  • OK /html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-2.html (#39703)
    • FAIL [expected PASS] subtest: Meta refresh of the original iframe is not blocked if moved into a sandboxed iframe

      uncaught exception: Error: assert_unreached: The iframe into which the meta was moved must not refresh Reached unreachable code
      

  • TIMEOUT [expected OK] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigate_other_frame_popup.sub.html (#39702)
    • TIMEOUT [expected FAIL] subtest: Sandboxed iframe can not navigate other frame's popup

      Test timed out
      

  • OK /html/semantics/forms/form-submission-0/jsurl-form-submit.tentative.html (#36489)
    • PASS [expected FAIL] subtest: Verifies that form submissions scheduled inside javascript: urls take precedence over the javascript: url's return value.
  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.worker-module.html (#43510)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Module fetching failed"
      

  • TIMEOUT [expected OK] /html/user-activation/navigation-state-reset-sameorigin.html
    • TIMEOUT [expected PASS] subtest: Post-navigation state reset.

      Test timed out
      

  • OK /html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.html (#42419)
    • FAIL [expected PASS] subtest: document.write in an imported module

      assert_true: onload must be called expected true got false
      

  • OK /mixed-content/tentative/autoupgrades/video-upgrade.https.sub.html (#41135)
    • FAIL [expected PASS] subtest: Video autoupgraded

      assert_equals: Length. expected 1 but got Infinity
      

  • TIMEOUT [expected OK] /preload/modulepreload-sri-importmap.html (#43354)
    • TIMEOUT [expected PASS] subtest: Script should not be loaded if modulepreload's integrity is invalid

      Test timed out
      

  • ERROR [expected OK] /resource-timing/cors-preflight.any.html (#28694)
  • OK /resource-timing/test_resource_timing.https.html (#25216)
    • PASS [expected FAIL] subtest: PerformanceEntry has correct name, initiatorType, startTime, and duration (link)
  • OK [expected TIMEOUT] /trusted-types/trusted-types-navigation.html?01-05 (#38975)
    • PASS [expected TIMEOUT] subtest: Navigate a window via anchor with javascript:-urls in report-only mode.
    • PASS [expected NOTRUN] subtest: Navigate a window via anchor with javascript:-urls w/ default policy in report-only mode.
    • PASS [expected NOTRUN] subtest: Navigate a frame via anchor with javascript:-urls in enforcing mode.
  • TIMEOUT /trusted-types/trusted-types-navigation.html?26-30 (#38807)
    • PASS [expected TIMEOUT] subtest: Navigate a window via form-submission with javascript:-urls in report-only mode.
    • PASS [expected NOTRUN] subtest: Navigate a window via form-submission with javascript:-urls w/ default policy in report-only mode.
    • PASS [expected NOTRUN] subtest: Navigate a frame via form-submission with javascript:-urls in enforcing mode.
    • TIMEOUT [expected NOTRUN] subtest: Navigate a frame via form-submission with javascript:-urls w/ default policy in enforcing mode.

      Test timed out
      

  • CRASH [expected OK] /webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/closed-audiocontext-construction.html
  • OK [expected TIMEOUT] /webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html (#29053)
    • PASS [expected TIMEOUT] subtest: StorageKey: test 3P about:blank window opened from a 3P iframe
  • OK [expected ERROR] /webxr/render_state_update.https.html (#27535)
  • OK /webxr/xrSession_features_deviceSupport.https.html (#24357)
    • FAIL [expected PASS] subtest: Immersive XRSession requests with no supported device should reject

      assert_unreached: Should have rejected: undefined Reached unreachable code
      

Stable unexpected results that are known to be intermittent (19)
  • FAIL [expected PASS] /_mozilla/mozilla/sslfail.html (#10760)
  • TIMEOUT [expected OK] /_mozilla/mozilla/window_resize_event.html (#36741)
    • TIMEOUT [expected PASS] subtest: Popup onresize event fires after resizeTo

      Test timed out
      

  • CRASH [expected PASS] /_mozilla/shadow-dom/move-element-with-ua-shadow-tree-crash.html (#39473)
  • OK /_webgl/conformance/textures/misc/texture-upload-size.html (#21770)
    • FAIL [expected PASS] subtest: WebGL test #45

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #47

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #49

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #51

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • PASS [expected FAIL] subtest: WebGL test #53
    • PASS [expected FAIL] subtest: WebGL test #55
    • PASS [expected FAIL] subtest: WebGL test #57
    • PASS [expected FAIL] subtest: WebGL test #59
    • FAIL [expected PASS] subtest: WebGL test #61

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #63

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • And 14 more unexpected results...
  • CRASH [expected OK] /content-security-policy/meta/sandbox-iframe.html (#43478)
  • OK /css/css-fonts/generic-family-keywords-001.html (#37467)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted generic(fangsong)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted generic(kai)
  • OK /css/css-fonts/generic-family-keywords-003.html (#38994)
    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted cursive (drawing text in a canvas)

      assert_equals: quoted cursive matches  @font-face rule expected 125 but got 40
      

    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted fantasy (drawing text in a canvas)

      assert_equals: quoted fantasy matches  @font-face rule expected 125 but got 40
      

    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted generic(kai) (drawing text in a canvas)

      assert_equals: unquoted generic(kai) does not match @font-face rule expected 40 but got 125
      

    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted generic(khmer-mul) (drawing text in a canvas)

      assert_equals: quoted generic(khmer-mul) matches  @font-face rule expected 125 but got 40
      

    • FAIL [expected PASS] subtest: @font-face matching for quoted and unquoted generic(nastaliq) (drawing text in a canvas)

      assert_equals: quoted generic(nastaliq) matches  @font-face rule expected 125 but got 40
      

  • OK /dom/nodes/moveBefore/iframe-document-preserve.window.html (#43152)
    • FAIL [expected PASS] subtest: moveBefore(): cross-origin iframe is preserved: remove self via innerHTML

      assert_equals: iframe does not fire a second load event expected 1 but got 0
      

  • OK [expected ERROR] /fetch/fetch-later/quota/same-origin-iframe/multiple-iframes.https.window.html (#35176)
  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-mode
    • PASS [expected FAIL] subtest: sec-fetch-user
  • ERROR [expected OK] /focus/focus-event-after-switching-iframes.sub.html (#40368)
  • OK /html/browsers/browsing-the-web/navigating-across-documents/005.html (#27062)
    • FAIL [expected PASS] subtest: Link with onclick navigation and href navigation

      assert_equals: expected "href" but got "click"
      

  • OK [expected TIMEOUT] /html/infrastructure/urls/base-url/document-base-url-window-initiator-is-not-opener.https.window.html (#30970)
  • TIMEOUT /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • PASS [expected TIMEOUT] subtest: Non-HTMLElement should not support autofocus
    • FAIL [expected NOTRUN] subtest: Host element with delegatesFocus should support autofocus

      promise_test: Unhandled rejection with value: object "TypeError: can't access property "appendChild", w.document.body is null"
      

    • TIMEOUT [expected NOTRUN] subtest: Host element with delegatesFocus including no focusable descendants should be skipped

      Test timed out
      

  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.worker.html (#33909)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Module fetching failed"
      

  • OK [expected TIMEOUT] /infrastructure/testdriver/click_nested.html (#43887)
    • FAIL [expected NOTRUN] subtest: TestDriver click method with multiple windows and nested iframe

      can't access property "document", child.frames[2] is undefined
      

  • OK /mixed-content/tentative/autoupgrades/mixed-content-cors.https.sub.html (#41123)
    • PASS [expected FAIL] subtest: Cross-Origin video should get upgraded even if CORS is set
  • OK /resource-timing/test_resource_timing.html (#25720)
    • PASS [expected FAIL] subtest: PerformanceEntry has correct name, initiatorType, startTime, and duration (iframe)
  • OK /trusted-types/trusted-types-reporting.html (#43737)
    • PASS [expected FAIL] subtest: Trusted Type violation report: creating a forbidden-but-not-reported policy.
    • PASS [expected FAIL] subtest: Trusted Type violation report: sample for SVGScriptElement href assignment by setAttribute
    • PASS [expected FAIL] subtest: Trusted Type violation report: sample for eval
    • PASS [expected FAIL] subtest: Trusted Type violation report: sample for custom element assignment
    • PASS [expected FAIL] subtest: Trusted Type violation report: Worker constructor

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 3, 2026

✨ Try run (#23936449766) succeeded.

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

@servo-wpt-sync
Copy link
Copy Markdown
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58805).

Comment on lines +79 to 82
if new_factor <= 1.0 {
self.zoom_factor = 1.0; // Update the zoom factor to 1.0 to avoid precision issues when zooming back in after zooming out fully.
self.transform = Transform2D::identity();
return;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does seem like it will cause an issue in the case that the ViewportDescription does say that we should be able to pinch zoom to values below 1.0. Would it make sense to change the default minimum zoom in ViewportDescription to be 1.0?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some websites that have initial-scale as 0.5. We should support entire range from 0.1 to 10.0, but selectively modify depending on platforms.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In those cases it seems that the ViewportDescription will no longer be the default one and so when you call clamp on the new value it will be clamped properly to [0.5, ...].

Copy link
Copy Markdown
Member Author

@shubhamg13 shubhamg13 Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's what exactly I am doing ( in PR where I support for scale less than 1, yet to push or I can add separate PR if you say)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please a take a look here #43905

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect deletion logic; it should be restricted using self.viewport_description.

7 participants