Skip to content

[web] Repair RenderCanvas CSS size drift#188797

Merged
auto-submit[bot] merged 4 commits into
flutter:masterfrom
MarlonJD:mobile-safari-skwasm-canvas-css-size-fix-upstream
Jul 10, 2026
Merged

[web] Repair RenderCanvas CSS size drift#188797
auto-submit[bot] merged 4 commits into
flutter:masterfrom
MarlonJD:mobile-safari-skwasm-canvas-css-size-fix-upstream

Conversation

@MarlonJD

@MarlonJD MarlonJD commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What changed

This PR makes the stock RenderCanvas path repair stale inline canvas CSS size even when the backing-store size and DPR have not changed.

Changes:

  • Factor the expected logical canvas CSS size into a helper.
  • Check actual style.width / style.height before the same-size early return.
  • Re-apply backing-store / DPR CSS size when the inline style is stale.
  • Add regression coverage for 1206 x 2142 @ DPR 3, repairing 0.333333px back to 402 x 714px.

Why

#188723 tracks a Safari/WebKit Skwasm case where the canvas backing store can be valid while the visible CSS/display rect remains collapsed around 0.328125 x 0.328125px.

The existing stock RenderCanvas code repairs CSS size on physical-size changes and DPR changes, but not when only the inline CSS value is stale. This PR makes that same-size path self-heal.

Scope

This does not enable Skwasm by default, change WebKit policy, depend on the multi-surface rasterizer, or by itself close all Safari/WebKit default-policy gates.

Validation

  • dart format: passed.
  • git diff --check: passed.
  • Targeted felt browser test in the [web] Repair RenderCanvas CSS size drift #188797 checkout: passed locally.
    • Command: DART_SUPPRESS_ANALYTICS=true HOME=/private/tmp DART_SDK_DIR=/private/tmp/flutter-mobile-safari-skwasm-canvas-css-size-fix-upstream-worktree/engine/src/flutter/third_party/dart/tools/sdks/dart-sdk ./dev/felt test --gcs-prod --browser chrome --compiler dart2js --renderer canvaskit --fail-early test/engine/compositing/render_canvas_test.dart
    • Result: chrome-dart2js-canvaskit-engine, 3/3, All tests passed!.
  • Fresh engine/src/out/wasm_release/flutter_web_sdk build from the [web] Repair RenderCanvas CSS size drift #188797 worktree: passed locally.
  • dev/benchmarks/macrobenchmarks built as web wasm/profile using the local wasm_release SDK: passed locally.
  • Guardrail: preserved SDK/app build logs and generated bundle were checked for FLUTTER_WEB_SKWASM_FORCE_MULTI_SURFACE_RASTERIZER; the string was absent.
  • Simulator MobileSafari, Skwasm, variant=none, no forced CSS sizing, bench_card_infinite_scroll: probe-complete, errors: [], loaded skwasm_heavy, main.dart.mjs, and main.dart.wasm, crossOriginIsolated=true, canvas backing 1206 x 2142, CSS/display/style 402 x 714 / 402px x 714px.
  • Physical iPhone MobileSafari, Skwasm, variant=none, no forced CSS sizing, bench_card_infinite_scroll: all-benchmarks-complete, errors: [], loaded skwasm_heavy, main.dart.mjs, and main.dart.wasm, canvas backing 1206 x 2142, CSS/display/style 402 x 714 / 402px x 714px.
  • Physical iPhone MobileSafari, Skwasm, variant=none, no forced CSS sizing, bench_simple_lazy_text_scroll: all-benchmarks-complete, errors: [], loaded skwasm_heavy, main.dart.mjs, and main.dart.wasm, canvas backing 1206 x 2142, CSS/display/style 402 x 714 / 402px x 714px.

Physical iPhone page telemetry reported crossOriginIsolated=false even though the harness served isolation headers. Skwasm still loaded through the WebKit allowlist, so this is local physical geometry/benchmark-completion evidence, not a cross-origin-isolation pass.

Related issue: #188723.
Broader Safari/WebKit Wasm/Skwasm tracking: #178893.

@harryterkelsen harryterkelsen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @MarlonJD, thank you so much for putting together this fix! The logical canvas size drift on Safari under Skwasm is a critical issue and this is a very elegant way to self-heal.

During our review and testing across Chrome, Firefox, and Safari on both compilers (dart2js and dart2wasm), we identified a critical performance issue with exact string matching:

The Layout Thrashing Issue

By comparing the expected style string directly against the DOM style:

style.width == logicalSize.width

we run into browser-specific floating-point normalization and rounding differences:

  • Chrome & Firefox parse and round logical styles to 3 decimal places (e.g. 400.3333333px -> 400.333px).
  • Safari rounds them to 6 decimal places (e.g. 400.3333333px -> 400.333333px).
  • dart2wasm stringifies doubles with .0 (e.g. 400.0px), whereas browsers normalize this to 400px.

This causes the comparison style.width == logicalSize.width to evaluate to false on every single frame for any fractional layouts or integer sizes compiled with dart2wasm. Consequently, the engine writes to the canvas element's inline styles on every single frame, triggering continuous browser layout invalidation and thrashing, which severely hurts frame rendering performance.

Proposed Solution

Instead of exact string matching, we can parse the pixel lengths from the style declaration and perform a tolerance-based (epsilon) comparison (e.g., matching within a 0.01px threshold).

Here is a suggested modification:

  bool _isLogicalHtmlCanvasSizeCurrent() {
    final double devicePixelRatio = EngineFlutterDisplay.instance.devicePixelRatio;
    if (devicePixelRatio != _currentDevicePixelRatio) {
      return false;
    }
    final DomCSSStyleDeclaration style = canvasElement.style;
    final double? actualWidth = _parseLogicalLength(style.width);
    final double? actualHeight = _parseLogicalLength(style.height);
    if (actualWidth == null || actualHeight == null) {
      return false;
    }
    final double expectedWidth = _pixelWidth / devicePixelRatio;
    final double expectedHeight = _pixelHeight / devicePixelRatio;
    // Allow a small threshold (e.g. 0.01px) to account for browser float precision/rounding differences.
    return (actualWidth - expectedWidth).abs() < 0.01 &&
        (actualHeight - expectedHeight).abs() < 0.01;
  }

  double? _parseLogicalLength(String value) {
    final String trimmed = value.trim();
    if (!trimmed.endsWith('px')) {
      return null;
    }
    return double.tryParse(trimmed.substring(0, trimmed.length - 2).trim());
  }

Could you update the PR to use a tolerance-based approach like this? We would love to get this landed!

@MarlonJD

MarlonJD commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Done, thanks! Updated the canvas CSS size check to parse px values and compare with a small tolerance, and added regression coverage for normalized inline CSS values.

@harryterkelsen

Copy link
Copy Markdown
Contributor

Thanks, LGTM! Can you take this out of draft status so I can start landing it?

@MarlonJD

MarlonJD commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Hey @harryterkelsen, GitHub is not allowing me to mark the PR ready for review from my account, and I can’t open a replacement non-draft PR because I’m currently at Flutter’s 2 open PR limit. Could a maintainer please mark this one ready for review?

@harryterkelsen harryterkelsen added the CICD Run CI/CD label Jul 7, 2026
@harryterkelsen

Copy link
Copy Markdown
Contributor

It won't let me manually set it to "Ready for Review" because of the open PR limit. Can you make one of your open ones a draft and we'll land this one to "free up" your space? If not, then just ping me once one of your other PRs are closed so we can land this one

@MarlonJD
MarlonJD marked this pull request as ready for review July 7, 2026 22:07
@MarlonJD
MarlonJD requested a review from harryterkelsen July 7, 2026 22:09
@MarlonJD

MarlonJD commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @harryterkelsen I moved my other open PRs back to draft to free up the active PR slot, and this PR is now marked ready for review.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates RenderCanvas to repair its logical HTML canvas size when the inline CSS size drifts or when the device pixel ratio changes, introducing a tolerance check. New tests were added to verify this behavior. The review feedback highlights that overriding the global devicePixelRatio in these tests without restoring it can cause test pollution, and suggests using addTearDown to reset the ratio.

@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Jul 7, 2026

@harryterkelsen harryterkelsen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@harryterkelsen harryterkelsen added CICD Run CI/CD autosubmit Merge PR when tree becomes green via auto submit App labels Jul 7, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 8, 2026
@auto-submit

auto-submit Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188797, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR.

@auto-submit

auto-submit Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188797, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a member of flutter-hackers before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@harryterkelsen harryterkelsen added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 8, 2026
@auto-submit

auto-submit Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188797, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR.

@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 8, 2026
@auto-submit

auto-submit Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188797, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a member of flutter-hackers before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Jul 8, 2026
@flutter-zl
flutter-zl self-requested a review July 8, 2026 20:12
@harryterkelsen harryterkelsen added the CICD Run CI/CD label Jul 8, 2026
@harryterkelsen harryterkelsen added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 8, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 8, 2026
@auto-submit

auto-submit Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188797, because - The status or check suite Mac_x64 framework_tests_misc has failed. Please fix the issues identified (or deflake) before re-applying this label.

@harryterkelsen harryterkelsen added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 9, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Jul 10, 2026
Merged via the queue into flutter:master with commit 8303fed Jul 10, 2026
213 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 10, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Jul 10, 2026
flutter/flutter@dc2a870...f7b66f3

2026-07-10 [email protected] [iOS][test] Fix VSyncClient display link deallocation test on iOS 27 (flutter/flutter#188627)
2026-07-10 [email protected] Fix broken listener code in WindowScope (flutter/flutter#189208)
2026-07-10 [email protected] [web] Preserve text field focus across tab switches (flutter/flutter#188738)
2026-07-10 [email protected] [Impeller] Recycle HostBuffer arena entries only after GPU completion (flutter/flutter#188965)
2026-07-10 [email protected] Assert TextStyle height is not NaN (flutter/flutter#186617)
2026-07-10 [email protected] Roll Fuchsia Test Scripts from dFkTCiDxEtPxYK5Nn... to wLST_A-xfOeGT_5mj... (flutter/flutter#189259)
2026-07-10 [email protected] Roll Dart SDK from a11fb7ed40a5 to 0fc1668c4af4 (5 revisions) (flutter/flutter#189257)
2026-07-10 [email protected] Adds a missing `await` to a `FutureOr` (flutter/flutter#189198)
2026-07-10 [email protected] [web] Repair RenderCanvas CSS size drift (flutter/flutter#188797)
2026-07-10 [email protected] Roll Fuchsia Test Scripts from s5_gZFJ8De9AJalTw... to dFkTCiDxEtPxYK5Nn... (flutter/flutter#189215)
2026-07-10 [email protected] Roll Fuchsia Linux SDK from QcRFUtvCw2EobfJ8s... to czpzDg9ABY2oKLAOY... (flutter/flutter#189222)
2026-07-10 [email protected] Update Depdencies Used By `flutter_engine_group_performance` (flutter/flutter#189229)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants