flutter / flutter/flutter

[two_dimensional_scrollables] [web] merged cells and span decorations has severe debug-mode scrolling jank

Open
#191,869 1 comment 5 reactions 0 assignees View on GitHub
c: performance f: scrolling framework has reproducible steps P2 perf: speed platform-web team-web triaged-web
Dominant language
Dart
Stars
179k
Forks
31.1k
PR merge metrics
PR metrics pending

Description

I'm using the performance template, but here we have a problem in debug mode only.
It might sound minimal, but it's becoming *impossible* to use debug mode and this package altogether.

## steps to reproduce
I wrote a small repro using flutter `3.47.1`, but I also tested it on `master` with the same results.

1. clone https://github.com/lucavenir/two_dimensional_scrollable_debug_jank.
2. `flutter pub get`.
3. `flutter run -d chrome`.
4. scroll/drag the table vertically and diagonally.
5. repeat with `flutter run --profile -d chrome`.

### expected results

the table remains... usable, while scrolling; even in debug mode.

### actual results

scrolling in debug mode is severely janky. ~400-600ms.
the same table scrolls smoothly in profile and release modes.

## code sample

again, it's one small file (`main.dart`) in this repo: https://github.com/lucavenir/two_dimensional_scrollable_debug_jank

### implementation notes
notice how the cells are empty, so - AFAIK - there's nothing much the inner widgets are adding, performance wise.

instead, I focused on adding:

- merged rows;
- row and column `TableSpanDecoration`s;
- one pinned row and column;
- `cacheExtent: 0`;
- disabled automatic keep-alives and repaint boundaries.

the last two were made in an effort of minimizing jank. that didn't work out.

## performance profiling on master channel

- [x] The issue still persists on the master channel.

## Timeline Traces

NOTE. of course, this being a `debug` mode problem only, I only traced the debug build.

Timeline trace

[repro_trace.gz](https://github.com/user-attachments/files/31510427/repro_trace.gz)

the debug CPU profile points to several calls to `RenderTwoDimensionalViewport.parentDataOf` from the table's merged-cell decoration path - including `getRowRect`.

in a nutshell: `parentDataOf` has three `.containsValue`/`.contain` calls in an assertion. AFAICT these are three `O(n)` calls on debug mode. [link](
https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart#L883-L889). code (for brevity):

```dart
assert(
_children.containsValue(child) || // oof
_keepAliveBucket.containsValue(child) || // oof
_debugOrphans!.contains(child), // oof
);
```

[looks like](
https://github.com/flutter/packages/blob/main/packages/two_dimensional_scrollables/lib/src/table_view/table.dart#L1791-L1919) the table invokes `parentDataOf` repeatedly while splitting decorations around merged cells and calculating decorations and stuff.

## possible fix?

I'm not sure why or how to circumvent/fix this tbh.

for what's worth, a gemini agent suggested:

> Use Key-Based Lookup: Since `child.parentData` contains the `ChildVicinity`, Flutter can check `_children[child.parentData.vicinity] == child` in `O(1)` time instead of scanning `_children.containsValue(child)`.

but - again - I have no clue if this is a valid or pure schlop.

## What target platforms are you seeing this bug on?

web only.

the jank on e.g. macOS is not nearly as comparable.

## OS/Browser name and version | Device information

- macOS 26.6.2
- Chrome 152.0.7977.64
- MacBook Pro (Mac16,7), Apple M4 Pro, 24 GB memory

## Does the problem occur on emulator/simulator as well as on physical devices?

not really. AFAICT this reliably happens on the web only.

## Is the problem only reproducible with Impeller?

N/A

## Logs

no exceptions or error logs are ever emitted.

## Flutter Doctor output

Doctor output

(when not using master)

```console
[✓] Flutter (Channel stable, 3.47.1, on macOS 26.6.2 25G83 darwin-arm64, locale en-IT)
• Flutter version 3.47.1 on channel stable at /Users/venir/.local/share/mise/http-tarballs/7eab9d8e9ea4ffbfefee7c22f3287ade60a47bdd2aef1630e4d6f353a9b43dc1_strip_1
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 6655482ec0 (8 days ago), 2026-08-19 10:07:23 -0700
• Engine revision 5d53178869
• Dart version 3.13.1
• DevTools version 2.60.0
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, enable-record-use, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration

[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0-rc1)
• Android SDK at /Users/venir/Library/Android/sdk
• Emulator version 35.2.10.0 (build_id 12414864) (CL:N/A)
• Platform android-36, build-tools 36.0.0-rc1
• Java binary at: /Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home/bin/java
• This JDK is specified in your Flutter configuration.
• Java version Java(TM) SE Runtime Environment (build 17.0.12+8-LTS-286)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 26.6)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 17F113
• CocoaPods version 1.16.2

[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Connected device (2 available)
• macOS (desktop) • macos • darwin-arm64 • macOS 26.6.2 25G83 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 152.0.7977.64

[✓] Network resources

• No issues found!
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the issue from the linked repository's main.dart with Flutter web in debug and profile modes. Read RenderTwoDimensionalViewport.parentDataOf in packages/flutter/lib/src/widgets/two_dimensional_viewport.dart and the merged-cell decoration path in packages/two_dimensional_scrollables/lib/src/table_view/table.dart. Done means the reported debug-mode web scrolling jank is resolved without regressing the profile and release behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
performance, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.