inset-rendering 0.18.0

Render-object tree and layout for Inset
Documentation
# inset-rendering/src
Flutter home: packages/flutter/lib/src/rendering
Ported against: ed2132410ee94b5a590cb7f67cee7a6ea9101a60

## Identical

- box.rs → BoxConstraints
- proxy_box.rs → HitTestBehavior
- object.rs → Constraints (`isTight` / `isNormalized` / `debugAssertIsValid`)
- relayout_when_system_fonts_change.rs → object.dart (`RelayoutWhenSystemFontsChangeMixin`)
- sliver.rs → GrowthDirection, applyGrowthDirectionToAxisDirection / ScrollDirection, SliverConstraints (`isTight` / `isNormalized` / `asBoxConstraints` / `==`)
- viewport_offset.rs → ScrollDirection, flipScrollDirection
- flex.rs → flex.dart
- stack.rs → StackFit
- box.rs → RenderBox intrinsics, dry layout and dry baselines with their caches
- layout_helper.rs → layout_helper.dart
- proxy_box.rs → RenderAspectRatio, RenderIntrinsicWidth, RenderIntrinsicHeight, RenderFittedBox
- shifted_box.rs → OverflowBoxFit, RenderConstrainedOverflowBox, RenderSizedOverflowBox, RenderFractionallySizedOverflowBox, RenderCustomSingleChildLayoutBox, SingleChildLayoutDelegate, RenderBaseline
- animated_size.rs → animated_size.dart
- viewport.rs → RenderViewportBase.debugThrowIfNotCheckingIntrinsics and the four intrinsics, RenderViewport.computeDryLayout
- object.rs / box.rs → getTransformTo, globalToLocal, localToGlobal
- editable.rs → TextSelectionPoint
- debug.rs → debug.dart
- pipeline_owner.rs → object.dart (PipelineOwner)
- sliver_fixed_extent_list.rs → sliver_fixed_extent_list.dart
- image.rs → image.dart (RenderImage)
- wrap.rs → wrap.dart

## object.rs → object.dart (RenderObject)

- Change: Flutter's `attach` / `detach` overrides are the post-hooks `did_attach` / `did_detach`, which run after the base body.
  Reason: language — a trait default cannot call `super`; no Flutter override reads its owner before `super.detach`.
  Affect: a hook cannot act before the owner is set, and `did_detach` runs with the owner already cleared.

- Change: a panic in `perform_layout`, `perform_resize` or `paint` unwinds.
  Reason: language — no `FlutterError.reportError` hook to catch and continue.
  Affect: layout and paint do not survive a failing render object.

- Change: `mark_needs_compositing_bits_update` skips telling the parent only when the node's own stored compositing bit, the one the parent last counted, is set and it is still a repaint boundary, where Flutter checks `_wasRepaintBoundary`.
  Reason: platform — `_wasRepaintBoundary` changes only when the node paints, so a boundary that stopped being one while an ancestor skipped painting it keeps a stale `true`; Flutter's display list ignores the resulting unmatched `restore()`, valo's panics.
  Affect: an `Opacity` inside a clip, inside another `Opacity`, that both go from 0 to visible in one frame stays clipped, where Flutter (3.47.1, checked) draws it outside the clip, and Inset no longer panics.

- Change: `layout` lives on the protocol's type-erased handle and takes that protocol's constraints.
  Reason: language — there is no abstract `Constraints` an erased node can hold.
  Affect: a parent that does not know its child's protocol cannot lay it out; there is no protocol-neutral `layout`.

## box.rs → box.dart (hit testing)

- Change: `BoxHitTestResult` is a view over a `HitTestResult` with no standalone constructor, and `BoxHitTestEntry` is the entry's target rather than a subclass of the entry.
  Reason: language — no subclassing of the gesture crate's result and entry types.
  Affect: a box hit test only runs inside a live `HitTestResult`; `handle_event` receives the `BoxHitTestEntry`.

- Change: a render object named by a pressed pointer's hit-test path, or by the mouse tracker, outlives its `dispose` until they let go.
  Reason: language — Dart keeps it alive by holding it; here the holder retains it (`App::retain`).
  Affect: a `Listener` rebuilt mid-press still receives its release; a region that just left the tree still receives its exit.

## painting_context.rs → object.dart (PaintingContext), layer.rs → layer.dart

- Change: a `LayerHandle` dropped without being cleared keeps its layer.
  Reason: language — the handle lives inside an arena object, so its setter takes the `App` (`LayerHandle::set_layer`) and its drop has none.
  Affect: that layer's entry lives until the `App` drops, where Dart's collector would take it.

- Change: `Layer.dispose` ends in `App::destroy`.
  Reason: language — no GC.
  Affect: a handle to a disposed layer is stale and `app.get` panics on it; `AnyLayer::debug_disposed` answers true, and a composition callback for it is a no-op.

- Change: annotation search is the non-generic `AnnotationSearch` in place of `AnnotationResult<S>`.
  Reason: language — a generic method cannot sit in a vtable.
  Affect: an annotated region's value is an `Rc<dyn Any>` found only by its exact type, and a `find_annotations` override asks `result.accepts(..)` before adding.

- Change: `LeaderLayer` / `FollowerLayer` hold the `LayerLink` as a `RetainedHandle`.
  Reason: language — Dart's GC keeps a link alive while a detached layer still names it.
  Affect: the link's entry lingers until those layers are disposed, past the `dispose` of the state that owns it.

## composition_layer_view.rs, layer.rs (`EmbeddedLayer`) → platform views (`PlatformViewLayer`, `RenderAndroidView` and kin)

- Change: one `RenderCompositionLayerView` shows a composition layer on every platform, through an `EmbeddedLayer`, named after Flutter's embedded views.
  Reason: platform — every compositor Inset targets shows a layer as a rectangle and its content.
  Affect: an app shows a composition layer with the same widget everywhere.

## video_frame_view.rs, layer.rs (`VideoLayer`) → `TextureBox`, `TextureLayer`

- Change: `RenderVideoFrameView` and its `VideoLayer` hold a video's `VideoFrameReader`, where Flutter's `TextureBox` and `TextureLayer` hold a texture id, and have no `freeze` or filter quality.
  Reason: platform — the reader is the frame source itself, with no registry between, and the host takes the frame for the moment the picture reaches the screen when it draws, sampled linearly.
  Affect: a video draws as part of the picture, under the clips, transforms and opacity above it.

## view.rs → view.dart, binding.rs → binding.dart

- Change: a frame lays out every view's render tree, then paints and composites only its own views, each without the views a `ViewAnchor` places in it.
  Reason: platform — each view has frames of its own, a view placed in another included.
  Affect: drawing one window repaints no other.

- Change: a view is composited at a frame only when its paint had work or it was marked, as when it was added, after the warm-up frame or when the app comes back from the background, which is Flutter's #192128 that Flutter has since reverted.
  Reason: platform — many of a view's frames change nothing in it, and every host keeps a window's last frame on screen.
  Affect: a window whose content did not change is not drawn again, so a host that clears or rebuilds its surface draws the last frame on it itself.

- Change: `RendererBinding` calls the hooks `will_draw_frame`, `did_draw_frame` and `did_handle_metrics_changed` on a registered `RendererBindingOverrides` instead of being overridden.
  Reason: language — Flutter's `WidgetsBinding` overrides `drawFrame` and `handleMetricsChanged` through mixin order, and a crate above cannot override a method below it.
  Affect: a binding layered above registers with `set_overrides` to get its build phase; a render-tree-only host runs the plain frame.

- Change: the deprecated `renderView` and `pipelineOwner` are not ported, and `init_render_view` (`TestRenderingFlutterBinding.initRenderView`) takes the view it renders into.
  Reason: platform — they serve the implicit view, and there is no implicit view.
  Affect: a test that renders without widgets passes its view.

## mouse_tracker.rs → mouse_tracker.dart

- Change: `MouseTracker` finds the annotations in a hit test by asking two kinds of target: a render object answers through its `RenderObject::mouse_tracker_annotation` override, which the tracker reads again on each pointer event, and a `TextSpan` is one.
  Reason: language — a `dyn HitTestTarget` cannot be asked whether it also implements another trait, so the tracker checks the two kinds of object Flutter's framework makes annotations of.
  Affect: a hit test target of any other type never gets enter, exit or a cursor, and a render object already freed from the `App` is skipped.

## proxy_box.rs → proxy_box.dart / shifted_box.rs → shifted_box.dart

- Change: `CustomClipper<T>` is a trait held as an `Rc`: `reclip()` is a method the implementor answers, `should_reclip` receives the old clipper as `&dyn CustomClipper<T>`, and two clippers compare by `Rc::ptr_eq`.
  Reason: language — a Rust trait has no fields, no constructor, no `runtimeType` and no identity equality on a boxed value.
  Affect: a fresh `Rc` around an equal clipper counts as a different clipper and re-subscribes; `old_clipper` is read with `as_any().downcast_ref()`.

- Change: `RenderTransform` has no `filterQuality`.
  Reason: platform — the filtered path is an `ImageFilterLayer` over `ImageFilter.matrix`, which neither the embedder's `Paint` nor `SceneBuilder` has.
  Affect: a transform always paints through `push_transform`, or through the child's paint offset when the matrix is a translation.

- Change: `RenderColoredBox` does not pass `is_anti_alias` to the canvas.
  Reason: platform — valo's `Paint` has no anti-alias flag; painting's `PORTING.md` records the same for `Clip`.
  Affect: the fill is drawn the way valo draws it, and setting the flag only marks a repaint.

## shifted_box.rs → shifted_box.dart (RenderConstraintsTransformBox)

- Change: `BoxConstraintsTransform` is a plain `fn(BoxConstraints) -> BoxConstraints`, and the setter compares the old and new transform by function address.
  Reason: language — a Rust closure has no identity, and Dart's setter compares two function values to decide whether anything changed.
  Affect: a transform that captures state cannot be used; when the addresses differ for the same function the setter still only marks layout if the current constraints map to a different value.

## image_filter_config.rs → image_filter_config.dart

- Change: a blur has no `tileMode`.
  Reason: platform — valo's blur has no tile mode (`inset-embedder`'s `PORTING.md` records that).
  Affect: every blur uses valo's edge behaviour, and `debug_short_description` prints no tile-mode word.

## custom_paint.rs → custom_paint.dart

- Change: `CustomPainter` is a trait held as an `Rc`, with `repaint()` a method the implementor answers and identity by `Rc::ptr_eq`.
  Reason: language — a trait has no fields, constructor or identity.
  Affect: a painter wrapped in a new `Rc` each frame is unsubscribed and re-subscribed each frame.

## paragraph.rs → paragraph.dart

- Change: `RenderParagraph` takes an optional `FontCollection` handle, falling back to `PaintingBinding`'s app-wide one, and has no selection registrar or `selectionColor`.
  Reason: platform — the font collection is explicit (painting's `binding.rs`), and selection waits on `selection.dart`.
  Affect: text in a `RichText` cannot be selected.

- Change: `TextOverflow::Fade` clips like `Clip`.
  Reason: platform — the fade is a gradient shader, and gradients are deferred.
  Affect: overflowing text is cut, not faded.

## table.rs → table.dart

- Change: `RenderTable`'s column width setters skip the relayout only when given the same `Rc` (`TableColumnWidthRef`, compared with `Rc::ptr_eq`), and Dart's `const FlexColumnWidth()` default is one shared value, `FlexColumnWidth::default_width`.
  Reason: language — Dart compares column widths by identity and makes each `const` one object, and Rust has no such constants.
  Affect: a column width built afresh on each rebuild lays the table out again each time, as a non-`const` one does in Dart; keeping the same `Rc` avoids it.

## table_border.rs → table_border.dart

- Change: `TableBorder::lerp` returns `a` when the two borders are equal, where Dart returns it when they are the same object.
  Reason: language — a `Copy` value has no identity.
  Affect: lerping two equal borders keeps their `border_radius`, which Dart's lerp drops for two distinct equal borders.

## editable.rs → editable.dart

- Change: `RenderEditable` has no custom-paint child boxes and no internal tap / long-press recognizers, and caret, selection and the handle leaders paint in `paint`.
  Reason: platform — engine layers wait.
  Affect: selection is driven from above (`select_position_at` under an `ignore_pointer`) rather than by the editable's own recognizers, and the handles' links are led from `paint` for a `CompositedTransformFollower`.

- Change: `VerticalCaretMovementRun::is_valid` compares the editable's layout generation.
  Reason: language — `compute_line_metrics` returns a new `Vec` each call, so Dart's `identical` on the list would always fail.
  Affect: a run stays valid across reads until the next layout.

## object.rs / box.rs → object.dart / box.dart (container children)

- Change: `ParentData` answers the type-keyed query `provide(TypeId)` / `provide_mut`, read as `part::<P>()`, so a value built from several halves answers for each of them; `ContainerBoxParentData` joins the container half with `BoxParentData`, and `parent_data_is::<P>()` / `parent_data_of::<P>()` accept a value that answers `P`, as Dart's `is` and `as` accept a subclass.
  Reason: language — an exact downcast cannot reach Dart's `parentData! as BoxParentData` on a subclass, and one cast method per half would close the set of halves to this crate.
  Affect: parent data that does not answer `BoxParentData` from `provide` cannot be positioned by a box parent; a child's offset is read as `child.box_parent_data(app).offset`.

## custom_layout.rs → custom_layout.dart

- Change: `MultiChildLayoutDelegate` is a trait held as an `Rc`, with `relayout()` a method the implementor answers and identity by `Rc::ptr_eq`.
  Reason: language — a Rust trait has no constructor, no fields, no `runtimeType` and no identity equality on a boxed value.
  Affect: a delegate rewrapped in a new `Rc` re-subscribes; `old_delegate` is read with `as_any().downcast_ref()`.

- Change: Dart's four `FlutterError`s (no such child, a child laid out twice, invalid constraints, a child left unlaid-out) are panics, and the ones Dart raises from an `assert` are debug-only.
  Reason: language — no catchable exception, and the set of children still needing layout is debug state.
  Affect: a delegate that misuses its children takes the frame down instead of reporting a `FlutterError`.

## stack.rs → stack.dart

- Change: `RelativeRect::lerp(Some(a), None, t)` interpolates `a` towards `RelativeRect::FILL`.
  Reason: language — Dart's branch reads `b!` on the null `b`, which Rust cannot express.
  Affect: the call returns a value where Dart throws.

## sliver_multi_box_adaptor.rs → sliver_multi_box_adaptor.dart

- Change: moving a child into or out of the keep-alive bucket gives it new parent data from the sliver's own `setup_parent_data` and writes back its index, layout offset and keep-alive flags, where Dart re-assigns the object it saved before `dropChild` nulled it.
  Reason: language — `drop_child` owns and drops the boxed parent data, which Dart's caller keeps a reference to.
  Affect: a subclass's own fields restart empty while the child is kept alive: a grid tile's `cross_axis_offset` is `None` until the grid lays it out again, before it paints or hits.

## sliver_grid.rs → sliver_grid.dart

- Change: `SliverGridDelegate` and `SliverGridLayout` are traits, the delegate held as an `Rc` with identity by `Rc::ptr_eq` and `get_layout` returning a `Box<dyn SliverGridLayout>`; the two delegates' optional arguments are fluent setters.
  Reason: language — a Rust trait has no constructor, no fields, no `runtimeType` and no identity equality on a boxed value.
  Affect: a delegate rewrapped in a new `Rc` is compared with `should_relayout`, which reads `old_delegate` with `as_any().downcast_ref()`.

## sliver.rs → sliver.dart

- Change: `SliverGeometry::is_zero()` answers Dart's `geometry == SliverGeometry.zero` by comparing the fields.
  Reason: language — `SliverGeometry` does not override `==`, so Dart compares canonicalized const identity, which a `Copy` value has none of.
  Affect: a geometry that happens to equal `SliverGeometry::ZERO` field by field reads as zero where Dart's identity check says no.

## viewport.rs → viewport.dart

- Change: Dart's `object is RenderAbstractViewport` is the type-keyed query `RenderObject::interface(TypeId)`, read as `object.interface::<AnyRenderAbstractViewport>()`.
  Reason: language — an erased render object cannot be asked whether it implements an interface, and one virtual per interface would close the set of interfaces to this crate.
  Affect: a viewport that does not answer that id is not found by `RenderAbstractViewport::of`, and neither is a floating header that does not answer its own.

## sliver_persistent_header.rs → sliver_persistent_header.dart

- Change: Flutter's `markNeedsLayout` override is the named `RenderSliverPersistentHeader::mark_needs_layout`.
  Reason: language — `mark_needs_layout` is an inherent method on the type-erased handle, not a virtual.
  Affect: marking a persistent header through the erased handle does not remeasure its child; the named call does.

## tweens.rs → tweens.dart

- Change: `FractionalOffsetTween`, `AlignmentTween` and `AlignmentGeometryTween` are `Clone` values that implement `Animatable<T>` directly, where `inset_animation`'s tweens are arena objects.
  Reason: language — orphan rule: an `Animatable` impl for a `Handle` of one of these tweens names no type of this crate.
  Affect: `drive` takes a clone, so writing `begin` or `end` afterwards does not reach the driven animation, as it does on a Dart `Tween`.

## Deferred

- `RenderImage`'s `color` / `colorBlendMode` and `invertColors`. Trigger: painting's colour filters.
- `RenderImage`'s `centerSlice`. Trigger: an image drawn as a resizable frame.
- `RenderImage`'s `filterQuality` and `isAntiAlias`. Trigger: a caller that needs to choose how an image is sampled.
- `RenderImage`'s semantics label. Trigger: accessibility.
- `PlatformViewLayer`, `PerformanceOverlayLayer`, `ClipRSuperellipseLayer`, `ColorFilterLayer`, `ImageFilterLayer`, `ShaderMaskLayer`, `OffsetLayer.toImage` / `toImageSync`, `PaintingContext.pushColorFilter`. Trigger: a platform view, a superellipse clip, a colour/image/shader filter widget, `RepaintBoundary.toImage`.
- `PaintingContext.addCompositionCallback`. Trigger: a caller that needs composition callbacks on the painting context (layers already have them).
- Debug paint overlays on boxes, slivers and the viewport, and the overflow indicators of `RenderFlex` and `RenderConstraintsTransformBox` (an overflowing box clips but paints no striped hint); with them, `paintsChild` as a virtual. Trigger: inspector.
- Semantics on `PipelineOwner`, `RenderObject`, `RenderCustomPaint`, the ignore- and absorb-pointer boxes, `RenderOffstage`, the opacity boxes' `alwaysIncludeSemantics`, `RenderTable`, the viewport and the slivers. Trigger: a11y; do not stub.
- The semantics half of `PipelineManifold`; the frame-request half is ported, and `RendererBinding::init_render_view` stays for render-tree-only hosts and must never be called in an app that runs `run_app`. Trigger: semantics.
- The layout-contract asserts: `_DebugSize` and `debugAssertDoesMeetConstraints` on box, sliver and the fixed-extent adaptor; `SliverGeometry::debug_assert_is_valid` is ported and the viewport calls it. Trigger: the first layout bug one of them would have caught.
- `layout` and `constraints` as override points; `markNeedsLayout` is one on the box protocol only. Trigger: OverlayPortal, `RenderView`. Ask before adding.
- `RenderView.applyPaintTransform`; `performReassemble`. Trigger: `getTransformTo`, hot reload.
- `RenderParagraph.applyPaintTransform`. Trigger: a caller that needs the paragraph's paint transform.
- `RenderEditable` inline children, the custom-paint child boxes and the internal tap / long-press recognizers. Trigger: `WidgetSpan`; a field that does not set `ignorePointer`.
- `SliverConstraints.debugAssertIsValid` extra numeric checks. Trigger: a caller that relies on those messages.
- `RenderIgnoreBaseline`, which reports no baseline for a child that has one, so that a baseline-aligned row puts that child at the top. Trigger: a child a baseline-aligned `Row` should not align by its baseline.
- `RenderBoxBase` sits in `proxy_box.rs` beside its callers instead of next to `RenderBox`. Trigger: the next edit of `box.rs`.
- `RenderTransform.filterQuality` and Dart's `ImageFilterLayer` path. Trigger: the first `Transform(filterQuality:)`, with `PaintingContext.pushColorFilter`.