Skip to content

perf(grid): eliminate per-cell allocations of BoxDecoration, Border, and TextStyle in _GridCell via flyweight cache #1519

Open

Description

@ZhuchkaTriplesix

Summary

In lib/features/workspace/grid/grid_cell_renderer.dart (lines 112–168):

Inside _GridCell.build(), which runs for every visible cell in every visible row on every scroll event:

final style = material.TextStyle(...); // Allocates a new TextStyle
final bg = isSelected ? ... : ...;
decoration: material.BoxDecoration(
  color: bg,
  border: material.Border( // Allocates a new Border
    right: material.BorderSide(...), // Allocates BorderSide instances
    left: isSelectionLeft ? ... : ...,
    top: isSelectionTop ? ... : ...,
    bottom: ...,
  ),
),

For a typical grid view with 40 visible rows $\times$ 15 columns = 600 visible cells:

  • 600 TextStyle objects
  • 600 BoxDecoration objects
  • 600 Border objects
  • 1,200 BorderSide objects
  • ~3,000 layout decoration allocations PER FRAME during fast scrolling.

Because every cell gets a newly instantiated BoxDecoration reference, Flutter's RenderDecoratedBox cannot short-circuit painting via identical(oldDecoration, newDecoration).

Architectural Solution: Flyweight Decoration Pool

Cell appearance states form a finite set of combinations:

  • striped (2 states)
  • isSelected (2 states)
  • rowStatus (clean / inserted / deleted) (3 states)
  • cellStatus (clean / modified) (2 states)
  1. Precompute and pool the decoration instances in a compact lookup cache (Flyweight pattern) keyed by integer bitmask:
    static BoxDecoration getDecoration({
      required bool striped,
      required bool isSelected,
      required StagedRowStatus rowStatus,
      required StagedCellStatus cellStatus,
      required ColorScheme colors,
    }) { ... }
  2. Cache the 4 standard text styles (normal, nullItalic, deletedStrikethrough, modified).
  3. Reused decoration instances allow RenderDecoratedBox to skip repainting when cell state is unchanged.

Acceptance Criteria

  • Scrolling the data grid produces zero BoxDecoration, Border, or TextStyle allocations for clean/unchanged cells.
  • 120 FPS scrolling maintained without GC stutter on large datasets (>10,000 rows).

Activity

  1. added
    frontendTheme parser epic label: frontend
    performanceTheme parser epic label: performance
    data-gridInteractive data grid, cell editor, filtering, groupings
    P2Medium priority / Parity & Refactoring
    on Oct 12, 2026
  2. added this to the 0.5.0 milestone on Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium priority / Parity & Refactoringdata-gridInteractive data grid, cell editor, filtering, groupingsfrontendTheme parser epic label: frontendperformanceTheme parser epic label: performance

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions