can "render" counter
diff --git a/examples/counter.dart b/examples/counter.dart
new file mode 100644
index 0000000..d560b3d
--- /dev/null
+++ b/examples/counter.dart
@@ -0,0 +1,65 @@
+import 'package:flute/material.dart';
+
+void main() {
+  runApp(MyApp());
+}
+
+class MyApp extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      title: 'Flutter Demo',
+      theme: ThemeData(
+        primarySwatch: Colors.blue,
+      ),
+      home: MyHomePage('Flutter Demo Home Page'),
+    );
+  }
+}
+
+class MyHomePage extends StatefulWidget {
+  MyHomePage(this.title);
+
+  final String title;
+
+  @override
+  _MyHomePageState createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State<MyHomePage> {
+  int _counter = 0;
+
+  void _incrementCounter() {
+    setState(() {
+      _counter++;
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(widget.title),
+      ),
+      body: Center(
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: <Widget>[
+            Text(
+              'You have pushed the button this many times:',
+            ),
+            Text(
+              '$_counter',
+              style: Theme.of(context).textTheme.headline4,
+            ),
+          ],
+        ),
+      ),
+      floatingActionButton: FloatingActionButton(
+        onPressed: _incrementCounter,
+        tooltip: 'Increment',
+        child: Icon(Icons.add),
+      ),
+    );
+  }
+}
diff --git a/lib/src/ui/compositing.dart b/lib/src/ui/compositing.dart
index d3990b4..b49e111 100644
--- a/lib/src/ui/compositing.dart
+++ b/lib/src/ui/compositing.dart
@@ -11,7 +11,7 @@
 ///
 /// Scene objects can be displayed on the screen using the [FlutterView.render]
 /// method.
-class Scene extends NativeFieldWrapperClass2 {
+class Scene {
   /// This class is created by the engine, and should not be instantiated
   /// or extended directly.
   ///
@@ -45,15 +45,13 @@
 // passed as `oldLayer` to `pushTransform`. This is achieved by having one
 // concrete subclass of this class per push method.
 abstract class _EngineLayerWrapper implements EngineLayer {
-  _EngineLayerWrapper._(this._nativeLayer);
-
-  EngineLayer _nativeLayer;
+  _EngineLayerWrapper._();
 
   // Children of this layer.
   //
   // Null if this layer has no children. This field is populated only in debug
   // mode.
-  List<_EngineLayerWrapper>? _debugChildren;
+  List<_EngineLayerWrapper>? _children;
 
   // Whether this layer was used as `oldLayer` in a past frame.
   //
@@ -73,6 +71,15 @@
   }
 }
 
+class _PictureLayer extends _EngineLayerWrapper {
+  _PictureLayer(this.dx, this.dy, this.picture, this.hints) : super._();
+
+  final double dx;
+  final double dy;
+  final Picture picture;
+  final int hints;
+}
+
 /// An opaque handle to a transform engine layer.
 ///
 /// Instances of this class are created by [SceneBuilder.pushTransform].
@@ -83,7 +90,10 @@
 /// a custom implementation of this class.
 /// {@endtemplate}
 class TransformEngineLayer extends _EngineLayerWrapper {
-  TransformEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  TransformEngineLayer._(Float64List matrix4)
+    : this.matrix4 = Float64List.fromList(matrix4), super._();
+
+  final Float64List matrix4;
 }
 
 /// An opaque handle to an offset engine layer.
@@ -92,7 +102,10 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class OffsetEngineLayer extends _EngineLayerWrapper {
-  OffsetEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  OffsetEngineLayer._(this.dx, this.dy) : super._();
+
+  final double dx;
+  final double dy;
 }
 
 /// An opaque handle to a clip rect engine layer.
@@ -101,7 +114,13 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class ClipRectEngineLayer extends _EngineLayerWrapper {
-  ClipRectEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  ClipRectEngineLayer._(this.left, this.right, this.top, this.bottom, this.clipBehavior) : super._();
+
+  final double left;
+  final double top;
+  final double right;
+  final double bottom;
+  final int clipBehavior;
 }
 
 /// An opaque handle to a clip rounded rect engine layer.
@@ -110,7 +129,10 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class ClipRRectEngineLayer extends _EngineLayerWrapper {
-  ClipRRectEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  ClipRRectEngineLayer._(this.rrect, this.clipBehavior) : super._();
+
+  final Float32List rrect;
+  final int clipBehavior;
 }
 
 /// An opaque handle to a clip path engine layer.
@@ -119,7 +141,9 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class ClipPathEngineLayer extends _EngineLayerWrapper {
-  ClipPathEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  ClipPathEngineLayer._(this.path) : super._();
+
+  final Path path;
 }
 
 /// An opaque handle to an opacity engine layer.
@@ -128,7 +152,11 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class OpacityEngineLayer extends _EngineLayerWrapper {
-  OpacityEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  OpacityEngineLayer._(this.alpha, this.dx, this.dy) : super._();
+
+  final int alpha;
+  final double dx;
+  final double dy;
 }
 
 /// An opaque handle to a color filter engine layer.
@@ -137,7 +165,9 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class ColorFilterEngineLayer extends _EngineLayerWrapper {
-  ColorFilterEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  ColorFilterEngineLayer._(this.filter) : super._();
+
+  final _ColorFilter filter;
 }
 
 /// An opaque handle to an image filter engine layer.
@@ -146,7 +176,9 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class ImageFilterEngineLayer extends _EngineLayerWrapper {
-  ImageFilterEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  ImageFilterEngineLayer._(this.filter) : super._();
+
+  final _ImageFilter filter;
 }
 
 /// An opaque handle to a backdrop filter engine layer.
@@ -155,7 +187,9 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class BackdropFilterEngineLayer extends _EngineLayerWrapper {
-  BackdropFilterEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  BackdropFilterEngineLayer._(this.filter) : super._();
+
+  final _ImageFilter filter;
 }
 
 /// An opaque handle to a shader mask engine layer.
@@ -164,7 +198,21 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class ShaderMaskEngineLayer extends _EngineLayerWrapper {
-  ShaderMaskEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  ShaderMaskEngineLayer._(
+    this.shader,
+    this.left,
+    this.right,
+    this.top,
+    this.bottom,
+    this.blendMode,
+  ) : super._();
+
+  final Shader shader;
+  final double left;
+  final double top;
+  final double right;
+  final double bottom;
+  final int blendMode;
 }
 
 /// An opaque handle to a physical shape engine layer.
@@ -173,7 +221,19 @@
 ///
 /// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
 class PhysicalShapeEngineLayer extends _EngineLayerWrapper {
-  PhysicalShapeEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
+  PhysicalShapeEngineLayer._(
+    this.path,
+    this.elevation,
+    this.colorValue,
+    this.shadowColorValue,
+    this.clipBehavior,
+  ) : super._();
+
+  final Path path;
+  final double elevation;
+  final int colorValue;
+  final int shadowColorValue;
+  final int clipBehavior;
 }
 
 /// Builds a [Scene] containing the given visuals.
@@ -183,9 +243,8 @@
 /// To draw graphical operations onto a [Scene], first create a
 /// [Picture] using a [PictureRecorder] and a [Canvas], and then add
 /// it to the scene using [addPicture].
-class SceneBuilder extends NativeFieldWrapperClass2 {
+class SceneBuilder {
   /// Creates an empty [SceneBuilder] object.
-  @pragma('vm:entry-point')
   SceneBuilder();
 
   // Layers used in this scene.
@@ -223,21 +282,17 @@
     return true;
   }
 
+  _EngineLayerWrapper? _rootLayer;
   final List<_EngineLayerWrapper> _layerStack = <_EngineLayerWrapper>[];
 
-  // Pushes the `newLayer` onto the `_layerStack` and adds it to the
-  // `_debugChildren` of the current layer in the stack, if any.
-  bool _debugPushLayer(_EngineLayerWrapper newLayer) {
-    assert(() {
-      if (_layerStack.isNotEmpty) {
-        final _EngineLayerWrapper currentLayer = _layerStack.last;
-        currentLayer._debugChildren ??= <_EngineLayerWrapper>[];
-        currentLayer._debugChildren!.add(newLayer);
-      }
-      _layerStack.add(newLayer);
-      return true;
-    }());
-    return true;
+  void _pushLayer(_EngineLayerWrapper layer) {
+    _rootLayer ??= layer;
+    if (_layerStack.isNotEmpty) {
+      final _EngineLayerWrapper currentLayer = _layerStack.last;
+      currentLayer._children ??= <_EngineLayerWrapper>[];
+      currentLayer._children!.add(layer);
+    }
+    _layerStack.add(layer);
   }
 
   /// Pushes a transform operation onto the operation stack.
@@ -274,15 +329,11 @@
   }) {
     assert(_matrix4IsValid(matrix4));
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushTransform'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushTransform(engineLayer, matrix4);
-    final TransformEngineLayer layer = TransformEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final TransformEngineLayer layer = TransformEngineLayer._(matrix4);
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushTransform(EngineLayer layer, Float64List matrix4) { throw UnimplementedError(); }
-
   /// Pushes an offset operation onto the operation stack.
   ///
   /// This is equivalent to [pushTransform] with a matrix with only translation.
@@ -298,15 +349,11 @@
     OffsetEngineLayer? oldLayer,
   }) {
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushOffset'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushOffset(engineLayer, dx, dy);
-    final OffsetEngineLayer layer = OffsetEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final OffsetEngineLayer layer = OffsetEngineLayer._(dx ,dy);
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushOffset(EngineLayer layer, double dx, double dy) { throw UnimplementedError(); }
-
   /// Pushes a rectangular clip operation onto the operation stack.
   ///
   /// Rasterization outside the given rectangle is discarded.
@@ -325,16 +372,11 @@
     assert(clipBehavior != null); // ignore: unnecessary_null_comparison
     assert(clipBehavior != Clip.none);
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipRect'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushClipRect(engineLayer, rect.left, rect.right, rect.top, rect.bottom, clipBehavior.index);
-    final ClipRectEngineLayer layer = ClipRectEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final ClipRectEngineLayer layer = ClipRectEngineLayer._(rect.left, rect.right, rect.top, rect.bottom, clipBehavior.index);
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushClipRect(EngineLayer outEngineLayer, double left, double right, double top, double bottom, int clipBehavior)
-      { throw UnimplementedError(); }
-
   /// Pushes a rounded-rectangular clip operation onto the operation stack.
   ///
   /// Rasterization outside the given rounded rectangle is discarded.
@@ -353,16 +395,11 @@
     assert(clipBehavior != null); // ignore: unnecessary_null_comparison
     assert(clipBehavior != Clip.none);
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipRRect'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushClipRRect(engineLayer, rrect._value32, clipBehavior.index);
-    final ClipRRectEngineLayer layer = ClipRRectEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final ClipRRectEngineLayer layer = ClipRRectEngineLayer._(rrect._value32, clipBehavior.index);
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushClipRRect(EngineLayer layer, Float32List rrect, int clipBehavior)
-      { throw UnimplementedError(); }
-
   /// Pushes a path clip operation onto the operation stack.
   ///
   /// Rasterization outside the given path is discarded.
@@ -381,15 +418,11 @@
     assert(clipBehavior != null); // ignore: unnecessary_null_comparison
     assert(clipBehavior != Clip.none);
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipPath'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushClipPath(engineLayer, path, clipBehavior.index);
-    final ClipPathEngineLayer layer = ClipPathEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final ClipPathEngineLayer layer = ClipPathEngineLayer._(path);
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushClipPath(EngineLayer layer, Path path, int clipBehavior) { throw UnimplementedError(); }
-
   /// Pushes an opacity operation onto the operation stack.
   ///
   /// The given alpha value is blended into the alpha value of the objects'
@@ -408,15 +441,11 @@
     OpacityEngineLayer? oldLayer,
   }) {
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushOpacity'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushOpacity(engineLayer, alpha, offset!.dx, offset.dy);
-    final OpacityEngineLayer layer = OpacityEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final OpacityEngineLayer layer = OpacityEngineLayer._(alpha, offset!.dx, offset.dy);
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushOpacity(EngineLayer layer, int alpha, double dx, double dy) { throw UnimplementedError(); }
-
   /// Pushes a color filter operation onto the operation stack.
   ///
   /// The given color is applied to the objects' rasterization using the given
@@ -435,15 +464,11 @@
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushColorFilter'));
     final _ColorFilter nativeFilter = filter._toNativeColorFilter()!;
     assert(nativeFilter != null); // ignore: unnecessary_null_comparison
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushColorFilter(engineLayer, nativeFilter);
-    final ColorFilterEngineLayer layer = ColorFilterEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final ColorFilterEngineLayer layer = ColorFilterEngineLayer._(nativeFilter);
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushColorFilter(EngineLayer layer, _ColorFilter filter) { throw UnimplementedError(); }
-
   /// Pushes an image filter operation onto the operation stack.
   ///
   /// The given filter is applied to the children's rasterization before compositing them into
@@ -462,15 +487,11 @@
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushImageFilter'));
     final _ImageFilter nativeFilter = filter._toNativeImageFilter();
     assert(nativeFilter != null); // ignore: unnecessary_null_comparison
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushImageFilter(engineLayer, nativeFilter);
-    final ImageFilterEngineLayer layer = ImageFilterEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final ImageFilterEngineLayer layer = ImageFilterEngineLayer._(nativeFilter);
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushImageFilter(EngineLayer outEngineLayer, _ImageFilter filter) { throw UnimplementedError(); }
-
   /// Pushes a backdrop filter operation onto the operation stack.
   ///
   /// The given filter is applied to the current contents of the scene prior to
@@ -486,15 +507,11 @@
     BackdropFilterEngineLayer? oldLayer,
   }) {
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushBackdropFilter'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushBackdropFilter(engineLayer, filter._toNativeImageFilter());
-    final BackdropFilterEngineLayer layer = BackdropFilterEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    final BackdropFilterEngineLayer layer = BackdropFilterEngineLayer._(filter._toNativeImageFilter());
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter) { throw UnimplementedError(); }
-
   /// Pushes a shader mask operation onto the operation stack.
   ///
   /// The given shader is applied to the object's rasterization in the given
@@ -512,9 +529,7 @@
     ShaderMaskEngineLayer? oldLayer,
   }) {
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushShaderMask'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushShaderMask(
-      engineLayer,
+    final ShaderMaskEngineLayer layer = ShaderMaskEngineLayer._(
       shader,
       maskRect.left,
       maskRect.right,
@@ -522,20 +537,10 @@
       maskRect.bottom,
       blendMode.index,
     );
-    final ShaderMaskEngineLayer layer = ShaderMaskEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushShaderMask(
-      EngineLayer engineLayer,
-      Shader shader,
-      double maskRectLeft,
-      double maskRectRight,
-      double maskRectTop,
-      double maskRectBottom,
-      int blendMode) { throw UnimplementedError(); }
-
   /// Pushes a physical layer operation for an arbitrary shape onto the
   /// operation stack.
   ///
@@ -562,23 +567,17 @@
     PhysicalShapeEngineLayer? oldLayer,
   }) {
     assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushPhysicalShape'));
-    final EngineLayer engineLayer = EngineLayer._();
-    _pushPhysicalShape(
-      engineLayer,
+    final PhysicalShapeEngineLayer layer = PhysicalShapeEngineLayer._(
       path,
       elevation,
       color.value,
       shadowColor?.value ?? 0xFF000000,
       clipBehavior.index,
     );
-    final PhysicalShapeEngineLayer layer = PhysicalShapeEngineLayer._(engineLayer);
-    assert(_debugPushLayer(layer));
+    _pushLayer(layer);
     return layer;
   }
 
-  void _pushPhysicalShape(EngineLayer outEngineLayer, Path path, double elevation, int color, int shadowColor,
-      int clipBehavior) { throw UnimplementedError(); }
-
   /// Ends the effect of the most recently pushed operation.
   ///
   /// Internally the scene builder maintains a stack of operations. Each of the
@@ -589,11 +588,8 @@
     if (_layerStack.isNotEmpty) {
       _layerStack.removeLast();
     }
-    _pop();
   }
 
-  void _pop() { throw UnimplementedError(); }
-
   /// Add a retained engine layer subtree from previous frames.
   ///
   /// All the engine layers that are in the subtree of the retained layer will
@@ -613,7 +609,7 @@
         _debugCheckUsedOnce(parentLayer, 'retained layer');
         parentLayer._debugCheckNotUsedAsOldLayer();
 
-        final List<_EngineLayerWrapper>? children = parentLayer._debugChildren;
+        final List<_EngineLayerWrapper>? children = parentLayer._children;
         if (children == null || children.isEmpty) {
           return;
         }
@@ -626,11 +622,10 @@
     }());
 
     final _EngineLayerWrapper wrapper = retainedLayer as _EngineLayerWrapper;
-    _addRetained(wrapper._nativeLayer);
+    _pushLayer(wrapper);
+    pop();
   }
 
-  void _addRetained(EngineLayer retainedLayer) { throw UnimplementedError(); }
-
   /// Adds an object to the scene that displays performance statistics.
   ///
   /// Useful during development to assess the performance of the application.
@@ -677,12 +672,10 @@
     bool willChangeHint = false,
   }) {
     final int hints = (isComplexHint ? 1 : 0) | (willChangeHint ? 2 : 0);
-    _addPicture(offset.dx, offset.dy, picture, hints);
+    final _PictureLayer layer = _PictureLayer(offset.dx, offset.dy, picture, hints);
+    _pushLayer(layer);
   }
 
-  void _addPicture(double dx, double dy, Picture picture, int hints)
-      { throw UnimplementedError(); }
-
   /// Adds a backend texture to the scene.
   ///
   /// The texture is scaled to the given size and rasterized at the given offset.
@@ -797,15 +790,12 @@
   /// cannot be used further.
   Scene build() {
     final Scene scene = Scene._();
-    _build(scene);
     return scene;
   }
-
-  void _build(Scene outScene) { throw UnimplementedError(); }
 }
 
 /// (Fuchsia-only) Hosts content provided by another application.
-class SceneHost extends NativeFieldWrapperClass2 {
+class SceneHost {
   /// Creates a host for a child scene's content.
   ///
   /// The ViewHolder token is bound to a ViewHolder scene graph node which acts
diff --git a/lib/src/ui/geometry.dart b/lib/src/ui/geometry.dart
index 92545ec..81f5b7f 100644
--- a/lib/src/ui/geometry.dart
+++ b/lib/src/ui/geometry.dart
@@ -630,8 +630,7 @@
 /// ```
 class Rect {
   /// Construct a rectangle from its left, top, right, and bottom edges.
-  @pragma('vm:entry-point')
-  const Rect.fromLTRB(this.left, this.top, this.right, this.bottom)
+    const Rect.fromLTRB(this.left, this.top, this.right, this.bottom)
       : assert(left != null), // ignore: unnecessary_null_comparison
         assert(top != null), // ignore: unnecessary_null_comparison
         assert(right != null), // ignore: unnecessary_null_comparison
diff --git a/lib/src/ui/hooks.dart b/lib/src/ui/hooks.dart
index 0056145..eb7d29b 100644
--- a/lib/src/ui/hooks.dart
+++ b/lib/src/ui/hooks.dart
@@ -8,7 +8,6 @@
 
 part of dart.ui;
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _updateWindowMetrics(
   Object id,
@@ -50,71 +49,59 @@
 
 typedef _LocaleClosure = String Function();
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 _LocaleClosure? _getLocaleClosure() => PlatformDispatcher.instance._localeClosure;
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _updateLocales(List<String> locales) {
   PlatformDispatcher.instance._updateLocales(locales);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _updateUserSettingsData(String jsonData) {
   PlatformDispatcher.instance._updateUserSettingsData(jsonData);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _updateLifecycleState(String state) {
   PlatformDispatcher.instance._updateLifecycleState(state);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _updateSemanticsEnabled(bool enabled) {
   PlatformDispatcher.instance._updateSemanticsEnabled(enabled);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _updateAccessibilityFeatures(int values) {
   PlatformDispatcher.instance._updateAccessibilityFeatures(values);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _dispatchPlatformMessage(String name, ByteData? data, int responseId) {
   PlatformDispatcher.instance._dispatchPlatformMessage(name, data, responseId);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _dispatchPointerDataPacket(ByteData packet) {
   PlatformDispatcher.instance._dispatchPointerDataPacket(packet);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _dispatchSemanticsAction(int id, int action, ByteData? args) {
   PlatformDispatcher.instance._dispatchSemanticsAction(id, action, args);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _beginFrame(int microseconds) {
   PlatformDispatcher.instance._beginFrame(microseconds);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _reportTimings(List<int> timings) {
   PlatformDispatcher.instance._reportTimings(timings);
 }
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _drawFrame() {
   PlatformDispatcher.instance._drawFrame();
@@ -123,7 +110,6 @@
 // ignore: always_declare_return_types, prefer_generic_function_type_aliases
 typedef _ListStringArgFunction(List<String> args);
 
-@pragma('vm:entry-point')
 // ignore: unused_element
 void _runMainZoned(Function startMainIsolateFunction,
                    Function userMainFunction,
diff --git a/lib/src/ui/natives.dart b/lib/src/ui/natives.dart
index 65e02fe..f291cf9 100644
--- a/lib/src/ui/natives.dart
+++ b/lib/src/ui/natives.dart
@@ -41,7 +41,6 @@
   }));
 }
 
-@pragma('vm:entry-point')
 void _setupHooks() {  // ignore: unused_element
   assert(() {
     // In debug mode, register the schedule frame extension.
@@ -86,7 +85,5 @@
 // Required for gen_snapshot to work correctly.
 int? _isolateId; // ignore: unused_element
 
-@pragma('vm:entry-point')
 Function _getPrintClosure() => _print;  // ignore: unused_element
-@pragma('vm:entry-point')
 Function _getScheduleMicrotaskClosure() => _scheduleMicrotask; // ignore: unused_element
diff --git a/lib/src/ui/painting.dart b/lib/src/ui/painting.dart
index 3230a97..45d15a8 100644
--- a/lib/src/ui/painting.dart
+++ b/lib/src/ui/painting.dart
@@ -6,35 +6,6 @@
 
 part of dart.ui;
 
-// Some methods in this file assert that their arguments are not null. These
-// asserts are just to improve the error messages; they should only cover
-// arguments that are either dereferenced _in Dart_, before being passed to the
-// engine, or that the engine explicitly null-checks itself (after attempting to
-// convert the argument to a native type). It should not be possible for a null
-// or invalid value to be used by the engine even in release mode, since that
-// would cause a crash. It is, however, acceptable for error messages to be much
-// less useful or correct in release mode than in debug mode.
-//
-// Painting APIs will also warn about arguments representing NaN coordinates,
-// which can not be rendered by Skia.
-
-// Update this list when changing the list of supported codecs.
-/// {@template dart.ui.imageFormats}
-/// JPEG, PNG, GIF, Animated GIF, WebP, Animated WebP, BMP, and WBMP. Additional
-/// formats may be supported by the underlying platform. Flutter will
-/// attempt to call platform API to decode unrecognized formats, and if the
-/// platform API supports decoding the image Flutter will be able to render it.
-/// {@endtemplate}
-
-// TODO(gspencergoog): remove this template block once the framework templates
-// are renamed to not reference it.
-/// {@template flutter.dart:ui.imageFormats}
-/// JPEG, PNG, GIF, Animated GIF, WebP, Animated WebP, BMP, and WBMP. Additional
-/// formats may be supported by the underlying platform. Flutter will
-/// attempt to call platform API to decode unrecognized formats, and if the
-/// platform API supports decoding the image Flutter will be able to render it.
-/// {@endtemplate}
-
 bool _rectIsValid(Rect rect) {
   assert(rect != null, 'Rect argument was null.'); // ignore: unnecessary_null_comparison
   assert(!rect.hasNaN, 'Rect argument contained a NaN value.');
@@ -69,160 +40,37 @@
 Color _scaleAlpha(Color a, double factor) {
   return a.withAlpha((a.alpha * factor).round().clamp(0, 255));
 }
-
-/// An immutable 32 bit color value in ARGB format.
-///
-/// Consider the light teal of the Flutter logo. It is fully opaque, with a red
-/// channel value of 0x42 (66), a green channel value of 0xA5 (165), and a blue
-/// channel value of 0xF5 (245). In the common "hash syntax" for color values,
-/// it would be described as `#42A5F5`.
-///
-/// Here are some ways it could be constructed:
-///
-/// ```dart
-/// Color c = const Color(0xFF42A5F5);
-/// Color c = const Color.fromARGB(0xFF, 0x42, 0xA5, 0xF5);
-/// Color c = const Color.fromARGB(255, 66, 165, 245);
-/// Color c = const Color.fromRGBO(66, 165, 245, 1.0);
-/// ```
-///
-/// If you are having a problem with `Color` wherein it seems your color is just
-/// not painting, check to make sure you are specifying the full 8 hexadecimal
-/// digits. If you only specify six, then the leading two digits are assumed to
-/// be zero, which means fully-transparent:
-///
-/// ```dart
-/// Color c1 = const Color(0xFFFFFF); // fully transparent white (invisible)
-/// Color c2 = const Color(0xFFFFFFFF); // fully opaque white (visible)
-/// ```
-///
-/// See also:
-///
-///  * [Colors](https://docs.flutter.io/flutter/material/Colors-class.html), which
-///    defines the colors found in the Material Design specification.
 class Color {
-  /// Construct a color from the lower 32 bits of an [int].
-  ///
-  /// The bits are interpreted as follows:
-  ///
-  /// * Bits 24-31 are the alpha value.
-  /// * Bits 16-23 are the red value.
-  /// * Bits 8-15 are the green value.
-  /// * Bits 0-7 are the blue value.
-  ///
-  /// In other words, if AA is the alpha value in hex, RR the red value in hex,
-  /// GG the green value in hex, and BB the blue value in hex, a color can be
-  /// expressed as `const Color(0xAARRGGBB)`.
-  ///
-  /// For example, to get a fully opaque orange, you would use `const
-  /// Color(0xFFFF9000)` (`FF` for the alpha, `FF` for the red, `90` for the
-  /// green, and `00` for the blue).
-  @pragma('vm:entry-point')
-  const Color(int value) : value = value & 0xFFFFFFFF;
-
-  /// Construct a color from the lower 8 bits of four integers.
-  ///
-  /// * `a` is the alpha value, with 0 being transparent and 255 being fully
-  ///   opaque.
-  /// * `r` is [red], from 0 to 255.
-  /// * `g` is [green], from 0 to 255.
-  /// * `b` is [blue], from 0 to 255.
-  ///
-  /// Out of range values are brought into range using modulo 255.
-  ///
-  /// See also [fromRGBO], which takes the alpha value as a floating point
-  /// value.
+    const Color(int value) : value = value & 0xFFFFFFFF;
   const Color.fromARGB(int a, int r, int g, int b) :
     value = (((a & 0xff) << 24) |
              ((r & 0xff) << 16) |
              ((g & 0xff) << 8)  |
              ((b & 0xff) << 0)) & 0xFFFFFFFF;
-
-  /// Create a color from red, green, blue, and opacity, similar to `rgba()` in CSS.
-  ///
-  /// * `r` is [red], from 0 to 255.
-  /// * `g` is [green], from 0 to 255.
-  /// * `b` is [blue], from 0 to 255.
-  /// * `opacity` is alpha channel of this color as a double, with 0.0 being
-  ///   transparent and 1.0 being fully opaque.
-  ///
-  /// Out of range values are brought into range using modulo 255.
-  ///
-  /// See also [fromARGB], which takes the opacity as an integer value.
   const Color.fromRGBO(int r, int g, int b, double opacity) :
     value = ((((opacity * 0xff ~/ 1) & 0xff) << 24) |
               ((r                    & 0xff) << 16) |
               ((g                    & 0xff) << 8)  |
               ((b                    & 0xff) << 0)) & 0xFFFFFFFF;
-
-  /// A 32 bit value representing this color.
-  ///
-  /// The bits are assigned as follows:
-  ///
-  /// * Bits 24-31 are the alpha value.
-  /// * Bits 16-23 are the red value.
-  /// * Bits 8-15 are the green value.
-  /// * Bits 0-7 are the blue value.
   final int value;
-
-  /// The alpha channel of this color in an 8 bit value.
-  ///
-  /// A value of 0 means this color is fully transparent. A value of 255 means
-  /// this color is fully opaque.
   int get alpha => (0xff000000 & value) >> 24;
-
-  /// The alpha channel of this color as a double.
-  ///
-  /// A value of 0.0 means this color is fully transparent. A value of 1.0 means
-  /// this color is fully opaque.
   double get opacity => alpha / 0xFF;
-
-  /// The red channel of this color in an 8 bit value.
   int get red => (0x00ff0000 & value) >> 16;
-
-  /// The green channel of this color in an 8 bit value.
   int get green => (0x0000ff00 & value) >> 8;
-
-  /// The blue channel of this color in an 8 bit value.
   int get blue => (0x000000ff & value) >> 0;
-
-  /// Returns a new color that matches this color with the alpha channel
-  /// replaced with `a` (which ranges from 0 to 255).
-  ///
-  /// Out of range values will have unexpected effects.
   Color withAlpha(int a) {
     return Color.fromARGB(a, red, green, blue);
   }
-
-  /// Returns a new color that matches this color with the alpha channel
-  /// replaced with the given `opacity` (which ranges from 0.0 to 1.0).
-  ///
-  /// Out of range values will have unexpected effects.
   Color withOpacity(double opacity) {
     assert(opacity >= 0.0 && opacity <= 1.0);
     return withAlpha((255.0 * opacity).round());
   }
-
-  /// Returns a new color that matches this color with the red channel replaced
-  /// with `r` (which ranges from 0 to 255).
-  ///
-  /// Out of range values will have unexpected effects.
   Color withRed(int r) {
     return Color.fromARGB(alpha, r, green, blue);
   }
-
-  /// Returns a new color that matches this color with the green channel
-  /// replaced with `g` (which ranges from 0 to 255).
-  ///
-  /// Out of range values will have unexpected effects.
   Color withGreen(int g) {
     return Color.fromARGB(alpha, red, g, blue);
   }
-
-  /// Returns a new color that matches this color with the blue channel replaced
-  /// with `b` (which ranges from 0 to 255).
-  ///
-  /// Out of range values will have unexpected effects.
   Color withBlue(int b) {
     return Color.fromARGB(alpha, red, green, b);
   }
@@ -233,13 +81,6 @@
       return component / 12.92;
     return math.pow((component + 0.055) / 1.055, 2.4) as double;
   }
-
-  /// Returns a brightness value between 0 for darkest and 1 for lightest.
-  ///
-  /// Represents the relative luminance of the color. This value is computationally
-  /// expensive to calculate.
-  ///
-  /// See <https://en.wikipedia.org/wiki/Relative_luminance>.
   double computeLuminance() {
     // See <https://www.w3.org/TR/WCAG20/#relativeluminancedef>
     final double R = _linearizeColorComponent(red / 0xFF);
@@ -247,29 +88,6 @@
     final double B = _linearizeColorComponent(blue / 0xFF);
     return 0.2126 * R + 0.7152 * G + 0.0722 * B;
   }
-
-  /// Linearly interpolate between two colors.
-  ///
-  /// This is intended to be fast but as a result may be ugly. Consider
-  /// [HSVColor] or writing custom logic for interpolating colors.
-  ///
-  /// If either color is null, this function linearly interpolates from a
-  /// transparent instance of the other color. This is usually preferable to
-  /// interpolating from [material.Colors.transparent] (`const
-  /// Color(0x00000000)`), which is specifically transparent _black_.
-  ///
-  /// The `t` argument represents position on the timeline, with 0.0 meaning
-  /// that the interpolation has not started, returning `a` (or something
-  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
-  /// returning `b` (or something equivalent to `b`), and values in between
-  /// meaning that the interpolation is at the relevant point on the timeline
-  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
-  /// 1.0, so negative values and values greater than 1.0 are valid (and can
-  /// easily be generated by curves such as [Curves.elasticInOut]). Each channel
-  /// will be clamped to the range 0 to 255.
-  ///
-  /// Values for `t` are usually obtained from an [Animation<double>], such as
-  /// an [AnimationController].
   static Color? lerp(Color? a, Color? b, double t) {
     assert(t != null); // ignore: unnecessary_null_comparison
     if (b == null) {
@@ -291,15 +109,6 @@
       }
     }
   }
-
-  /// Combine the foreground color as a transparent color over top
-  /// of a background color, and return the resulting combined color.
-  ///
-  /// This uses standard alpha blending ("SRC over DST") rules to produce a
-  /// blended color from two colors. This can be used as a performance
-  /// enhancement when trying to avoid needless alpha blending compositing
-  /// operations for two things that are solid colors with the same shape, but
-  /// overlay each other: instead, just paint one with the combined color.
   static Color alphaBlend(Color foreground, Color background) {
     final int alpha = foreground.alpha;
     if (alpha == 0x00) { // Foreground completely transparent.
@@ -326,10 +135,6 @@
       );
     }
   }
-
-  /// Returns an alpha value representative of the provided [opacity] value.
-  ///
-  /// The [opacity] value may not be null.
   static int getAlphaFromOpacity(double opacity) {
     assert(opacity != null); // ignore: unnecessary_null_comparison
     return (opacity.clamp(0.0, 1.0) * 255).round();
@@ -351,706 +156,75 @@
   @override
   String toString() => 'Color(0x${value.toRadixString(16).padLeft(8, '0')})';
 }
-
-/// Algorithms to use when painting on the canvas.
-///
-/// When drawing a shape or image onto a canvas, different algorithms can be
-/// used to blend the pixels. The different values of [BlendMode] specify
-/// different such algorithms.
-///
-/// Each algorithm has two inputs, the _source_, which is the image being drawn,
-/// and the _destination_, which is the image into which the source image is
-/// being composited. The destination is often thought of as the _background_.
-/// The source and destination both have four color channels, the red, green,
-/// blue, and alpha channels. These are typically represented as numbers in the
-/// range 0.0 to 1.0. The output of the algorithm also has these same four
-/// channels, with values computed from the source and destination.
-///
-/// The documentation of each value below describes how the algorithm works. In
-/// each case, an image shows the output of blending a source image with a
-/// destination image. In the images below, the destination is represented by an
-/// image with horizontal lines and an opaque landscape photograph, and the
-/// source is represented by an image with vertical lines (the same lines but
-/// rotated) and a bird clip-art image. The [src] mode shows only the source
-/// image, and the [dst] mode shows only the destination image. In the
-/// documentation below, the transparency is illustrated by a checkerboard
-/// pattern. The [clear] mode drops both the source and destination, resulting
-/// in an output that is entirely transparent (illustrated by a solid
-/// checkerboard pattern).
-///
-/// The horizontal and vertical bars in these images show the red, green, and
-/// blue channels with varying opacity levels, then all three color channels
-/// together with those same varying opacity levels, then all three color
-/// channels set to zero with those varying opacity levels, then two bars showing
-/// a red/green/blue repeating gradient, the first with full opacity and the
-/// second with partial opacity, and finally a bar with the three color channels
-/// set to zero but the opacity varying in a repeating gradient.
-///
-/// ## Application to the [Canvas] API
-///
-/// When using [Canvas.saveLayer] and [Canvas.restore], the blend mode of the
-/// [Paint] given to the [Canvas.saveLayer] will be applied when
-/// [Canvas.restore] is called. Each call to [Canvas.saveLayer] introduces a new
-/// layer onto which shapes and images are painted; when [Canvas.restore] is
-/// called, that layer is then composited onto the parent layer, with the source
-/// being the most-recently-drawn shapes and images, and the destination being
-/// the parent layer. (For the first [Canvas.saveLayer] call, the parent layer
-/// is the canvas itself.)
-///
-/// See also:
-///
-///  * [Paint.blendMode], which uses [BlendMode] to define the compositing
-///    strategy.
 enum BlendMode {
   // This list comes from Skia's SkXfermode.h and the values (order) should be
   // kept in sync.
   // See: https://skia.org/user/api/skpaint#SkXfermode
-
-  /// Drop both the source and destination images, leaving nothing.
-  ///
-  /// This corresponds to the "clear" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_clear.png)
   clear,
-
-  /// Drop the destination image, only paint the source image.
-  ///
-  /// Conceptually, the destination is first cleared, then the source image is
-  /// painted.
-  ///
-  /// This corresponds to the "Copy" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_src.png)
   src,
-
-  /// Drop the source image, only paint the destination image.
-  ///
-  /// Conceptually, the source image is discarded, leaving the destination
-  /// untouched.
-  ///
-  /// This corresponds to the "Destination" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dst.png)
   dst,
-
-  /// Composite the source image over the destination image.
-  ///
-  /// This is the default value. It represents the most intuitive case, where
-  /// shapes are painted on top of what is below, with transparent areas showing
-  /// the destination layer.
-  ///
-  /// This corresponds to the "Source over Destination" Porter-Duff operator,
-  /// also known as the Painter's Algorithm.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_srcOver.png)
   srcOver,
-
-  /// Composite the source image under the destination image.
-  ///
-  /// This is the opposite of [srcOver].
-  ///
-  /// This corresponds to the "Destination over Source" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dstOver.png)
-  ///
-  /// This is useful when the source image should have been painted before the
-  /// destination image, but could not be.
   dstOver,
-
-  /// Show the source image, but only where the two images overlap. The
-  /// destination image is not rendered, it is treated merely as a mask. The
-  /// color channels of the destination are ignored, only the opacity has an
-  /// effect.
-  ///
-  /// To show the destination image instead, consider [dstIn].
-  ///
-  /// To reverse the semantic of the mask (only showing the source where the
-  /// destination is absent, rather than where it is present), consider
-  /// [srcOut].
-  ///
-  /// This corresponds to the "Source in Destination" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_srcIn.png)
   srcIn,
-
-  /// Show the destination image, but only where the two images overlap. The
-  /// source image is not rendered, it is treated merely as a mask. The color
-  /// channels of the source are ignored, only the opacity has an effect.
-  ///
-  /// To show the source image instead, consider [srcIn].
-  ///
-  /// To reverse the semantic of the mask (only showing the source where the
-  /// destination is present, rather than where it is absent), consider [dstOut].
-  ///
-  /// This corresponds to the "Destination in Source" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dstIn.png)
   dstIn,
-
-  /// Show the source image, but only where the two images do not overlap. The
-  /// destination image is not rendered, it is treated merely as a mask. The color
-  /// channels of the destination are ignored, only the opacity has an effect.
-  ///
-  /// To show the destination image instead, consider [dstOut].
-  ///
-  /// To reverse the semantic of the mask (only showing the source where the
-  /// destination is present, rather than where it is absent), consider [srcIn].
-  ///
-  /// This corresponds to the "Source out Destination" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_srcOut.png)
   srcOut,
-
-  /// Show the destination image, but only where the two images do not overlap. The
-  /// source image is not rendered, it is treated merely as a mask. The color
-  /// channels of the source are ignored, only the opacity has an effect.
-  ///
-  /// To show the source image instead, consider [srcOut].
-  ///
-  /// To reverse the semantic of the mask (only showing the destination where the
-  /// source is present, rather than where it is absent), consider [dstIn].
-  ///
-  /// This corresponds to the "Destination out Source" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dstOut.png)
   dstOut,
-
-  /// Composite the source image over the destination image, but only where it
-  /// overlaps the destination.
-  ///
-  /// This corresponds to the "Source atop Destination" Porter-Duff operator.
-  ///
-  /// This is essentially the [srcOver] operator, but with the output's opacity
-  /// channel being set to that of the destination image instead of being a
-  /// combination of both image's opacity channels.
-  ///
-  /// For a variant with the destination on top instead of the source, see
-  /// [dstATop].
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_srcATop.png)
   srcATop,
-
-  /// Composite the destination image over the source image, but only where it
-  /// overlaps the source.
-  ///
-  /// This corresponds to the "Destination atop Source" Porter-Duff operator.
-  ///
-  /// This is essentially the [dstOver] operator, but with the output's opacity
-  /// channel being set to that of the source image instead of being a
-  /// combination of both image's opacity channels.
-  ///
-  /// For a variant with the source on top instead of the destination, see
-  /// [srcATop].
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dstATop.png)
   dstATop,
-
-  /// Apply a bitwise `xor` operator to the source and destination images. This
-  /// leaves transparency where they would overlap.
-  ///
-  /// This corresponds to the "Source xor Destination" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_xor.png)
   xor,
-
-  /// Sum the components of the source and destination images.
-  ///
-  /// Transparency in a pixel of one of the images reduces the contribution of
-  /// that image to the corresponding output pixel, as if the color of that
-  /// pixel in that image was darker.
-  ///
-  /// This corresponds to the "Source plus Destination" Porter-Duff operator.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_plus.png)
   plus,
-
-  /// Multiply the color components of the source and destination images.
-  ///
-  /// This can only result in the same or darker colors (multiplying by white,
-  /// 1.0, results in no change; multiplying by black, 0.0, results in black).
-  ///
-  /// When compositing two opaque images, this has similar effect to overlapping
-  /// two transparencies on a projector.
-  ///
-  /// For a variant that also multiplies the alpha channel, consider [multiply].
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_modulate.png)
-  ///
-  /// See also:
-  ///
-  ///  * [screen], which does a similar computation but inverted.
-  ///  * [overlay], which combines [modulate] and [screen] to favor the
-  ///    destination image.
-  ///  * [hardLight], which combines [modulate] and [screen] to favor the
-  ///    source image.
   modulate,
 
   // Following blend modes are defined in the CSS Compositing standard.
-
-  /// Multiply the inverse of the components of the source and destination
-  /// images, and inverse the result.
-  ///
-  /// Inverting the components means that a fully saturated channel (opaque
-  /// white) is treated as the value 0.0, and values normally treated as 0.0
-  /// (black, transparent) are treated as 1.0.
-  ///
-  /// This is essentially the same as [modulate] blend mode, but with the values
-  /// of the colors inverted before the multiplication and the result being
-  /// inverted back before rendering.
-  ///
-  /// This can only result in the same or lighter colors (multiplying by black,
-  /// 1.0, results in no change; multiplying by white, 0.0, results in white).
-  /// Similarly, in the alpha channel, it can only result in more opaque colors.
-  ///
-  /// This has similar effect to two projectors displaying their images on the
-  /// same screen simultaneously.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_screen.png)
-  ///
-  /// See also:
-  ///
-  ///  * [modulate], which does a similar computation but without inverting the
-  ///    values.
-  ///  * [overlay], which combines [modulate] and [screen] to favor the
-  ///    destination image.
-  ///  * [hardLight], which combines [modulate] and [screen] to favor the
-  ///    source image.
   screen,  // The last coeff mode.
-
-  /// Multiply the components of the source and destination images after
-  /// adjusting them to favor the destination.
-  ///
-  /// Specifically, if the destination value is smaller, this multiplies it with
-  /// the source value, whereas is the source value is smaller, it multiplies
-  /// the inverse of the source value with the inverse of the destination value,
-  /// then inverts the result.
-  ///
-  /// Inverting the components means that a fully saturated channel (opaque
-  /// white) is treated as the value 0.0, and values normally treated as 0.0
-  /// (black, transparent) are treated as 1.0.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_overlay.png)
-  ///
-  /// See also:
-  ///
-  ///  * [modulate], which always multiplies the values.
-  ///  * [screen], which always multiplies the inverses of the values.
-  ///  * [hardLight], which is similar to [overlay] but favors the source image
-  ///    instead of the destination image.
   overlay,
-
-  /// Composite the source and destination image by choosing the lowest value
-  /// from each color channel.
-  ///
-  /// The opacity of the output image is computed in the same way as for
-  /// [srcOver].
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_darken.png)
   darken,
-
-  /// Composite the source and destination image by choosing the highest value
-  /// from each color channel.
-  ///
-  /// The opacity of the output image is computed in the same way as for
-  /// [srcOver].
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_lighten.png)
   lighten,
-
-  /// Divide the destination by the inverse of the source.
-  ///
-  /// Inverting the components means that a fully saturated channel (opaque
-  /// white) is treated as the value 0.0, and values normally treated as 0.0
-  /// (black, transparent) are treated as 1.0.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_colorDodge.png)
   colorDodge,
-
-  /// Divide the inverse of the destination by the source, and inverse the result.
-  ///
-  /// Inverting the components means that a fully saturated channel (opaque
-  /// white) is treated as the value 0.0, and values normally treated as 0.0
-  /// (black, transparent) are treated as 1.0.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_colorBurn.png)
   colorBurn,
-
-  /// Multiply the components of the source and destination images after
-  /// adjusting them to favor the source.
-  ///
-  /// Specifically, if the source value is smaller, this multiplies it with the
-  /// destination value, whereas is the destination value is smaller, it
-  /// multiplies the inverse of the destination value with the inverse of the
-  /// source value, then inverts the result.
-  ///
-  /// Inverting the components means that a fully saturated channel (opaque
-  /// white) is treated as the value 0.0, and values normally treated as 0.0
-  /// (black, transparent) are treated as 1.0.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_hardLight.png)
-  ///
-  /// See also:
-  ///
-  ///  * [modulate], which always multiplies the values.
-  ///  * [screen], which always multiplies the inverses of the values.
-  ///  * [overlay], which is similar to [hardLight] but favors the destination
-  ///    image instead of the source image.
   hardLight,
-
-  /// Use [colorDodge] for source values below 0.5 and [colorBurn] for source
-  /// values above 0.5.
-  ///
-  /// This results in a similar but softer effect than [overlay].
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_softLight.png)
-  ///
-  /// See also:
-  ///
-  ///  * [color], which is a more subtle tinting effect.
   softLight,
-
-  /// Subtract the smaller value from the bigger value for each channel.
-  ///
-  /// Compositing black has no effect; compositing white inverts the colors of
-  /// the other image.
-  ///
-  /// The opacity of the output image is computed in the same way as for
-  /// [srcOver].
-  ///
-  /// The effect is similar to [exclusion] but harsher.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_difference.png)
   difference,
-
-  /// Subtract double the product of the two images from the sum of the two
-  /// images.
-  ///
-  /// Compositing black has no effect; compositing white inverts the colors of
-  /// the other image.
-  ///
-  /// The opacity of the output image is computed in the same way as for
-  /// [srcOver].
-  ///
-  /// The effect is similar to [difference] but softer.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_exclusion.png)
   exclusion,
-
-  /// Multiply the components of the source and destination images, including
-  /// the alpha channel.
-  ///
-  /// This can only result in the same or darker colors (multiplying by white,
-  /// 1.0, results in no change; multiplying by black, 0.0, results in black).
-  ///
-  /// Since the alpha channel is also multiplied, a fully-transparent pixel
-  /// (opacity 0.0) in one image results in a fully transparent pixel in the
-  /// output. This is similar to [dstIn], but with the colors combined.
-  ///
-  /// For a variant that multiplies the colors but does not multiply the alpha
-  /// channel, consider [modulate].
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_multiply.png)
   multiply,  // The last separable mode.
-
-  /// Take the hue of the source image, and the saturation and luminosity of the
-  /// destination image.
-  ///
-  /// The effect is to tint the destination image with the source image.
-  ///
-  /// The opacity of the output image is computed in the same way as for
-  /// [srcOver]. Regions that are entirely transparent in the source image take
-  /// their hue from the destination.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_hue.png)
-  ///
-  /// See also:
-  ///
-  ///  * [color], which is a similar but stronger effect as it also applies the
-  ///    saturation of the source image.
-  ///  * [HSVColor], which allows colors to be expressed using Hue rather than
-  ///    the red/green/blue channels of [Color].
   hue,
-
-  /// Take the saturation of the source image, and the hue and luminosity of the
-  /// destination image.
-  ///
-  /// The opacity of the output image is computed in the same way as for
-  /// [srcOver]. Regions that are entirely transparent in the source image take
-  /// their saturation from the destination.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_hue.png)
-  ///
-  /// See also:
-  ///
-  ///  * [color], which also applies the hue of the source image.
-  ///  * [luminosity], which applies the luminosity of the source image to the
-  ///    destination.
   saturation,
-
-  /// Take the hue and saturation of the source image, and the luminosity of the
-  /// destination image.
-  ///
-  /// The effect is to tint the destination image with the source image.
-  ///
-  /// The opacity of the output image is computed in the same way as for
-  /// [srcOver]. Regions that are entirely transparent in the source image take
-  /// their hue and saturation from the destination.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_color.png)
-  ///
-  /// See also:
-  ///
-  ///  * [hue], which is a similar but weaker effect.
-  ///  * [softLight], which is a similar tinting effect but also tints white.
-  ///  * [saturation], which only applies the saturation of the source image.
   color,
-
-  /// Take the luminosity of the source image, and the hue and saturation of the
-  /// destination image.
-  ///
-  /// The opacity of the output image is computed in the same way as for
-  /// [srcOver]. Regions that are entirely transparent in the source image take
-  /// their luminosity from the destination.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_luminosity.png)
-  ///
-  /// See also:
-  ///
-  ///  * [saturation], which applies the saturation of the source image to the
-  ///    destination.
-  ///  * [ImageFilter.blur], which can be used with [BackdropFilter] for a
-  ///    related effect.
   luminosity,
 }
-
-/// Quality levels for image filters.
-///
-/// See [Paint.filterQuality].
 enum FilterQuality {
   // This list comes from Skia's SkFilterQuality.h and the values (order) should
   // be kept in sync.
-
-  /// Fastest possible filtering, albeit also the lowest quality.
-  ///
-  /// Typically this implies nearest-neighbor filtering.
   none,
-
-  /// Better quality than [none], faster than [medium].
-  ///
-  /// Typically this implies bilinear interpolation.
   low,
-
-  /// Better quality than [low], faster than [high].
-  ///
-  /// Typically this implies a combination of bilinear interpolation and
-  /// pyramidal parametric pre-filtering (mipmaps).
   medium,
-
-  /// Best possible quality filtering, albeit also the slowest.
-  ///
-  /// Typically this implies bicubic interpolation or better.
   high,
 }
-
-/// Styles to use for line endings.
-///
-/// See also:
-///
-///  * [Paint.strokeCap] for how this value is used.
-///  * [StrokeJoin] for the different kinds of line segment joins.
 // These enum values must be kept in sync with SkPaint::Cap.
 enum StrokeCap {
-  /// Begin and end contours with a flat edge and no extension.
-  ///
-  /// ![A butt cap ends line segments with a square end that stops at the end of
-  /// the line segment.](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/butt_cap.png)
-  ///
-  /// Compare to the [square] cap, which has the same shape, but extends past
-  /// the end of the line by half a stroke width.
   butt,
-
-  /// Begin and end contours with a semi-circle extension.
-  ///
-  /// ![A round cap adds a rounded end to the line segment that protrudes
-  /// by one half of the thickness of the line (which is the radius of the cap)
-  /// past the end of the segment.](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/round_cap.png)
-  ///
-  /// The cap is colored in the diagram above to highlight it: in normal use it
-  /// is the same color as the line.
   round,
-
-  /// Begin and end contours with a half square extension. This is
-  /// similar to extending each contour by half the stroke width (as
-  /// given by [Paint.strokeWidth]).
-  ///
-  /// ![A square cap has a square end that effectively extends the line length
-  /// by half of the stroke width.](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/square_cap.png)
-  ///
-  /// The cap is colored in the diagram above to highlight it: in normal use it
-  /// is the same color as the line.
-  ///
-  /// Compare to the [butt] cap, which has the same shape, but doesn't extend
-  /// past the end of the line.
   square,
 }
-
-/// Styles to use for line segment joins.
-///
-/// This only affects line joins for polygons drawn by [Canvas.drawPath] and
-/// rectangles, not points drawn as lines with [Canvas.drawPoints].
-///
-/// See also:
-///
-/// * [Paint.strokeJoin] and [Paint.strokeMiterLimit] for how this value is
-///   used.
-/// * [StrokeCap] for the different kinds of line endings.
 // These enum values must be kept in sync with SkPaint::Join.
 enum StrokeJoin {
-  /// Joins between line segments form sharp corners.
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4}
-  ///
-  /// The center of the line segment is colored in the diagram above to
-  /// highlight the join, but in normal usage the join is the same color as the
-  /// line.
-  ///
-  /// See also:
-  ///
-  ///   * [Paint.strokeJoin], used to set the line segment join style to this
-  ///     value.
-  ///   * [Paint.strokeMiterLimit], used to define when a miter is drawn instead
-  ///     of a bevel when the join is set to this value.
   miter,
-
-  /// Joins between line segments are semi-circular.
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/round_join.mp4}
-  ///
-  /// The center of the line segment is colored in the diagram above to
-  /// highlight the join, but in normal usage the join is the same color as the
-  /// line.
-  ///
-  /// See also:
-  ///
-  ///   * [Paint.strokeJoin], used to set the line segment join style to this
-  ///     value.
   round,
-
-  /// Joins between line segments connect the corners of the butt ends of the
-  /// line segments to give a beveled appearance.
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/bevel_join.mp4}
-  ///
-  /// The center of the line segment is colored in the diagram above to
-  /// highlight the join, but in normal usage the join is the same color as the
-  /// line.
-  ///
-  /// See also:
-  ///
-  ///   * [Paint.strokeJoin], used to set the line segment join style to this
-  ///     value.
   bevel,
 }
-
-/// Strategies for painting shapes and paths on a canvas.
-///
-/// See [Paint.style].
 // These enum values must be kept in sync with SkPaint::Style.
 enum PaintingStyle {
   // This list comes from Skia's SkPaint.h and the values (order) should be kept
   // in sync.
-
-  /// Apply the [Paint] to the inside of the shape. For example, when
-  /// applied to the [Canvas.drawCircle] call, this results in a disc
-  /// of the given size being painted.
   fill,
-
-  /// Apply the [Paint] to the edge of the shape. For example, when
-  /// applied to the [Canvas.drawCircle] call, this results is a hoop
-  /// of the given size being painted. The line drawn on the edge will
-  /// be the width given by the [Paint.strokeWidth] property.
   stroke,
 }
-
-
-/// Different ways to clip a widget's content.
 enum Clip {
-  /// No clip at all.
-  ///
-  /// This is the default option for most widgets: if the content does not
-  /// overflow the widget boundary, don't pay any performance cost for clipping.
-  ///
-  /// If the content does overflow, please explicitly specify the following
-  /// [Clip] options:
-  ///  * [hardEdge], which is the fastest clipping, but with lower fidelity.
-  ///  * [antiAlias], which is a little slower than [hardEdge], but with smoothed edges.
-  ///  * [antiAliasWithSaveLayer], which is much slower than [antiAlias], and should
-  ///    rarely be used.
   none,
-
-  /// Clip, but do not apply anti-aliasing.
-  ///
-  /// This mode enables clipping, but curves and non-axis-aligned straight lines will be
-  /// jagged as no effort is made to anti-alias.
-  ///
-  /// Faster than other clipping modes, but slower than [none].
-  ///
-  /// This is a reasonable choice when clipping is needed, if the container is an axis-
-  /// aligned rectangle or an axis-aligned rounded rectangle with very small corner radii.
-  ///
-  /// See also:
-  ///
-  ///  * [antiAlias], which is more reasonable when clipping is needed and the shape is not
-  ///    an axis-aligned rectangle.
   hardEdge,
-
-  /// Clip with anti-aliasing.
-  ///
-  /// This mode has anti-aliased clipping edges to achieve a smoother look.
-  ///
-  /// It' s much faster than [antiAliasWithSaveLayer], but slower than [hardEdge].
-  ///
-  /// This will be the common case when dealing with circles and arcs.
-  ///
-  /// Different from [hardEdge] and [antiAliasWithSaveLayer], this clipping may have
-  /// bleeding edge artifacts.
-  /// (See https://fiddle.skia.org/c/21cb4c2b2515996b537f36e7819288ae for an example.)
-  ///
-  /// See also:
-  ///
-  ///  * [hardEdge], which is a little faster, but with lower fidelity.
-  ///  * [antiAliasWithSaveLayer], which is much slower, but can avoid the
-  ///    bleeding edges if there's no other way.
-  ///  * [Paint.isAntiAlias], which is the anti-aliasing switch for general draw operations.
   antiAlias,
-
-  /// Clip with anti-aliasing and saveLayer immediately following the clip.
-  ///
-  /// This mode not only clips with anti-aliasing, but also allocates an offscreen
-  /// buffer. All subsequent paints are carried out on that buffer before finally
-  /// being clipped and composited back.
-  ///
-  /// This is very slow. It has no bleeding edge artifacts (that [antiAlias] has)
-  /// but it changes the semantics as an offscreen buffer is now introduced.
-  /// (See https://github.com/flutter/flutter/issues/18057#issuecomment-394197336
-  /// for a difference between paint without saveLayer and paint with saveLayer.)
-  ///
-  /// This will be only rarely needed. One case where you might need this is if
-  /// you have an image overlaid on a very different background color. In these
-  /// cases, consider whether you can avoid overlaying multiple colors in one
-  /// spot (e.g. by having the background color only present where the image is
-  /// absent). If you can, [antiAlias] would be fine and much faster.
-  ///
-  /// See also:
-  ///
-  ///  * [antiAlias], which is much faster, and has similar clipping results.
   antiAliasWithSaveLayer,
 }
-
-/// A description of the style to use when drawing on a [Canvas].
-///
-/// Most APIs on [Canvas] take a [Paint] object to describe the style
-/// to use for that operation.
 class Paint {
   // Paint objects are encoded in two buffers:
   //
@@ -1110,19 +284,11 @@
   static const int _kColorFilterIndex = 1;
   static const int _kImageFilterIndex = 2;
   static const int _kObjectCount = 3; // Must be one larger than the largest index.
-
-  /// Constructs an empty [Paint] object with all fields initialized to
-  /// their defaults.
   Paint() {
     if (enableDithering) {
       _dither = true;
     }
   }
-
-  /// Whether to apply anti-aliasing to lines and images drawn on the
-  /// canvas.
-  ///
-  /// Defaults to true.
   bool get isAntiAlias {
     return _data.getInt32(_kIsAntiAliasOffset, _kFakeHostEndian) == 0;
   }
@@ -1135,19 +301,6 @@
 
   // Must be kept in sync with the default in paint.cc.
   static const int _kColorDefault = 0xFF000000;
-
-  /// The color to use when stroking or filling a shape.
-  ///
-  /// Defaults to opaque black.
-  ///
-  /// See also:
-  ///
-  ///  * [style], which controls whether to stroke or fill (or both).
-  ///  * [colorFilter], which overrides [color].
-  ///  * [shader], which overrides [color] with more elaborate effects.
-  ///
-  /// This color is not used when compositing. To colorize a layer, use
-  /// [colorFilter].
   Color get color {
     final int encoded = _data.getInt32(_kColorOffset, _kFakeHostEndian);
     return Color(encoded ^ _kColorDefault);
@@ -1160,25 +313,6 @@
 
   // Must be kept in sync with the default in paint.cc.
   static final int _kBlendModeDefault = BlendMode.srcOver.index;
-
-  /// A blend mode to apply when a shape is drawn or a layer is composited.
-  ///
-  /// The source colors are from the shape being drawn (e.g. from
-  /// [Canvas.drawPath]) or layer being composited (the graphics that were drawn
-  /// between the [Canvas.saveLayer] and [Canvas.restore] calls), after applying
-  /// the [colorFilter], if any.
-  ///
-  /// The destination colors are from the background onto which the shape or
-  /// layer is being composited.
-  ///
-  /// Defaults to [BlendMode.srcOver].
-  ///
-  /// See also:
-  ///
-  ///  * [Canvas.saveLayer], which uses its [Paint]'s [blendMode] to composite
-  ///    the layer when [Canvas.restore] is called.
-  ///  * [BlendMode], which discusses the user of [Canvas.saveLayer] with
-  ///    [blendMode].
   BlendMode get blendMode {
     final int encoded = _data.getInt32(_kBlendModeOffset, _kFakeHostEndian);
     return BlendMode.values[encoded ^ _kBlendModeDefault];
@@ -1188,10 +322,6 @@
     final int encoded = value.index ^ _kBlendModeDefault;
     _data.setInt32(_kBlendModeOffset, encoded, _kFakeHostEndian);
   }
-
-  /// Whether to paint inside shapes, the edges of shapes, or both.
-  ///
-  /// Defaults to [PaintingStyle.fill].
   PaintingStyle get style {
     return PaintingStyle.values[_data.getInt32(_kStyleOffset, _kFakeHostEndian)];
   }
@@ -1200,12 +330,6 @@
     final int encoded = value.index;
     _data.setInt32(_kStyleOffset, encoded, _kFakeHostEndian);
   }
-
-  /// How wide to make edges drawn when [style] is set to
-  /// [PaintingStyle.stroke]. The width is given in logical pixels measured in
-  /// the direction orthogonal to the direction of the path.
-  ///
-  /// Defaults to 0.0, which correspond to a hairline width.
   double get strokeWidth {
     return _data.getFloat32(_kStrokeWidthOffset, _kFakeHostEndian);
   }
@@ -1214,11 +338,6 @@
     final double encoded = value;
     _data.setFloat32(_kStrokeWidthOffset, encoded, _kFakeHostEndian);
   }
-
-  /// The kind of finish to place on the end of lines drawn when
-  /// [style] is set to [PaintingStyle.stroke].
-  ///
-  /// Defaults to [StrokeCap.butt], i.e. no caps.
   StrokeCap get strokeCap {
     return StrokeCap.values[_data.getInt32(_kStrokeCapOffset, _kFakeHostEndian)];
   }
@@ -1227,32 +346,6 @@
     final int encoded = value.index;
     _data.setInt32(_kStrokeCapOffset, encoded, _kFakeHostEndian);
   }
-
-  /// The kind of finish to place on the joins between segments.
-  ///
-  /// This applies to paths drawn when [style] is set to [PaintingStyle.stroke],
-  /// It does not apply to points drawn as lines with [Canvas.drawPoints].
-  ///
-  /// Defaults to [StrokeJoin.miter], i.e. sharp corners.
-  ///
-  /// Some examples of joins:
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4}
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/round_join.mp4}
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/bevel_join.mp4}
-  ///
-  /// The centers of the line segments are colored in the diagrams above to
-  /// highlight the joins, but in normal usage the join is the same color as the
-  /// line.
-  ///
-  /// See also:
-  ///
-  ///  * [strokeMiterLimit] to control when miters are replaced by bevels when
-  ///    this is set to [StrokeJoin.miter].
-  ///  * [strokeCap] to control what is drawn at the ends of the stroke.
-  ///  * [StrokeJoin] for the definitive list of stroke joins.
   StrokeJoin get strokeJoin {
     return StrokeJoin.values[_data.getInt32(_kStrokeJoinOffset, _kFakeHostEndian)];
   }
@@ -1264,33 +357,6 @@
 
   // Must be kept in sync with the default in paint.cc.
   static const double _kStrokeMiterLimitDefault = 4.0;
-
-  /// The limit for miters to be drawn on segments when the join is set to
-  /// [StrokeJoin.miter] and the [style] is set to [PaintingStyle.stroke]. If
-  /// this limit is exceeded, then a [StrokeJoin.bevel] join will be drawn
-  /// instead. This may cause some 'popping' of the corners of a path if the
-  /// angle between line segments is animated, as seen in the diagrams below.
-  ///
-  /// This limit is expressed as a limit on the length of the miter.
-  ///
-  /// Defaults to 4.0.  Using zero as a limit will cause a [StrokeJoin.bevel]
-  /// join to be used all the time.
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_0_join.mp4}
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4}
-  ///
-  /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_6_join.mp4}
-  ///
-  /// The centers of the line segments are colored in the diagrams above to
-  /// highlight the joins, but in normal usage the join is the same color as the
-  /// line.
-  ///
-  /// See also:
-  ///
-  ///  * [strokeJoin] to control the kind of finish to place on the joins
-  ///    between segments.
-  ///  * [strokeCap] to control what is drawn at the ends of the stroke.
   double get strokeMiterLimit {
     return _data.getFloat32(_kStrokeMiterLimitOffset, _kFakeHostEndian);
   }
@@ -1299,11 +365,6 @@
     final double encoded = value - _kStrokeMiterLimitDefault;
     _data.setFloat32(_kStrokeMiterLimitOffset, encoded, _kFakeHostEndian);
   }
-
-  /// A mask filter (for example, a blur) to apply to a shape after it has been
-  /// drawn but before it has been composited into the image.
-  ///
-  /// See [MaskFilter] for details.
   MaskFilter? get maskFilter {
     switch (_data.getInt32(_kMaskFilterOffset, _kFakeHostEndian)) {
       case MaskFilter._TypeNone:
@@ -1329,12 +390,6 @@
       _data.setFloat32(_kMaskFilterSigmaOffset, value._sigma, _kFakeHostEndian);
     }
   }
-
-  /// Controls the performance vs quality trade-off to use when applying
-  /// filters, such as [maskFilter], or when drawing images, as with
-  /// [Canvas.drawImageRect] or [Canvas.drawImageNine].
-  ///
-  /// Defaults to [FilterQuality.none].
   // TODO(ianh): verify that the image drawing methods actually respect this
   FilterQuality get filterQuality {
     return FilterQuality.values[_data.getInt32(_kFilterQualityOffset, _kFakeHostEndian)];
@@ -1344,30 +399,12 @@
     final int encoded = value.index;
     _data.setInt32(_kFilterQualityOffset, encoded, _kFakeHostEndian);
   }
-
-  /// The shader to use when stroking or filling a shape.
-  ///
-  /// When this is null, the [color] is used instead.
-  ///
-  /// See also:
-  ///
-  ///  * [Gradient], a shader that paints a color gradient.
-  ///  * [ImageShader], a shader that tiles an [Image].
-  ///  * [colorFilter], which overrides [shader].
-  ///  * [color], which is used if [shader] and [colorFilter] are null.
   Shader? get shader {
     return _objects?[_kShaderIndex] as Shader?;
   }
   set shader(Shader? value) {
     _ensureObjectsInitialized()[_kShaderIndex] = value;
   }
-
-  /// A color filter to apply when a shape is drawn or when a layer is
-  /// composited.
-  ///
-  /// See [ColorFilter] for details.
-  ///
-  /// When a shape is being drawn, [colorFilter] overrides [color] and [shader].
   ColorFilter? get colorFilter {
     return _objects?[_kColorFilterIndex]?.creator as ColorFilter?;
   }
@@ -1382,29 +419,6 @@
       _ensureObjectsInitialized()[_kColorFilterIndex] = nativeFilter;
     }
   }
-
-  /// The [ImageFilter] to use when drawing raster images.
-  ///
-  /// For example, to blur an image using [Canvas.drawImage], apply an
-  /// [ImageFilter.blur]:
-  ///
-  /// ```dart
-  /// import 'dart:ui' as ui;
-  ///
-  /// ui.Image image;
-  ///
-  /// void paint(Canvas canvas, Size size) {
-  ///   canvas.drawImage(
-  ///     image,
-  ///     Offset.zero,
-  ///     Paint()..imageFilter = ui.ImageFilter.blur(sigmaX: .5, sigmaY: .5),
-  ///   );
-  /// }
-  /// ```
-  ///
-  /// See also:
-  ///
-  ///  * [MaskFilter], which is used for drawing geometry.
   ImageFilter? get imageFilter {
     return _objects?[_kImageFilterIndex]?.creator as ImageFilter?;
   }
@@ -1421,12 +435,6 @@
       }
     }
   }
-
-  /// Whether the colors of the image are inverted when drawn.
-  ///
-  /// Inverting the colors of an image applies a new color filter that will
-  /// be composed with any user provided color filters. This is primarily
-  /// used for implementing smart invert on iOS.
   bool get invertColors {
     return _data.getInt32(_kInvertColorOffset, _kFakeHostEndian) == 1;
   }
@@ -1440,22 +448,6 @@
   set _dither(bool value) {
     _data.setInt32(_kDitherOffset, value ? 1 : 0, _kFakeHostEndian);
   }
-
-  /// Whether to dither the output when drawing images.
-  ///
-  /// If false, the default value, dithering will be enabled when the input
-  /// color depth is higher than the output color depth. For example,
-  /// drawing an RGB8 image onto an RGB565 canvas.
-  ///
-  /// This value also controls dithering of [shader]s, which can make
-  /// gradients appear smoother.
-  ///
-  /// Whether or not dithering affects the output is implementation defined.
-  /// Some implementations may choose to ignore this completely, if they're
-  /// unable to control dithering.
-  ///
-  /// To ensure that dithering is consistently enabled for your entire
-  /// application, set this to true before invoking any drawing related code.
   static bool enableDithering = false;
 
   @override
@@ -1522,76 +514,15 @@
     return result.toString();
   }
 }
-
-/// The format in which image bytes should be returned when using
-/// [Image.toByteData].
 enum ImageByteFormat {
-  /// Raw RGBA format.
-  ///
-  /// Unencoded bytes, in RGBA row-primary form, 8 bits per channel.
   rawRgba,
-
-  /// Raw unmodified format.
-  ///
-  /// Unencoded bytes, in the image's existing format. For example, a grayscale
-  /// image may use a single 8-bit channel for each pixel.
   rawUnmodified,
-
-  /// PNG format.
-  ///
-  /// A loss-less compression format for images. This format is well suited for
-  /// images with hard edges, such as screenshots or sprites, and images with
-  /// text. Transparency is supported. The PNG format supports images up to
-  /// 2,147,483,647 pixels in either dimension, though in practice available
-  /// memory provides a more immediate limitation on maximum image size.
-  ///
-  /// PNG images normally use the `.png` file extension and the `image/png` MIME
-  /// type.
-  ///
-  /// See also:
-  ///
-  ///  * <https://en.wikipedia.org/wiki/Portable_Network_Graphics>, the Wikipedia page on PNG.
-  ///  * <https://tools.ietf.org/rfc/rfc2083.txt>, the PNG standard.
   png,
 }
-
-/// The format of pixel data given to [decodeImageFromPixels].
 enum PixelFormat {
-  /// Each pixel is 32 bits, with the highest 8 bits encoding red, the next 8
-  /// bits encoding green, the next 8 bits encoding blue, and the lowest 8 bits
-  /// encoding alpha.
   rgba8888,
-
-  /// Each pixel is 32 bits, with the highest 8 bits encoding blue, the next 8
-  /// bits encoding green, the next 8 bits encoding red, and the lowest 8 bits
-  /// encoding alpha.
   bgra8888,
 }
-
-/// Opaque handle to raw decoded image data (pixels).
-///
-/// To obtain an [Image] object, use the [ImageDescriptor] API.
-///
-/// To draw an [Image], use one of the methods on the [Canvas] class, such as
-/// [Canvas.drawImage].
-///
-/// A class or method that receives an image object must call [dispose] on the
-/// handle when it is no longer needed. To create a shareable reference to the
-/// underlying image, call [clone]. The method or object that recieves
-/// the new instance will then be responsible for disposing it, and the
-/// underlying image itself will be disposed when all outstanding handles are
-/// disposed.
-///
-/// If `dart:ui` passes an `Image` object and the recipient wishes to share
-/// that handle with other callers, [clone] must be called _before_ [dispose].
-/// A handle that has been disposed cannot create new handles anymore.
-///
-/// See also:
-///
-///  * [Image](https://api.flutter.dev/flutter/widgets/Image-class.html), the class in the [widgets] library.
-///  * [ImageDescriptor], which allows reading information about the image and
-///    creating a codec to decode it.
-///  * [instantiateImageCodec], a utility method that wraps [ImageDescriptor].
 class Image {
   Image._(this._image) {
     assert(() {
@@ -1602,34 +533,19 @@
   }
 
   // C++ unit tests access this.
-  @pragma('vm:entry-point')
-  final _Image _image;
+    final _Image _image;
 
   StackTrace? _debugStack;
-
-  /// The number of image pixels along the image's horizontal axis.
   int get width {
     assert(!_disposed && !_image._disposed);
     return _image.width;
   }
-
-  /// The number of image pixels along the image's vertical axis.
   int get height {
     assert(!_disposed && !_image._disposed);
     return _image.height;
   }
 
   bool _disposed = false;
-  /// Release this handle's claim on the underlying Image. This handle is no
-  /// longer usable after this method is called.
-  ///
-  /// Once all outstanding handles have been disposed, the underlying image will
-  /// be disposed as well.
-  ///
-  /// In debug mode, [debugGetOpenHandleStackTraces] will return a list of
-  /// [StackTrace] objects from all open handles' creation points. This is
-  /// useful when trying to determine what parts of the program are keeping an
-  /// image resident in memory.
   void dispose() {
     assert(!_disposed && !_image._disposed);
     assert(_image._handles.contains(this));
@@ -1640,11 +556,6 @@
       _image.dispose();
     }
   }
-
-  /// Whether this reference to the underlying image is [dispose]d.
-  ///
-  /// This only returns a valid value if asserts are enabled, and must not be
-  /// used otherwise.
   bool get debugDisposed {
     bool? disposed;
     assert(() {
@@ -1653,23 +564,10 @@
     }());
     return disposed ?? (throw StateError('Image.debugDisposed is only available when asserts are enabled.'));
   }
-
-  /// Converts the [Image] object into a byte array.
-  ///
-  /// The [format] argument specifies the format in which the bytes will be
-  /// returned.
-  ///
-  /// Returns a future that completes with the binary image data or an error
-  /// if encoding fails.
   Future<ByteData?> toByteData({ImageByteFormat format = ImageByteFormat.rawRgba}) {
     assert(!_disposed && !_image._disposed);
     return _image.toByteData(format: format);
   }
-
-  /// If asserts are enabled, returns the [StackTrace]s of each open handle from
-  /// [clone], in creation order.
-  ///
-  /// If asserts are disabled, this method always returns null.
   List<StackTrace>? debugGetOpenHandleStackTraces() {
     List<StackTrace>? stacks;
     assert(() {
@@ -1678,81 +576,6 @@
     }());
     return stacks;
   }
-
-  /// Creates a disposable handle to this image.
-  ///
-  /// Holders of an [Image] must dispose of the image when they no longer need
-  /// to access it or draw it. However, once the underlying image is disposed,
-  /// it is no longer possible to use it. If a holder of an image needs to share
-  /// access to that image with another object or method, [clone] creates a
-  /// duplicate handle. The underlying image will only be disposed once all
-  /// outstanding handles are disposed. This allows for safe sharing of image
-  /// references while still disposing of the underlying resources when all
-  /// consumers are finished.
-  ///
-  /// It is safe to pass an [Image] handle to another object or method if the
-  /// current holder no longer needs it.
-  ///
-  /// To check whether two [Image] references are refering to the same
-  /// underlying image memory, use [isCloneOf] rather than the equality operator
-  /// or [identical].
-  ///
-  /// The following example demonstrates valid usage.
-  ///
-  /// ```dart
-  /// import 'dart:async';
-  ///
-  /// Future<Image> _loadImage(int width, int height) {
-  ///   final Completer<Image> completer = Completer<Image>();
-  ///   decodeImageFromPixels(
-  ///     Uint8List.fromList(List<int>.filled(width * height * 4, 0xFF)),
-  ///     width,
-  ///     height,
-  ///     PixelFormat.rgba8888,
-  ///     // Don't worry about disposing or cloning this image - responsibility
-  ///     // is transferred to the caller, and that is safe since this method
-  ///     // will not touch it again.
-  ///     (Image image) => completer.complete(image),
-  ///   );
-  ///   return completer.future;
-  /// }
-  ///
-  /// Future<void> main() async {
-  ///   final Image image = await _loadImage(5, 5);
-  ///   // Make sure to clone the image, because MyHolder might dispose it
-  ///   // and we need to access it again.
-  ///   final MyImageHolder holder = MyImageHolder(image.clone());
-  ///   final MyImageHolder holder2 = MyImageHolder(image.clone());
-  ///   // Now we dispose it because we won't need it again.
-  ///   image.dispose();
-  ///
-  ///   final PictureRecorder recorder = PictureRecorder();
-  ///   final Canvas canvas = Canvas(recorder);
-  ///
-  ///   holder.draw(canvas);
-  ///   holder.dispose();
-  ///
-  ///   canvas.translate(50, 50);
-  ///   holder2.draw(canvas);
-  ///   holder2.dispose();
-  /// }
-  ///
-  /// class MyImageHolder {
-  ///   MyImageLoader(this.image);
-  ///
-  ///   final Image image;
-  ///
-  ///   void draw(Canvas canvas) {
-  ///     canvas.drawImage(image, Offset.zero, Paint());
-  ///   }
-  ///
-  ///   void dispose() => image.dispose();
-  /// }
-  /// ```
-  ///
-  /// The returned object behaves identically to this image. Calling
-  /// [dispose] on it will only dispose the underlying native resources if it
-  /// is the last remaining handle.
   Image clone() {
     if (_disposed) {
       throw StateError(
@@ -1765,35 +588,23 @@
     assert(!_image._disposed);
     return Image._(_image);
   }
-
-  /// Returns true if `other` is a [clone] of this and thus shares the same
-  /// underlying image memory, even if this or `other` is [dispose]d.
-  ///
-  /// This method may return false for two images that were decoded from the
-  /// same underlying asset, if they are not sharing the same memory. For
-  /// example, if the same file is decoded using [instantiateImageCodec] twice,
-  /// or the same bytes are decoded using [decodeImageFromPixels] twice, there
-  /// will be two distinct [Image]s that render the same but do not share
-  /// underlying memory, and so will not be treated as clones of each other.
   bool isCloneOf(Image other) => other._image == _image;
 
   @override
   String toString() => _image.toString();
 }
 
-@pragma('vm:entry-point')
-class _Image extends NativeFieldWrapperClass2 {
+class _Image {
   // This class is created by the engine, and should not be instantiated
   // or extended directly.
   //
   // _Images are always handed out wrapped in [Image]s. To create an [Image],
   // use the ImageDescriptor API.
-  @pragma('vm:entry-point')
-  _Image._();
+  _Image._(this.width, this.height);
 
-  int get width { throw UnimplementedError(); }
+  final int width;
 
-  int get height { throw UnimplementedError(); }
+  final int height;
 
   Future<ByteData?> toByteData({ImageByteFormat format = ImageByteFormat.rawRgba}) {
     return _futurize((_Callback<ByteData> callback) {
@@ -1802,8 +613,6 @@
       });
     });
   }
-
-  /// Returns an error message on failure, null on success.
   String? _toByteData(int format, _Callback<Uint8List?> callback) { throw UnimplementedError(); }
 
   bool _disposed = false;
@@ -1827,114 +636,28 @@
   @override
   String toString() => '[$width\u00D7$height]';
 }
-
-/// Callback signature for [decodeImageFromList].
 typedef ImageDecoderCallback = void Function(Image result);
-
-/// Information for a single frame of an animation.
-///
-/// To obtain an instance of the [FrameInfo] interface, see
-/// [Codec.getNextFrame].
-///
-/// The recipient of an instance of this class is responsible for calling
-/// [Image.dispose] on [image]. To share the image with other interested
-/// parties, use [Image.clone]. If the [FrameInfo] object itself is passed to
-/// another method or object, that method or object must assume it is
-/// responsible for disposing the image when done, and the passer must not
-/// access the [image] after that point.
-///
-/// For example, the following code sample is incorrect:
-///
-/// ```dart
-/// /// BAD
-/// Future<void> nextFrameRoutine(Codec codec) async {
-///   final FrameInfo frameInfo = await codec.getNextFrame();
-///   _cacheImage(frameInfo);
-///   // ERROR - _cacheImage is now responsible for disposing the image, and
-///   // the image may not be available any more for this drawing routine.
-///   _drawImage(frameInfo);
-///   // ERROR again - the previous methods might or might not have created
-///   // handles to the image.
-///   frameInfo.image.dispose();
-/// }
-/// ```
-///
-/// Correct usage is:
-///
-/// ```dart
-/// /// GOOD
-/// Future<void> nextFrameRoutine(Codec codec) async {
-///   final FrameInfo frameInfo = await codec.getNextFrame();
-///   _cacheImage(frameInfo.image.clone(), frameInfo.duration);
-///   _drawImage(frameInfo.image.clone(), frameInfo.duration);
-///   // This method is done with its handle, and has passed handles to its
-///   // clients already.
-///   // The image will live until those clients dispose of their handles, and
-///   // this one must not be disposed since it will not be used again.
-///   frameInfo.image.dispose();
-/// }
-/// ```
 class FrameInfo {
-  /// This class is created by the engine, and should not be instantiated
-  /// or extended directly.
-  ///
-  /// To obtain an instance of the [FrameInfo] interface, see
-  /// [Codec.getNextFrame].
   FrameInfo._({required this.duration, required this.image});
-
-  /// The duration this frame should be shown.
-  ///
-  /// A zero duration indicates that the frame should be shown indefinitely.
   final Duration duration;
-
-
-  /// The [Image] object for this frame.
-  ///
-  /// This object must be disposed by the recipient of this frame info.
-  ///
-  /// To share this image with other interested parties, use [Image.clone].
   final Image image;
 }
-
-/// A handle to an image codec.
-///
-/// This class is created by the engine, and should not be instantiated
-/// or extended directly.
-///
-/// To obtain an instance of the [Codec] interface, see
-/// [instantiateImageCodec].
-@pragma('vm:entry-point')
-class Codec extends NativeFieldWrapperClass2 {
+class Codec {
   //
   // This class is created by the engine, and should not be instantiated
   // or extended directly.
   //
   // To obtain an instance of the [Codec] interface, see
   // [instantiateImageCodec].
-  @pragma('vm:entry-point')
-  Codec._();
+    Codec._();
 
   int? _cachedFrameCount;
-  /// Number of frames in this image.
   int get frameCount => _cachedFrameCount ??= _frameCount;
   int get _frameCount { throw UnimplementedError(); }
 
   int? _cachedRepetitionCount;
-  /// Number of times to repeat the animation.
-  ///
-  /// * 0 when the animation should be played once.
-  /// * -1 for infinity repetitions.
   int get repetitionCount => _cachedRepetitionCount ??= _repetitionCount;
   int get _repetitionCount { throw UnimplementedError(); }
-
-  /// Fetches the next animation frame.
-  ///
-  /// Wraps back to the first frame after returning the last frame.
-  ///
-  /// The returned future can complete with an error if the decoding has failed.
-  ///
-  /// The caller of this method is responsible for disposing the
-  /// [FrameInfo.image] on the returned object.
   Future<FrameInfo> getNextFrame() async {
     final Completer<FrameInfo> completer = Completer<FrameInfo>.sync();
     final String? error = _getNextFrame((_Image? image, int durationMilliseconds) {
@@ -1951,43 +674,9 @@
     }
     return await completer.future;
   }
-
-  /// Returns an error message on failure, null on success.
   String? _getNextFrame(void Function(_Image?, int) callback) { throw UnimplementedError(); }
-
-  /// Release the resources used by this object. The object is no longer usable
-  /// after this method is called.
   void dispose() { throw UnimplementedError(); }
 }
-
-/// Instantiates an image [Codec].
-///
-/// This method is a convenience wrapper around the [ImageDescriptor] API, and
-/// using [ImageDescriptor] directly is preferred since it allows the caller to
-/// make better determinations about how and whether to use the `targetWidth`
-/// and `targetHeight` parameters.
-///
-/// The `list` parameter is the binary image data (e.g a PNG or GIF binary data).
-/// The data can be for either static or animated images. The following image
-/// formats are supported: {@macro dart.ui.imageFormats}
-///
-/// The `targetWidth` and `targetHeight` arguments specify the size of the
-/// output image, in image pixels. If they are not equal to the intrinsic
-/// dimensions of the image, then the image will be scaled after being decoded.
-/// If the `allowUpscaling` parameter is not set to true, both dimensions will
-/// be capped at the intrinsic dimensions of the image, even if only one of
-/// them would have exceeded those intrinsic dimensions. If exactly one of these
-/// two arguments is specified, then the aspect ratio will be maintained while
-/// forcing the image to match the other given dimension. If neither is
-/// specified, then the image maintains its intrinsic size.
-///
-/// Scaling the image to larger than its intrinsic size should usually be
-/// avoided, since it causes the image to use more memory than necessary.
-/// Instead, prefer scaling the [Canvas] transform. If the image must be scaled
-/// up, the `allowUpscaling` parameter must be set to true.
-///
-/// The returned future can complete with an error if the image decoding has
-/// failed.
 Future<Codec> instantiateImageCodec(
   Uint8List list, {
   int? targetWidth,
@@ -2009,12 +698,6 @@
     targetHeight: targetHeight,
   );
 }
-
-/// Loads a single image frame from a byte array into an [Image] object.
-///
-/// This is a convenience wrapper around [instantiateImageCodec]. Prefer using
-/// [instantiateImageCodec] which also supports multi frame images and offers
-/// better error handling. This function swallows asynchronous errors.
 void decodeImageFromList(Uint8List list, ImageDecoderCallback callback) {
   _decodeImageFromListAsync(list, callback);
 }
@@ -2025,30 +708,6 @@
   final FrameInfo frameInfo = await codec.getNextFrame();
   callback(frameInfo.image);
 }
-
-/// Convert an array of pixel values into an [Image] object.
-///
-/// The `pixels` parameter is the pixel data in the encoding described by
-/// `format`.
-///
-/// The `rowBytes` parameter is the number of bytes consumed by each row of
-/// pixels in the data buffer. If unspecified, it defaults to `width` multiplied
-/// by the number of bytes per pixel in the provided `format`.
-///
-/// The `targetWidth` and `targetHeight` arguments specify the size of the
-/// output image, in image pixels. If they are not equal to the intrinsic
-/// dimensions of the image, then the image will be scaled after being decoded.
-/// If the `allowUpscaling` parameter is not set to true, both dimensions will
-/// be capped at the intrinsic dimensions of the image, even if only one of
-/// them would have exceeded those intrinsic dimensions. If exactly one of these
-/// two arguments is specified, then the aspect ratio will be maintained while
-/// forcing the image to match the other given dimension. If neither is
-/// specified, then the image maintains its intrinsic size.
-///
-/// Scaling the image to larger than its intrinsic size should usually be
-/// avoided, since it causes the image to use more memory than necessary.
-/// Instead, prefer scaling the [Canvas] transform. If the image must be scaled
-/// up, the `allowUpscaling` parameter must be set to true.
 void decodeImageFromPixels(
   Uint8List pixels,
   int width,
@@ -2095,230 +754,289 @@
         .then((FrameInfo frameInfo) => callback(frameInfo.image));
   });
 }
-
-/// Determines the winding rule that decides how the interior of a [Path] is
-/// calculated.
-///
-/// This enum is used by the [Path.fillType] property.
 enum PathFillType {
-  /// The interior is defined by a non-zero sum of signed edge crossings.
-  ///
-  /// For a given point, the point is considered to be on the inside of the path
-  /// if a line drawn from the point to infinity crosses lines going clockwise
-  /// around the point a different number of times than it crosses lines going
-  /// counter-clockwise around that point.
-  ///
-  /// See: <https://en.wikipedia.org/wiki/Nonzero-rule>
   nonZero,
-
-  /// The interior is defined by an odd number of edge crossings.
-  ///
-  /// For a given point, the point is considered to be on the inside of the path
-  /// if a line drawn from the point to infinity crosses an odd number of lines.
-  ///
-  /// See: <https://en.wikipedia.org/wiki/Even-odd_rule>
   evenOdd,
 }
-
-/// Strategies for combining paths.
-///
-/// See also:
-///
-/// * [Path.combine], which uses this enum to decide how to combine two paths.
 // Must be kept in sync with SkPathOp
 enum PathOperation {
-  /// Subtract the second path from the first path.
-  ///
-  /// For example, if the two paths are overlapping circles of equal diameter
-  /// but differing centers, the result would be a crescent portion of the
-  /// first circle that was not overlapped by the second circle.
-  ///
-  /// See also:
-  ///
-  ///  * [reverseDifference], which is the same but subtracting the first path
-  ///    from the second.
   difference,
-  /// Create a new path that is the intersection of the two paths, leaving the
-  /// overlapping pieces of the path.
-  ///
-  /// For example, if the two paths are overlapping circles of equal diameter
-  /// but differing centers, the result would be only the overlapping portion
-  /// of the two circles.
-  ///
-  /// See also:
-  ///  * [xor], which is the inverse of this operation
   intersect,
-  /// Create a new path that is the union (inclusive-or) of the two paths.
-  ///
-  /// For example, if the two paths are overlapping circles of equal diameter
-  /// but differing centers, the result would be a figure-eight like shape
-  /// matching the outer boundaries of both circles.
   union,
-  /// Create a new path that is the exclusive-or of the two paths, leaving
-  /// everything but the overlapping pieces of the path.
-  ///
-  /// For example, if the two paths are overlapping circles of equal diameter
-  /// but differing centers, the figure-eight like shape less the overlapping parts
-  ///
-  /// See also:
-  ///  * [intersect], which is the inverse of this operation
   xor,
-  /// Subtract the first path from the second path.
-  ///
-  /// For example, if the two paths are overlapping circles of equal diameter
-  /// but differing centers, the result would be a crescent portion of the
-  /// second circle that was not overlapped by the first circle.
-  ///
-  /// See also:
-  ///
-  ///  * [difference], which is the same but subtracting the second path
-  ///    from the first.
   reverseDifference,
 }
 
-/// A handle for the framework to hold and retain an engine layer across frames.
-@pragma('vm:entry-point')
-class EngineLayer extends NativeFieldWrapperClass2 {
-  /// This class is created by the engine, and should not be instantiated
-  /// or extended directly.
-  @pragma('vm:entry-point')
-  EngineLayer._();
+abstract class EngineLayer {
 }
 
-/// A complex, one-dimensional subset of a plane.
-///
-/// A path consists of a number of sub-paths, and a _current point_.
-///
-/// Sub-paths consist of segments of various types, such as lines,
-/// arcs, or beziers. Sub-paths can be open or closed, and can
-/// self-intersect.
-///
-/// Closed sub-paths enclose a (possibly discontiguous) region of the
-/// plane based on the current [fillType].
-///
-/// The _current point_ is initially at the origin. After each
-/// operation adding a segment to a sub-path, the current point is
-/// updated to the end of that segment.
-///
-/// Paths can be drawn on canvases using [Canvas.drawPath], and can
-/// used to create clip regions using [Canvas.clipPath].
-@pragma('vm:entry-point')
-class Path extends NativeFieldWrapperClass2 {
-  /// Create a new empty [Path] object.
-  @pragma('vm:entry-point')
-  Path() { _constructor(); }
-  void _constructor() { throw UnimplementedError(); }
-
-  /// Avoids creating a new native backing for the path for methods that will
-  /// create it later, such as [Path.from], [shift] and [transform].
+class _PathMethods {
+  static const int moveTo = 0;
+  static const int relativeMoveTo = 1;
+  static const int lineTo = 2;
+  static const int relativeLineTo = 3;
+  static const int quadraticBezierTo = 4;
+  static const int relativeQuadraticBezierTo = 5;
+  static const int cubicTo = 6;
+  static const int relativeCubicTo = 7;
+  static const int conicTo = 8;
+  static const int relativeConicTo = 9;
+  static const int arcTo = 10;
+  static const int arcToPoint = 11;
+  static const int relativeArcToPoint = 12;
+  static const int addRect = 13;
+  static const int addOval = 14;
+  static const int addArc = 15;
+  static const int addPolygon = 16;
+  static const int addRRect = 17;
+  static const int addPath = 18;
+  static const int addPathWithMatrix = 19;
+  static const int extendWithPath = 20;
+  static const int extendWithPathAndMatrix = 21;
+  static const int close = 22;
+  static const int reset = 23;
+}
+class Path {
+  Path();
   Path._();
 
-  /// Creates a copy of another [Path].
-  ///
-  /// This copy is fast and does not require additional memory unless either
-  /// the `source` path or the path returned by this constructor are modified.
-  factory Path.from(Path source) {
-    final Path clonedPath = Path._();
-    source._clone(clonedPath);
-    return clonedPath;
+  PathFillType fillType = PathFillType.nonZero;
+  double _currentX = 0;
+  double _currentY = 0;
+  Uint8List _methods = Uint8List(10);
+  int _methodsLength = 0;
+  Float32List _data = Float32List(30);
+  int _dataLength = 0;
+  List<Object> _objects = <Object>[];
+  bool _isEmpty = true;
+  double _left = 0;
+  double _top = 0;
+  double _right = 0;
+  double _bottom = 0;
+
+  void _updateBounds(double x, double y) {
+    if (_isEmpty) {
+      _left = _right = x;
+      _top = _bottom = y;
+      _isEmpty = false;
+    } else {
+      if (x < _left) {
+        _left = x;
+      }
+      if (x > _right) {
+        _right = x;
+      }
+      if (y < _top) {
+        _top = y;
+      }
+      if (y > _bottom) {
+        _bottom = y;
+      }
+    }
   }
-  void _clone(Path outPath) { throw UnimplementedError(); }
 
-  /// Determines how the interior of this path is calculated.
-  ///
-  /// Defaults to the non-zero winding rule, [PathFillType.nonZero].
-  PathFillType get fillType => PathFillType.values[_getFillType()];
-  set fillType(PathFillType value) => _setFillType(value.index);
+  _updateBoundsFromCurrent() {
+    _updateBounds(_currentX, _currentY);
+  }
 
-  int _getFillType() { throw UnimplementedError(); }
-  void _setFillType(int fillType) { throw UnimplementedError(); }
+  void _addObject(Object object) {
+    _objects.add(object);
+  }
 
-  /// Starts a new sub-path at the given coordinate.
-  void moveTo(double x, double y) { throw UnimplementedError(); }
+  void _addMethod(int methodId) {
+    if (_methodsLength >= _methods.length) {
+      final Uint8List newList = Uint8List(_methods.length * 2);
+      for (int i = 0; i < _methodsLength; i++) {
+        newList[i] = _methods[i];
+      }
+      _methods = newList;
+    }
+    _methods[_methodsLength] = methodId;
+    _methodsLength += 1;
+  }
 
-  /// Starts a new sub-path at the given offset from the current point.
-  void relativeMoveTo(double dx, double dy) { throw UnimplementedError(); }
+  void _ensureDataLength(int newLength) {
+    if (_data.length >= newLength) {
+      return;
+    }
 
-  /// Adds a straight line segment from the current point to the given
-  /// point.
-  void lineTo(double x, double y) { throw UnimplementedError(); }
+    final Float32List newList = Float32List(_data.length * 2);
+    for (int i = 0; i < _dataLength; i++) {
+      newList[i] = _data[i];
+    }
+    _data = newList;
+  }
 
-  /// Adds a straight line segment from the current point to the point
-  /// at the given offset from the current point.
-  void relativeLineTo(double dx, double dy) { throw UnimplementedError(); }
+  void _addData2(double a, double b) {
+    _ensureDataLength(_dataLength + 2);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+  }
 
-  /// Adds a quadratic bezier segment that curves from the current
-  /// point to the given point (x2,y2), using the control point
-  /// (x1,y1).
-  void quadraticBezierTo(double x1, double y1, double x2, double y2) { throw UnimplementedError(); }
+  void _addData4(double a, double b, double c, double d) {
+    _ensureDataLength(_dataLength + 4);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+  }
 
-  /// Adds a quadratic bezier segment that curves from the current
-  /// point to the point at the offset (x2,y2) from the current point,
-  /// using the control point at the offset (x1,y1) from the current
-  /// point.
-  void relativeQuadraticBezierTo(double x1, double y1, double x2, double y2) { throw UnimplementedError(); }
+  void _addData5(double a, double b, double c, double d, double e) {
+    _ensureDataLength(_dataLength + 5);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+    _data[_dataLength++] = e;
+  }
 
-  /// Adds a cubic bezier segment that curves from the current point
-  /// to the given point (x3,y3), using the control points (x1,y1) and
-  /// (x2,y2).
-  void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) { throw UnimplementedError(); }
+  void _addData6(double a, double b, double c, double d, double e, double f) {
+    _ensureDataLength(_dataLength + 6);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+    _data[_dataLength++] = e;
+    _data[_dataLength++] = f;
+  }
 
-  /// Adds a cubic bezier segment that curves from the current point
-  /// to the point at the offset (x3,y3) from the current point, using
-  /// the control points at the offsets (x1,y1) and (x2,y2) from the
-  /// current point.
-  void relativeCubicTo(double x1, double y1, double x2, double y2, double x3, double y3) { throw UnimplementedError(); }
+  void _addData7(double a, double b, double c, double d, double e, double f, double g) {
+    _ensureDataLength(_dataLength + 7);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+    _data[_dataLength++] = e;
+    _data[_dataLength++] = f;
+    _data[_dataLength++] = g;
+  }
 
-  /// Adds a bezier segment that curves from the current point to the
-  /// given point (x2,y2), using the control points (x1,y1) and the
-  /// weight w. If the weight is greater than 1, then the curve is a
-  /// hyperbola; if the weight equals 1, it's a parabola; and if it is
-  /// less than 1, it is an ellipse.
-  void conicTo(double x1, double y1, double x2, double y2, double w) { throw UnimplementedError(); }
-
-  /// Adds a bezier segment that curves from the current point to the
-  /// point at the offset (x2,y2) from the current point, using the
-  /// control point at the offset (x1,y1) from the current point and
-  /// the weight w. If the weight is greater than 1, then the curve is
-  /// a hyperbola; if the weight equals 1, it's a parabola; and if it
-  /// is less than 1, it is an ellipse.
-  void relativeConicTo(double x1, double y1, double x2, double y2, double w) { throw UnimplementedError(); }
-
-  /// If the `forceMoveTo` argument is false, adds a straight line
-  /// segment and an arc segment.
-  ///
-  /// If the `forceMoveTo` argument is true, starts a new sub-path
-  /// consisting of an arc segment.
-  ///
-  /// In either case, the arc segment consists of the arc that follows
-  /// the edge of the oval bounded by the given rectangle, from
-  /// startAngle radians around the oval up to startAngle + sweepAngle
-  /// radians around the oval, with zero radians being the point on
-  /// the right hand side of the oval that crosses the horizontal line
-  /// that intersects the center of the rectangle and with positive
-  /// angles going clockwise around the oval.
-  ///
-  /// The line segment added if `forceMoveTo` is false starts at the
-  /// current point and ends at the start of the arc.
+  void _addData12(double a, double b, double c, double d, double e, double f,
+                  double g, double h, double i, double j, double k, double l) {
+    _ensureDataLength(_dataLength + 12);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+    _data[_dataLength++] = e;
+    _data[_dataLength++] = f;
+    _data[_dataLength++] = g;
+    _data[_dataLength++] = h;
+    _data[_dataLength++] = i;
+    _data[_dataLength++] = j;
+    _data[_dataLength++] = k;
+    _data[_dataLength++] = l;
+  }
+  factory Path.from(Path source) {
+    return source.shift(Offset.zero);
+  }
+  void moveTo(double x, double y) {
+    _addMethod(_PathMethods.moveTo);
+    _addData2(x, y);
+    _currentX = x;
+    _currentY = y;
+    _updateBoundsFromCurrent();
+  }
+  void relativeMoveTo(double dx, double dy) {
+    _addMethod(_PathMethods.relativeMoveTo);
+    _addData2(dx, dy);
+    _currentX += dx;
+    _currentY += dy;
+    _updateBoundsFromCurrent();
+  }
+  void lineTo(double x, double y) {
+    _addMethod(_PathMethods.lineTo);
+    _addData2(x, y);
+    _updateBoundsFromCurrent();
+    _currentX = x;
+    _currentY = y;
+    _updateBoundsFromCurrent();
+  }
+  void relativeLineTo(double dx, double dy) {
+    _addMethod(_PathMethods.relativeLineTo);
+    _addData2(dx, dy);
+    _updateBoundsFromCurrent();
+    _currentX += dx;
+    _currentY += dy;
+    _updateBoundsFromCurrent();
+  }
+  void quadraticBezierTo(double x1, double y1, double x2, double y2) {
+    _addMethod(_PathMethods.quadraticBezierTo);
+    _addData4(x1, y1, x2, y2);
+    _currentX = x1;
+    _currentY = y1;
+    _updateBoundsFromCurrent();
+    _currentX = x2;
+    _currentY = y2;
+    _updateBoundsFromCurrent();
+  }
+  void relativeQuadraticBezierTo(double x1, double y1, double x2, double y2) {
+    _addMethod(_PathMethods.relativeQuadraticBezierTo);
+    _addData4(x1, y1, x2, y2);
+    _currentX += x1;
+    _currentY += y1;
+    _updateBoundsFromCurrent();
+    _currentX += x2;
+    _currentY += y2;
+    _updateBoundsFromCurrent();
+  }
+  void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) {
+    _addMethod(_PathMethods.cubicTo);
+    _addData6(x1, y1, x2, y2, x3, y3);
+    _currentX = x1;
+    _currentY = y1;
+    _updateBoundsFromCurrent();
+    _currentX = x2;
+    _currentY = y2;
+    _updateBoundsFromCurrent();
+    _currentX = x3;
+    _currentY = y3;
+    _updateBoundsFromCurrent();
+  }
+  void relativeCubicTo(double x1, double y1, double x2, double y2, double x3, double y3) {
+    _addMethod(_PathMethods.relativeCubicTo);
+    _addData6(x1, y1, x2, y2, x3, y3);
+    _currentX += x1;
+    _currentY += y1;
+    _updateBoundsFromCurrent();
+    _currentX += x2;
+    _currentY += y2;
+    _updateBoundsFromCurrent();
+    _currentX += x3;
+    _currentY += y3;
+    _updateBoundsFromCurrent();
+  }
+  void conicTo(double x1, double y1, double x2, double y2, double w) {
+    _addMethod(_PathMethods.conicTo);
+    _addData5(x1, y1, x2, y2, w);
+    _currentX = x1;
+    _currentY = y1;
+    _updateBoundsFromCurrent();
+    _currentX = x2;
+    _currentY = y2;
+    _updateBoundsFromCurrent();
+  }
+  void relativeConicTo(double x1, double y1, double x2, double y2, double w) {
+    _addMethod(_PathMethods.relativeConicTo);
+    _addData5(x1, y1, x2, y2, w);
+    _currentX += x1;
+    _currentY += y1;
+    _updateBoundsFromCurrent();
+    _currentX += x2;
+    _currentY += y2;
+    _updateBoundsFromCurrent();
+  }
   void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo) {
     assert(_rectIsValid(rect));
-    _arcTo(rect.left, rect.top, rect.right, rect.bottom, startAngle, sweepAngle, forceMoveTo);
+    _addMethod(_PathMethods.arcTo);
+    _addData7(rect.left, rect.top, rect.right, rect.bottom, startAngle, sweepAngle, forceMoveTo ? 1 : 0);
+    _currentX = rect.left;
+    _currentY = rect.top;
+    _updateBoundsFromCurrent();
+    _currentX = rect.right;
+    _currentY = rect.bottom;
+    _updateBoundsFromCurrent();
   }
-  void _arcTo(double left, double top, double right, double bottom,
-              double startAngle, double sweepAngle, bool forceMoveTo) { throw UnimplementedError(); }
-
-  /// Appends up to four conic curves weighted to describe an oval of `radius`
-  /// and rotated by `rotation`.
-  ///
-  /// The first curve begins from the last point in the path and the last ends
-  /// at `arcEnd`. The curves follow a path in a direction determined by
-  /// `clockwise` and `largeArc` in such a way that the sweep angle
-  /// is always less than 360 degrees.
-  ///
-  /// A simple line is appended if either either radii are zero or the last
-  /// point in the path is `arcEnd`. The radii are scaled to fit the last path
-  /// point if both are greater than zero but too small to describe an arc.
-  ///
   void arcToPoint(Offset arcEnd, {
     Radius radius = Radius.zero,
     double rotation = 0.0,
@@ -2327,28 +1045,13 @@
   }) {
     assert(_offsetIsValid(arcEnd));
     assert(_radiusIsValid(radius));
-    _arcToPoint(arcEnd.dx, arcEnd.dy, radius.x, radius.y, rotation,
-                largeArc, clockwise);
+    _addMethod(_PathMethods.arcToPoint);
+    _addData7(arcEnd.dx, arcEnd.dy, radius.x, radius.y, rotation, largeArc ? 1 : 0, clockwise ? 1 : 0);
+    _updateBoundsFromCurrent();
+    _currentX = arcEnd.dx;
+    _currentY = arcEnd.dy;
+    _updateBoundsFromCurrent();
   }
-  void _arcToPoint(double arcEndX, double arcEndY, double radiusX,
-                   double radiusY, double rotation, bool largeArc,
-                   bool clockwise) { throw UnimplementedError(); }
-
-
-  /// Appends up to four conic curves weighted to describe an oval of `radius`
-  /// and rotated by `rotation`.
-  ///
-  /// The last path point is described by (px, py).
-  ///
-  /// The first curve begins from the last point in the path and the last ends
-  /// at `arcEndDelta.dx + px` and `arcEndDelta.dy + py`. The curves follow a
-  /// path in a direction determined by `clockwise` and `largeArc`
-  /// in such a way that the sweep angle is always less than 360 degrees.
-  ///
-  /// A simple line is appended if either either radii are zero, or, both
-  /// `arcEndDelta.dx` and `arcEndDelta.dy` are zero. The radii are scaled to
-  /// fit the last path point if both are greater than zero but too small to
-  /// describe an arc.
   void relativeArcToPoint(Offset arcEndDelta, {
     Radius radius = Radius.zero,
     double rotation = 0.0,
@@ -2357,289 +1060,219 @@
   }) {
     assert(_offsetIsValid(arcEndDelta));
     assert(_radiusIsValid(radius));
-    _relativeArcToPoint(arcEndDelta.dx, arcEndDelta.dy, radius.x, radius.y,
-                        rotation, largeArc, clockwise);
+    _addMethod(_PathMethods.relativeArcToPoint);
+    _addData7(arcEndDelta.dx, arcEndDelta.dy, radius.x, radius.y, rotation, largeArc ? 1 : 0, clockwise ? 1 : 0);
+    _updateBoundsFromCurrent();
+    _currentX += arcEndDelta.dx;
+    _currentY += arcEndDelta.dy;
+    _updateBoundsFromCurrent();
   }
-  void _relativeArcToPoint(double arcEndX, double arcEndY, double radiusX,
-                           double radiusY, double rotation,
-                           bool largeArc, bool clockwise)
-                           { throw UnimplementedError(); }
-
-  /// Adds a new sub-path that consists of four lines that outline the
-  /// given rectangle.
   void addRect(Rect rect) {
     assert(_rectIsValid(rect));
-    _addRect(rect.left, rect.top, rect.right, rect.bottom);
+    _addMethod(_PathMethods.addRect);
+    _addData4(rect.left, rect.top, rect.right, rect.bottom);
+    _currentX = rect.left;
+    _currentY = rect.top;
+    _updateBoundsFromCurrent();
+    _currentX = rect.right;
+    _currentY = rect.bottom;
+    _updateBoundsFromCurrent();
   }
-  void _addRect(double left, double top, double right, double bottom) { throw UnimplementedError(); }
-
-  /// Adds a new sub-path that consists of a curve that forms the
-  /// ellipse that fills the given rectangle.
-  ///
-  /// To add a circle, pass an appropriate rectangle as `oval`. [Rect.fromCircle]
-  /// can be used to easily describe the circle's center [Offset] and radius.
   void addOval(Rect oval) {
     assert(_rectIsValid(oval));
-    _addOval(oval.left, oval.top, oval.right, oval.bottom);
+    _addMethod(_PathMethods.addOval);
+    _addData4(oval.left, oval.top, oval.right, oval.bottom);
+    _currentX = oval.left;
+    _currentY = oval.top;
+    _updateBoundsFromCurrent();
+    _currentX = oval.right;
+    _currentY = oval.bottom;
+    _updateBoundsFromCurrent();
   }
-  void _addOval(double left, double top, double right, double bottom) { throw UnimplementedError(); }
-
-  /// Adds a new sub-path with one arc segment that consists of the arc
-  /// that follows the edge of the oval bounded by the given
-  /// rectangle, from startAngle radians around the oval up to
-  /// startAngle + sweepAngle radians around the oval, with zero
-  /// radians being the point on the right hand side of the oval that
-  /// crosses the horizontal line that intersects the center of the
-  /// rectangle and with positive angles going clockwise around the
-  /// oval.
   void addArc(Rect oval, double startAngle, double sweepAngle) {
     assert(_rectIsValid(oval));
-    _addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
+    _addMethod(_PathMethods.addArc);
+    _addData6(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
+    _currentX = oval.left;
+    _currentY = oval.top;
+    _updateBoundsFromCurrent();
+    _currentX = oval.right;
+    _currentY = oval.bottom;
+    _updateBoundsFromCurrent();
   }
-  void _addArc(double left, double top, double right, double bottom,
-               double startAngle, double sweepAngle) { throw UnimplementedError(); }
-
-  /// Adds a new sub-path with a sequence of line segments that connect the given
-  /// points.
-  ///
-  /// If `close` is true, a final line segment will be added that connects the
-  /// last point to the first point.
-  ///
-  /// The `points` argument is interpreted as offsets from the origin.
   void addPolygon(List<Offset> points, bool close) {
     assert(points != null); // ignore: unnecessary_null_comparison
-    _addPolygon(_encodePointList(points), close);
+    _addMethod(_PathMethods.addPolygon);
+    _ensureDataLength(_dataLength + points.length * 2);
+    for (final Offset point in points) {
+      _data[_dataLength++] = point.dx;
+      _data[_dataLength++] = point.dy;
+      _currentX = point.dx;
+      _currentY = point.dy;
+      _updateBoundsFromCurrent();
+    }
   }
-  void _addPolygon(Float32List points, bool close) { throw UnimplementedError(); }
-
-  /// Adds a new sub-path that consists of the straight lines and
-  /// curves needed to form the rounded rectangle described by the
-  /// argument.
   void addRRect(RRect rrect) {
     assert(_rrectIsValid(rrect));
-    _addRRect(rrect._value32);
+    _addMethod(_PathMethods.addRRect);
+    _addData12(
+      rrect.left,
+      rrect.top,
+      rrect.right,
+      rrect.bottom,
+      rrect.tlRadiusX,
+      rrect.tlRadiusY,
+      rrect.trRadiusX,
+      rrect.trRadiusY,
+      rrect.brRadiusX,
+      rrect.brRadiusY,
+      rrect.blRadiusX,
+      rrect.blRadiusY,
+    );
+    _currentX = rrect.left;
+    _currentY = rrect.top;
+    _updateBoundsFromCurrent();
+    _currentX = rrect.right;
+    _currentY = rrect.bottom;
+    _updateBoundsFromCurrent();
   }
-  void _addRRect(Float32List rrect) { throw UnimplementedError(); }
-
-  /// Adds a new sub-path that consists of the given `path` offset by the given
-  /// `offset`.
-  ///
-  /// If `matrix4` is specified, the path will be transformed by this matrix
-  /// after the matrix is translated by the given offset. The matrix is a 4x4
-  /// matrix stored in column major order.
   void addPath(Path path, Offset offset, {Float64List? matrix4}) {
     // ignore: unnecessary_null_comparison
     assert(path != null); // path is checked on the engine side
     assert(_offsetIsValid(offset));
     if (matrix4 != null) {
       assert(_matrix4IsValid(matrix4));
-      _addPathWithMatrix(path, offset.dx, offset.dy, matrix4);
+      _addMethod(_PathMethods.addPathWithMatrix);
+      _addData2(offset.dx, offset.dy);
+      _addObject(path);
+      _addObject(matrix4);
     } else {
-      _addPath(path, offset.dx, offset.dy);
+      _addMethod(_PathMethods.addPath);
+      _addData2(offset.dx, offset.dy);
+      _addObject(path);
     }
+    final Rect otherBounds = path.getBounds();
+    _updateBounds(otherBounds.left, otherBounds.top);
+    _updateBounds(otherBounds.right, otherBounds.bottom);
   }
-  void _addPath(Path path, double dx, double dy) { throw UnimplementedError(); }
-  void _addPathWithMatrix(Path path, double dx, double dy, Float64List matrix) { throw UnimplementedError(); }
-
-  /// Adds the given path to this path by extending the current segment of this
-  /// path with the first segment of the given path.
-  ///
-  /// If `matrix4` is specified, the path will be transformed by this matrix
-  /// after the matrix is translated by the given `offset`.  The matrix is a 4x4
-  /// matrix stored in column major order.
   void extendWithPath(Path path, Offset offset, {Float64List? matrix4}) {
     // ignore: unnecessary_null_comparison
     assert(path != null); // path is checked on the engine side
     assert(_offsetIsValid(offset));
     if (matrix4 != null) {
       assert(_matrix4IsValid(matrix4));
-      _extendWithPathAndMatrix(path, offset.dx, offset.dy, matrix4);
+      _addMethod(_PathMethods.extendWithPathAndMatrix);
+      _addData2(offset.dx, offset.dy);
+      _addObject(path);
+      _addObject(matrix4);
     } else {
-      _extendWithPath(path, offset.dx, offset.dy);
+      _addMethod(_PathMethods.extendWithPath);
+      _addData2(offset.dx, offset.dy);
+      _addObject(path);
     }
+    final Rect otherBounds = path.getBounds();
+    _updateBounds(otherBounds.left, otherBounds.top);
+    _updateBounds(otherBounds.right, otherBounds.bottom);
   }
-  void _extendWithPath(Path path, double dx, double dy) { throw UnimplementedError(); }
-  void _extendWithPathAndMatrix(Path path, double dx, double dy, Float64List matrix) { throw UnimplementedError(); }
-
-  /// Closes the last sub-path, as if a straight line had been drawn
-  /// from the current point to the first point of the sub-path.
-  void close() { throw UnimplementedError(); }
-
-  /// Clears the [Path] object of all sub-paths, returning it to the
-  /// same state it had when it was created. The _current point_ is
-  /// reset to the origin.
-  void reset() { throw UnimplementedError(); }
-
-  /// Tests to see if the given point is within the path. (That is, whether the
-  /// point would be in the visible portion of the path if the path was used
-  /// with [Canvas.clipPath].)
-  ///
-  /// The `point` argument is interpreted as an offset from the origin.
-  ///
-  /// Returns true if the point is in the path, and false otherwise.
+  void close() {
+    _addMethod(_PathMethods.close);
+  }
+  void reset() {
+    _addMethod(_PathMethods.reset);
+  }
   bool contains(Offset point) {
     assert(_offsetIsValid(point));
-    return _contains(point.dx, point.dy);
+    return getBounds().contains(point);
   }
-  bool _contains(double x, double y) { throw UnimplementedError(); }
-
-  /// Returns a copy of the path with all the segments of every
-  /// sub-path translated by the given offset.
   Path shift(Offset offset) {
     assert(_offsetIsValid(offset));
-    final Path path = Path._();
-    _shift(path, offset.dx, offset.dy);
-    return path;
+    // This is a dummy implementation.
+    final Path shifted = Path._();
+    shifted._methods = Uint8List.fromList(this._methods);
+    shifted._methodsLength = _methodsLength;
+    shifted._data = Float32List.fromList(this._data);
+    shifted._dataLength = _dataLength;
+    shifted._objects = this._objects.toList();
+    shifted._isEmpty = _isEmpty;
+    shifted._left = _left + offset.dx;
+    shifted._top = _top + offset.dy;
+    shifted._right = _right + offset.dx;
+    shifted._bottom = _bottom + offset.dy;
+    shifted._currentX = _currentX + offset.dx;
+    shifted._currentY = _currentY + offset.dy;
+    shifted.fillType = fillType;
+    return shifted;
   }
-  void _shift(Path outPath, double dx, double dy) { throw UnimplementedError(); }
-
-  /// Returns a copy of the path with all the segments of every
-  /// sub-path transformed by the given matrix.
   Path transform(Float64List matrix4) {
     assert(_matrix4IsValid(matrix4));
-    final Path path = Path._();
-    _transform(path, matrix4);
-    return path;
+    // This is a dummy implementation.
+    final double dx = matrix4[12];
+    final double dy = matrix4[13];
+    final Path transformed = Path._();
+    transformed._methods = Uint8List.fromList(this._methods);
+    transformed._methodsLength = _methodsLength;
+    transformed._data = Float32List.fromList(this._data);
+    transformed._dataLength = _dataLength;
+    transformed._objects = this._objects.toList();
+    transformed._isEmpty = _isEmpty;
+    transformed._left = _left + dx;
+    transformed._top = _top + dy;
+    transformed._right = _right + dx;
+    transformed._bottom = _bottom + dy;
+    transformed._currentX = _currentX + dx;
+    transformed._currentY = _currentY + dy;
+    transformed.fillType = fillType;
+    return transformed;
   }
-  void _transform(Path outPath, Float64List matrix4) { throw UnimplementedError(); }
-
-  /// Computes the bounding rectangle for this path.
-  ///
-  /// A path containing only axis-aligned points on the same straight line will
-  /// have no area, and therefore `Rect.isEmpty` will return true for such a
-  /// path. Consider checking `rect.width + rect.height > 0.0` instead, or
-  /// using the [computeMetrics] API to check the path length.
-  ///
-  /// For many more elaborate paths, the bounds may be inaccurate.  For example,
-  /// when a path contains a circle, the points used to compute the bounds are
-  /// the circle's implied control points, which form a square around the circle;
-  /// if the circle has a transformation applied using [transform] then that
-  /// square is rotated, and the (axis-aligned, non-rotated) bounding box
-  /// therefore ends up grossly overestimating the actual area covered by the
-  /// circle.
   // see https://skia.org/user/api/SkPath_Reference#SkPath_getBounds
   Rect getBounds() {
-    final Float32List rect = _getBounds();
-    return Rect.fromLTRB(rect[0], rect[1], rect[2], rect[3]);
+    return Rect.fromLTRB(_left, _top, _right, _bottom);
   }
-  Float32List _getBounds() { throw UnimplementedError(); }
-
-  /// Combines the two paths according to the manner specified by the given
-  /// `operation`.
-  ///
-  /// The resulting path will be constructed from non-overlapping contours. The
-  /// curve order is reduced where possible so that cubics may be turned into
-  /// quadratics, and quadratics maybe turned into lines.
   static Path combine(PathOperation operation, Path path1, Path path2) {
     assert(path1 != null); // ignore: unnecessary_null_comparison
     assert(path2 != null); // ignore: unnecessary_null_comparison
-    final Path path = Path();
-    if (path._op(path1, path2, operation.index)) {
-      return path;
-    }
-    throw StateError('Path.combine() failed.  This may be due an invalid path; in particular, check for NaN values.');
+    // This is a dummy implementation
+    final Path combined = Path._();
+    combined._methods = Uint8List.fromList([
+      ...path1._methods,
+      ...path2._methods,
+    ]);
+    combined._methodsLength = path1._methodsLength + path2._methodsLength;
+    combined._data = Float32List.fromList([
+      ...path1._data,
+      ...path2._data,
+    ]);
+    combined._dataLength = path1._dataLength + path2._dataLength;
+    combined._objects = <Object>[
+      ...path1._objects,
+      ...path2._objects,
+    ];
+    combined._isEmpty = path1._isEmpty && path2._isEmpty;
+    combined._left = math.min(path1._left, path2._left);
+    combined._top = math.min(path1._top, path2._top);
+    combined._right = math.max(path1._right, path2._right);
+    combined._bottom = math.max(path1._bottom, path2._bottom);
+    combined._currentX = path2._currentX;
+    combined._currentY = path2._currentY;
+    combined.fillType = path1.fillType;
+    return combined;
   }
-  bool _op(Path path1, Path path2, int operation) { throw UnimplementedError(); }
-
-  /// Creates a [PathMetrics] object for this path, which can describe various
-  /// properties about the contours of the path.
-  ///
-  /// A [Path] is made up of zero or more contours. A contour is made up of
-  /// connected curves and segments, created via methods like [lineTo],
-  /// [cubicTo], [arcTo], [quadraticBezierTo], their relative counterparts, as
-  /// well as the add* methods such as [addRect]. Creating a new [Path] starts
-  /// a new contour once it has any drawing instructions, and another new
-  /// contour is started for each [moveTo] instruction.
-  ///
-  /// A [PathMetric] object describes properties of an individual contour,
-  /// such as its length, whether it is closed, what the tangent vector of a
-  /// particular offset along the path is. It also provides a method for
-  /// creating sub-paths: [PathMetric.extractPath].
-  ///
-  /// Calculating [PathMetric] objects is not trivial. The [PathMetrics] object
-  /// returned by this method is a lazy [Iterable], meaning it only performs
-  /// calculations when the iterator is moved to the next [PathMetric]. Callers
-  /// that wish to memoize this iterable can easily do so by using
-  /// [Iterable.toList] on the result of this method. In particular, callers
-  /// looking for information about how many contours are in the path should
-  /// either store the result of `path.computeMetrics().length`, or should use
-  /// `path.computeMetrics().toList()` so they can repeatedly check the length,
-  /// since calling `Iterable.length` causes traversal of the entire iterable.
-  ///
-  /// In particular, callers should be aware that [PathMetrics.length] is the
-  /// number of contours, **not the length of the path**. To get the length of
-  /// a contour in a path, use [PathMetric.length].
-  ///
-  /// If `forceClosed` is set to true, the contours of the path will be measured
-  /// as if they had been closed, even if they were not explicitly closed.
   PathMetrics computeMetrics({bool forceClosed = false}) {
     return PathMetrics._(this, forceClosed);
   }
 }
-
-/// The geometric description of a tangent: the angle at a point.
-///
-/// See also:
-///  * [PathMetric.getTangentForOffset], which returns the tangent of an offset along a path.
 class Tangent {
-  /// Creates a [Tangent] with the given values.
-  ///
-  /// The arguments must not be null.
   const Tangent(this.position, this.vector)
     : assert(position != null), // ignore: unnecessary_null_comparison
       assert(vector != null); // ignore: unnecessary_null_comparison
-
-  /// Creates a [Tangent] based on the angle rather than the vector.
-  ///
-  /// The [vector] is computed to be the unit vector at the given angle, interpreted
-  /// as clockwise radians from the x axis.
   factory Tangent.fromAngle(Offset position, double angle) {
     return Tangent(position, Offset(math.cos(angle), math.sin(angle)));
   }
-
-  /// Position of the tangent.
-  ///
-  /// When used with [PathMetric.getTangentForOffset], this represents the precise
-  /// position that the given offset along the path corresponds to.
   final Offset position;
-
-  /// The vector of the curve at [position].
-  ///
-  /// When used with [PathMetric.getTangentForOffset], this is the vector of the
-  /// curve that is at the given offset along the path (i.e. the direction of the
-  /// curve at [position]).
   final Offset vector;
-
-  /// The direction of the curve at [position].
-  ///
-  /// When used with [PathMetric.getTangentForOffset], this is the angle of the
-  /// curve that is the given offset along the path (i.e. the direction of the
-  /// curve at [position]).
-  ///
-  /// This value is in radians, with 0.0 meaning pointing along the x axis in
-  /// the positive x-axis direction, positive numbers pointing downward toward
-  /// the negative y-axis, i.e. in a clockwise direction, and negative numbers
-  /// pointing upward toward the positive y-axis, i.e. in a counter-clockwise
-  /// direction.
   // flip the sign to be consistent with [Path.arcTo]'s `sweepAngle`
   double get angle => -math.atan2(vector.dy, vector.dx);
 }
-
-/// An iterable collection of [PathMetric] objects describing a [Path].
-///
-/// A [PathMetrics] object is created by using the [Path.computeMetrics] method,
-/// and represents the path as it stood at the time of the call. Subsequent
-/// modifications of the path do not affect the [PathMetrics] object.
-///
-/// Each path metric corresponds to a segment, or contour, of a path.
-///
-/// For example, a path consisting of a [Path.lineTo], a [Path.moveTo], and
-/// another [Path.lineTo] will contain two contours and thus be represented by
-/// two [PathMetric] objects.
-///
-/// This iterable does not memoize. Callers who need to traverse the list
-/// multiple times, or who need to randomly access elements of the list, should
-/// use [toList] on this object.
 class PathMetrics extends collection.IterableBase<PathMetric> {
   PathMetrics._(Path path, bool forceClosed) :
     _iterator = PathMetricIterator._(_PathMeasure(path, forceClosed));
@@ -2649,9 +1282,6 @@
   @override
   Iterator<PathMetric> get iterator => _iterator;
 }
-
-/// Used by [PathMetrics] to track iteration from one segment of a path to the
-/// next for measurement.
 class PathMetricIterator implements Iterator<PathMetric> {
   PathMetricIterator._(this._pathMeasure) : assert(_pathMeasure != null); // ignore: unnecessary_null_comparison
 
@@ -2681,73 +1311,20 @@
     return false;
   }
 }
-
-/// Utilities for measuring a [Path] and extracting sub-paths.
-///
-/// Iterate over the object returned by [Path.computeMetrics] to obtain
-/// [PathMetric] objects. Callers that want to randomly access elements or
-/// iterate multiple times should use `path.computeMetrics().toList()`, since
-/// [PathMetrics] does not memoize.
-///
-/// Once created, the metrics are only valid for the path as it was specified
-/// when [Path.computeMetrics] was called. If additional contours are added or
-/// any contours are updated, the metrics need to be recomputed. Previously
-/// created metrics will still refer to a snapshot of the path at the time they
-/// were computed, rather than to the actual metrics for the new mutations to
-/// the path.
 class PathMetric {
   PathMetric._(this._measure)
     : assert(_measure != null), // ignore: unnecessary_null_comparison
       length = _measure.length(_measure.currentContourIndex),
       isClosed = _measure.isClosed(_measure.currentContourIndex),
       contourIndex = _measure.currentContourIndex;
-
-  /// Return the total length of the current contour.
   final double length;
-
-  /// Whether the contour is closed.
-  ///
-  /// Returns true if the contour ends with a call to [Path.close] (which may
-  /// have been implied when using methods like [Path.addRect]) or if
-  /// `forceClosed` was specified as true in the call to [Path.computeMetrics].
-  /// Returns false otherwise.
   final bool isClosed;
-
-  /// The zero-based index of the contour.
-  ///
-  /// [Path] objects are made up of zero or more contours. The first contour is
-  /// created once a drawing command (e.g. [Path.lineTo]) is issued. A
-  /// [Path.moveTo] command after a drawing command may create a new contour,
-  /// although it may not if optimizations are applied that determine the move
-  /// command did not actually result in moving the pen.
-  ///
-  /// This property is only valid with reference to its original iterator and
-  /// the contours of the path at the time the path's metrics were computed. If
-  /// additional contours were added or existing contours updated, this metric
-  /// will be invalid for the current state of the path.
   final int contourIndex;
 
   final _PathMeasure _measure;
-
-
-  /// Computes the position of the current contour at the given offset, and the
-  /// angle of the path at that point.
-  ///
-  /// For example, calling this method with a distance of 1.41 for a line from
-  /// 0.0,0.0 to 2.0,2.0 would give a point 1.0,1.0 and the angle 45 degrees
-  /// (but in radians).
-  ///
-  /// Returns null if the contour has zero [length].
-  ///
-  /// The distance is clamped to the [length] of the current contour.
   Tangent? getTangentForOffset(double distance) {
     return _measure.getTangentForOffset(contourIndex, distance);
   }
-
-  /// Given a start and end distance, return the intervening segment(s).
-  ///
-  /// `start` and `end` are clamped to legal values (0..[length])
-  /// Begin the segment with a moveTo if `startWithMoveTo` is true.
   Path extractPath(double start, double end, {bool startWithMoveTo = true}) {
     return _measure.extractPath(contourIndex, start, end, startWithMoveTo: startWithMoveTo);
   }
@@ -2756,7 +1333,7 @@
   String toString() => '$runtimeType{length: $length, isClosed: $isClosed, contourIndex:$contourIndex}';
 }
 
-class _PathMeasure extends NativeFieldWrapperClass2 {
+class _PathMeasure {
   _PathMeasure(Path path, bool forceClosed) {
     _constructor(path, forceClosed);
   }
@@ -2809,61 +1386,17 @@
     return next;
   }
   bool _nativeNextContour() { throw UnimplementedError(); }
-
-  /// The index of the current contour in the list of contours in the path.
-  ///
-  /// [nextContour] will increment this to the zero based index.
   int currentContourIndex = -1;
 }
-
-/// Styles to use for blurs in [MaskFilter] objects.
 // These enum values must be kept in sync with SkBlurStyle.
 enum BlurStyle {
   // These mirror SkBlurStyle and must be kept in sync.
-
-  /// Fuzzy inside and outside. This is useful for painting shadows that are
-  /// offset from the shape that ostensibly is casting the shadow.
   normal,
-
-  /// Solid inside, fuzzy outside. This corresponds to drawing the shape, and
-  /// additionally drawing the blur. This can make objects appear brighter,
-  /// maybe even as if they were fluorescent.
   solid,
-
-  /// Nothing inside, fuzzy outside. This is useful for painting shadows for
-  /// partially transparent shapes, when they are painted separately but without
-  /// an offset, so that the shadow doesn't paint below the shape.
   outer,
-
-  /// Fuzzy inside, nothing outside. This can make shapes appear to be lit from
-  /// within.
   inner,
 }
-
-/// A mask filter to apply to shapes as they are painted. A mask filter is a
-/// function that takes a bitmap of color pixels, and returns another bitmap of
-/// color pixels.
-///
-/// Instances of this class are used with [Paint.maskFilter] on [Paint] objects.
 class MaskFilter {
-  /// Creates a mask filter that takes the shape being drawn and blurs it.
-  ///
-  /// This is commonly used to approximate shadows.
-  ///
-  /// The `style` argument controls the kind of effect to draw; see [BlurStyle].
-  ///
-  /// The `sigma` argument controls the size of the effect. It is the standard
-  /// deviation of the Gaussian blur to apply. The value must be greater than
-  /// zero. The sigma corresponds to very roughly half the radius of the effect
-  /// in pixels.
-  ///
-  /// A blur is an expensive operation and should therefore be used sparingly.
-  ///
-  /// The arguments must not be null.
-  ///
-  /// See also:
-  ///
-  ///  * [Canvas.drawShadow], which is a more efficient way to draw shadows.
   const MaskFilter.blur(
     this._style,
     this._sigma,
@@ -2891,105 +1424,22 @@
   @override
   String toString() => 'MaskFilter.blur($_style, ${_sigma.toStringAsFixed(1)})';
 }
-
-/// A description of a color filter to apply when drawing a shape or compositing
-/// a layer with a particular [Paint]. A color filter is a function that takes
-/// two colors, and outputs one color. When applied during compositing, it is
-/// independently applied to each pixel of the layer being drawn before the
-/// entire layer is merged with the destination.
-///
-/// Instances of this class are used with [Paint.colorFilter] on [Paint]
-/// objects.
 class ColorFilter implements ImageFilter {
-  /// Creates a color filter that applies the blend mode given as the second
-  /// argument. The source color is the one given as the first argument, and the
-  /// destination color is the one from the layer being composited.
-  ///
-  /// The output of this filter is then composited into the background according
-  /// to the [Paint.blendMode], using the output of this filter as the source
-  /// and the background as the destination.
   const ColorFilter.mode(Color color, BlendMode blendMode)
       : _color = color,
         _blendMode = blendMode,
         _matrix = null,
         _type = _kTypeMode;
-
-  /// Construct a color filter that transforms a color by a 5x5 matrix, where
-  /// the fifth row is implicitly added in an identity configuration.
-  ///
-  /// Every pixel's color value, repsented as an `[R, G, B, A]`, is matrix
-  /// multiplied to create a new color:
-  ///
-  /// ```text
-  /// | R' |   | a00 a01 a02 a03 a04 |   | R |
-  /// | G' |   | a10 a11 a22 a33 a44 |   | G |
-  /// | B' | = | a20 a21 a22 a33 a44 | * | B |
-  /// | A' |   | a30 a31 a22 a33 a44 |   | A |
-  /// | 1  |   |  0   0   0   0   1  |   | 1 |
-  /// ```
-  ///
-  /// The matrix is in row-major order and the translation column is specified
-  /// in unnormalized, 0...255, space. For example, the identity matrix is:
-  ///
-  /// ```
-  /// const ColorFilter identity = ColorFilter.matrix(<double>[
-  ///   1, 0, 0, 0, 0,
-  ///   0, 1, 0, 0, 0,
-  ///   0, 0, 1, 0, 0,
-  ///   0, 0, 0, 1, 0,
-  /// ]);
-  /// ```
-  ///
-  /// ## Examples
-  ///
-  /// An inversion color matrix:
-  ///
-  /// ```
-  /// const ColorFilter invert = ColorFilter.matrix(<double>[
-  ///   -1,  0,  0, 0, 255,
-  ///    0, -1,  0, 0, 255,
-  ///    0,  0, -1, 0, 255,
-  ///    0,  0,  0, 1,   0,
-  /// ]);
-  /// ```
-  ///
-  /// A sepia-toned color matrix (values based on the [Filter Effects Spec](https://www.w3.org/TR/filter-effects-1/#sepiaEquivalent)):
-  ///
-  /// ```
-  /// const ColorFilter sepia = ColorFilter.matrix(<double>[
-  ///   0.393, 0.769, 0.189, 0, 0,
-  ///   0.349, 0.686, 0.168, 0, 0,
-  ///   0.272, 0.534, 0.131, 0, 0,
-  ///   0,     0,     0,     1, 0,
-  /// ]);
-  /// ```
-  ///
-  /// A greyscale color filter (values based on the [Filter Effects Spec](https://www.w3.org/TR/filter-effects-1/#grayscaleEquivalent)):
-  ///
-  /// ```
-  /// const ColorFilter greyscale = ColorFilter.matrix(<double>[
-  ///   0.2126, 0.7152, 0.0722, 0, 0,
-  ///   0.2126, 0.7152, 0.0722, 0, 0,
-  ///   0.2126, 0.7152, 0.0722, 0, 0,
-  ///   0,      0,      0,      1, 0,
-  /// ]);
-  /// ```
   const ColorFilter.matrix(List<double> matrix)
       : _color = null,
         _blendMode = null,
         _matrix = matrix,
         _type = _kTypeMatrix;
-
-  /// Construct a color filter that applies the sRGB gamma curve to the RGB
-  /// channels.
   const ColorFilter.linearToSrgbGamma()
       : _color = null,
         _blendMode = null,
         _matrix = null,
         _type = _kTypeLinearToSrgbGamma;
-
-  /// Creates a color filter that applies the inverse of the sRGB gamma curve
-  /// to the RGB channels.
   const ColorFilter.srgbToLinearGamma()
       : _color = null,
         _blendMode = null,
@@ -3079,14 +1529,7 @@
     }
   }
 }
-
-/// A [ColorFilter] that is backed by a native SkColorFilter.
-///
-/// This is a private class, rather than being the implementation of the public
-/// ColorFilter, because we want ColorFilter to be const constructible and
-/// efficiently comparable, so that widgets can check for ColorFilter equality to
-/// avoid repainting.
-class _ColorFilter extends NativeFieldWrapperClass2 {
+class _ColorFilter {
   _ColorFilter.mode(this.creator)
     : assert(creator != null), // ignore: unnecessary_null_comparison
       assert(creator._type == ColorFilter._kTypeMode) {
@@ -3113,9 +1556,6 @@
     _constructor();
     _initSrgbToLinearGamma();
   }
-
-  /// The original Dart object that created the native wrapper, which retains
-  /// the values used for the filter.
   final ColorFilter creator;
 
   void _constructor() { throw UnimplementedError(); }
@@ -3124,30 +1564,13 @@
   void _initLinearToSrgbGamma() { throw UnimplementedError(); }
   void _initSrgbToLinearGamma() { throw UnimplementedError(); }
 }
-
-/// A filter operation to apply to a raster image.
-///
-/// See also:
-///
-///  * [BackdropFilter], a widget that applies [ImageFilter] to its rendering.
-///  * [ImageFiltered], a widget that applies [ImageFilter] to its children.
-///  * [SceneBuilder.pushBackdropFilter], which is the low-level API for using
-///    this class as a backdrop filter.
-///  * [SceneBuilder.pushImageFilter], which is the low-level API for using
-///    this class as a child layer filter.
 abstract class ImageFilter {
-  /// Creates an image filter that applies a Gaussian blur.
   factory ImageFilter.blur({ double sigmaX = 0.0, double sigmaY = 0.0, TileMode tileMode = TileMode.clamp }) {
     assert(sigmaX != null); // ignore: unnecessary_null_comparison
     assert(sigmaY != null); // ignore: unnecessary_null_comparison
     assert(tileMode != null); // ignore: unnecessary_null_comparison
     return _GaussianBlurImageFilter(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode);
   }
-
-  /// Creates an image filter that applies a matrix transformation.
-  ///
-  /// For example, applying a positive scale matrix (see [Matrix4.diagonal3])
-  /// when used with [BackdropFilter] would magnify the background image.
   factory ImageFilter.matrix(Float64List matrix4,
                      { FilterQuality filterQuality = FilterQuality.low }) {
     assert(matrix4 != null);       // ignore: unnecessary_null_comparison
@@ -3156,12 +1579,6 @@
       throw ArgumentError('"matrix4" must have 16 entries.');
     return _MatrixImageFilter(data: Float64List.fromList(matrix4), filterQuality: filterQuality);
   }
-
-  /// Composes the `inner` filter with `outer`, to combine their effects.
-  ///
-  /// Creates a single [ImageFilter] that when applied, has the same effect as
-  /// subsequently applying `inner` and `outer`, i.e.,
-  /// result = outer(inner(source)).
   factory ImageFilter.compose({ required ImageFilter outer, required ImageFilter inner }) {
     assert (inner != null && outer != null);  // ignore: unnecessary_null_comparison
     return _ComposeImageFilter(innerFilter: inner, outerFilter: outer);
@@ -3276,16 +1693,8 @@
   @override
   int get hashCode => hashValues(innerFilter, outerFilter);
 }
-
-/// An [ImageFilter] that is backed by a native SkImageFilter.
-///
-/// This is a private class, rather than being the implementation of the public
-/// ImageFilter, because we want ImageFilter to be efficiently comparable, so that
-/// widgets can check for ImageFilter equality to avoid repainting.
-class _ImageFilter extends NativeFieldWrapperClass2 {
+class _ImageFilter {
   void _constructor() { throw UnimplementedError(); }
-
-  /// Creates an image filter that applies a Gaussian blur.
   _ImageFilter.blur(_GaussianBlurImageFilter filter)
     : assert(filter != null), // ignore: unnecessary_null_comparison
       creator = filter {    // ignore: prefer_initializing_formals
@@ -3293,11 +1702,6 @@
     _initBlur(filter.sigmaX, filter.sigmaY, filter.tileMode.index);
   }
   void _initBlur(double sigmaX, double sigmaY, int tileMode) { throw UnimplementedError(); }
-
-  /// Creates an image filter that applies a matrix transformation.
-  ///
-  /// For example, applying a positive scale matrix (see [Matrix4.diagonal3])
-  /// when used with [BackdropFilter] would magnify the background image.
   _ImageFilter.matrix(_MatrixImageFilter filter)
     : assert(filter != null), // ignore: unnecessary_null_comparison
       creator = filter {    // ignore: prefer_initializing_formals
@@ -3307,8 +1711,6 @@
     _initMatrix(filter.data, filter.filterQuality.index);
   }
   void _initMatrix(Float64List matrix4, int filterQuality) { throw UnimplementedError(); }
-
-  /// Converts a color filter to an image filter.
   _ImageFilter.fromColorFilter(ColorFilter filter)
     : assert(filter != null), // ignore: unnecessary_null_comparison
       creator = filter {    // ignore: prefer_initializing_formals
@@ -3317,8 +1719,6 @@
     _initColorFilter(nativeFilter);
   }
   void _initColorFilter(_ColorFilter? colorFilter) { throw UnimplementedError(); }
-
-  /// Composes `_innerFilter` with `_outerFilter`.
   _ImageFilter.composed(_ComposeImageFilter filter)
     : assert(filter != null), // ignore: unnecessary_null_comparison
       creator = filter {    // ignore: prefer_initializing_formals
@@ -3328,100 +1728,16 @@
     _initComposed(nativeFilterOuter,  nativeFilterInner);
   }
   void _initComposed(_ImageFilter outerFilter, _ImageFilter innerFilter) { throw UnimplementedError(); }
-  /// The original Dart object that created the native wrapper, which retains
-  /// the values used for the filter.
   final ImageFilter creator;
 }
-
-/// Base class for objects such as [Gradient] and [ImageShader] which
-/// correspond to shaders as used by [Paint.shader].
-class Shader extends NativeFieldWrapperClass2 {
-  /// This class is created by the engine, and should not be instantiated
-  /// or extended directly.
-  @pragma('vm:entry-point')
-  Shader._();
+class Shader {
+    Shader._();
 }
-
-/// Defines what happens at the edge of a gradient or the sampling of a source image
-/// in an [ImageFilter].
-///
-/// A gradient is defined along a finite inner area. In the case of a linear
-/// gradient, it's between the parallel lines that are orthogonal to the line
-/// drawn between two points. In the case of radial gradients, it's the disc
-/// that covers the circle centered on a particular point up to a given radius.
-///
-/// An image filter reads source samples from a source image and performs operations
-/// on those samples to produce a result image. An image defines color samples only
-/// for pixels within the bounds of the image but some filter operations, such as a blur
-/// filter, read samples over a wide area to compute the output for a given pixel. Such
-/// a filter would need to combine samples from inside the image with hypothetical
-/// color values from outside the image.
-///
-/// This enum is used to define how the gradient or image filter should treat the regions
-/// outside that defined inner area.
-///
-/// See also:
-///
-///  * [painting.Gradient], the superclass for [LinearGradient] and
-///    [RadialGradient], as used by [BoxDecoration] et al, which works in
-///    relative coordinates and can create a [Shader] representing the gradient
-///    for a particular [Rect] on demand.
-///  * [dart:ui.Gradient], the low-level class used when dealing with the
-///    [Paint.shader] property directly, with its [Gradient.linear] and
-///    [Gradient.radial] constructors.
-///  * [dart:ui.ImageFilter.blur], an ImageFilter that may sometimes need to
-///    read samples from outside an image to combine with the pixels near the
-///    edge of the image.
 // These enum values must be kept in sync with SkTileMode.
 enum TileMode {
-  /// Samples beyond the edge are clamped to the nearest color in the defined inner area.
-  ///
-  /// A gradient will paint all the regions outside the inner area with the
-  /// color at the end of the color stop list closest to that region.
-  ///
-  /// An image filter will substitute the nearest edge pixel for any samples taken from
-  /// outside its source image.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_linear.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_radial.png)
   clamp,
-
-  /// Samples beyond the edge are repeated from the far end of the defined area.
-  ///
-  /// For a gradient, this technique is as if the stop points from 0.0 to 1.0 were then
-  /// repeated from 1.0 to 2.0, 2.0 to 3.0, and so forth (and for linear gradients, similarly
-  /// from -1.0 to 0.0, -2.0 to -1.0, etc).
-  ///
-  /// An image filter will treat its source image as if it were tiled across the enlarged
-  /// sample space from which it reads, each tile in the same orientation as the base image.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_linear.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_radial.png)
   repeated,
-
-  /// Samples beyond the edge are mirrored back and forth across the defined area.
-  ///
-  /// For a gradient, this technique is as if the stop points from 0.0 to 1.0 were then
-  /// repeated backwards from 2.0 to 1.0, then forwards from 2.0 to 3.0, then backwards
-  /// again from 4.0 to 3.0, and so forth (and for linear gradients, similarly in the
-  /// negative direction).
-  ///
-  /// An image filter will treat its source image as tiled in an alternating forwards and
-  /// backwards or upwards and downwards direction across the sample space from which
-  /// it is reading.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_linear.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_radial.png)
   mirror,
-
-  /// Samples beyond the edge are treated as transparent black.
-  ///
-  /// A gradient will render transparency over any region that is outside the circle of a
-  /// radial gradient or outside the parallel lines that define the inner area of a linear
-  /// gradient.
-  ///
-  /// An image filter will substitute transparent black for any sample it must read from
-  /// outside its source image.
   decal,
 }
 
@@ -3458,41 +1774,9 @@
   result[3] = pointB.dy;
   return result;
 }
-
-/// A shader (as used by [Paint.shader]) that renders a color gradient.
-///
-/// There are several types of gradients, represented by the various constructors
-/// on this class.
-///
-/// See also:
-///
-///  * [Gradient](https://api.flutter.dev/flutter/painting/Gradient-class.html), the class in the [painting] library.
-///
 class Gradient extends Shader {
 
   void _constructor() { throw UnimplementedError(); }
-
-  /// Creates a linear gradient from `from` to `to`.
-  ///
-  /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0
-  /// that specifies where `color[i]` begins in the gradient. If `colorStops` is
-  /// not provided, then only two stops, at 0.0 and 1.0, are implied (and
-  /// `color` must therefore only have two entries).
-  ///
-  /// The behavior before `from` and after `to` is described by the `tileMode`
-  /// argument. For details, see the [TileMode] enum.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_linear.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_linear.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_linear.png)
-  ///
-  /// If `from`, `to`, `colors`, or `tileMode` are null, or if `colors` or
-  /// `colorStops` contain null values, this constructor will throw a
-  /// [NoSuchMethodError].
-  ///
-  /// If `matrix4` is provided, the gradient fill will be transformed by the
-  /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must
-  /// be a column-major matrix packed into a list of 16 values.
   Gradient.linear(
     Offset from,
     Offset to,
@@ -3514,36 +1798,6 @@
     _initLinear(endPointsBuffer, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4);
   }
   void _initLinear(Float32List endPoints, Int32List colors, Float32List? colorStops, int tileMode, Float64List? matrix4) { throw UnimplementedError(); }
-
-  /// Creates a radial gradient centered at `center` that ends at `radius`
-  /// distance from the center.
-  ///
-  /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0
-  /// that specifies where `color[i]` begins in the gradient. If `colorStops` is
-  /// not provided, then only two stops, at 0.0 and 1.0, are implied (and
-  /// `color` must therefore only have two entries).
-  ///
-  /// The behavior before and after the radius is described by the `tileMode`
-  /// argument. For details, see the [TileMode] enum.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_radial.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_radial.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_radial.png)
-  ///
-  /// If `center`, `radius`, `colors`, or `tileMode` are null, or if `colors` or
-  /// `colorStops` contain null values, this constructor will throw a
-  /// [NoSuchMethodError].
-  ///
-  /// If `matrix4` is provided, the gradient fill will be transformed by the
-  /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must
-  /// be a column-major matrix packed into a list of 16 values.
-  ///
-  /// If `focal` is provided and not equal to `center` and `focalRadius` is
-  /// provided and not equal to 0.0, the generated shader will be a two point
-  /// conical radial gradient, with `focal` being the center of the focal
-  /// circle and `focalRadius` being the radius of that circle. If `focal` is
-  /// provided and not equal to `center`, at least one of the two offsets must
-  /// not be equal to [Offset.zero].
   Gradient.radial(
     Offset center,
     double radius,
@@ -3575,33 +1829,6 @@
   }
   void _initRadial(double centerX, double centerY, double radius, Int32List colors, Float32List? colorStops, int tileMode, Float64List? matrix4) { throw UnimplementedError(); }
   void _initConical(double startX, double startY, double startRadius, double endX, double endY, double endRadius, Int32List colors, Float32List? colorStops, int tileMode, Float64List? matrix4) { throw UnimplementedError(); }
-
-  /// Creates a sweep gradient centered at `center` that starts at `startAngle`
-  /// and ends at `endAngle`.
-  ///
-  /// `startAngle` and `endAngle` should be provided in radians, with zero
-  /// radians being the horizontal line to the right of the `center` and with
-  /// positive angles going clockwise around the `center`.
-  ///
-  /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0
-  /// that specifies where `color[i]` begins in the gradient. If `colorStops` is
-  /// not provided, then only two stops, at 0.0 and 1.0, are implied (and
-  /// `color` must therefore only have two entries).
-  ///
-  /// The behavior before `startAngle` and after `endAngle` is described by the
-  /// `tileMode` argument. For details, see the [TileMode] enum.
-  ///
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_sweep.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_sweep.png)
-  /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_sweep.png)
-  ///
-  /// If `center`, `colors`, `tileMode`, `startAngle`, or `endAngle` are null,
-  /// or if `colors` or `colorStops` contain null values, this constructor will
-  /// throw a [NoSuchMethodError].
-  ///
-  /// If `matrix4` is provided, the gradient fill will be transformed by the
-  /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must
-  /// be a column-major matrix packed into a list of 16 values.
   Gradient.sweep(
     Offset center,
     List<Color> colors, [
@@ -3636,16 +1863,8 @@
     }
   }
 }
-
-/// A shader (as used by [Paint.shader]) that tiles an image.
 class ImageShader extends Shader {
-  /// Creates an image-tiling shader. The first argument specifies the image to
-  /// tile. The second and third arguments specify the [TileMode] for the x
-  /// direction and y direction respectively. The fourth argument gives the
-  /// matrix to apply to the effect. All the arguments are required and must not
-  /// be null.
-  @pragma('vm:entry-point')
-  ImageShader(Image image, TileMode tmx, TileMode tmy, Float64List matrix4) :
+    ImageShader(Image image, TileMode tmx, TileMode tmy, Float64List matrix4) :
     // ignore: unnecessary_null_comparison
     assert(image != null), // image is checked on the engine side
     assert(tmx != null), // ignore: unnecessary_null_comparison
@@ -3660,33 +1879,13 @@
   void _constructor() { throw UnimplementedError(); }
   void _initWithImage(_Image image, int tmx, int tmy, Float64List matrix4) { throw UnimplementedError(); }
 }
-
-/// Defines how a list of points is interpreted when drawing a set of triangles.
-///
-/// Used by [Canvas.drawVertices].
 // These enum values must be kept in sync with SkVertices::VertexMode.
 enum VertexMode {
-  /// Draw each sequence of three points as the vertices of a triangle.
   triangles,
-
-  /// Draw each sliding window of three points as the vertices of a triangle.
   triangleStrip,
-
-  /// Draw the first point and each sliding window of two points as the vertices of a triangle.
   triangleFan,
 }
-
-/// A set of vertex data used by [Canvas.drawVertices].
-class Vertices extends NativeFieldWrapperClass2 {
-  /// Creates a set of vertex data for use with [Canvas.drawVertices].
-  ///
-  /// The [mode] and [positions] parameters must not be null.
-  ///
-  /// If the [textureCoordinates] or [colors] parameters are provided, they must
-  /// be the same length as [positions].
-  ///
-  /// If the [indices] parameter is provided, all values in the list must be
-  /// valid index values for [positions].
+class Vertices {
   Vertices(
     VertexMode mode,
     List<Offset> positions, {
@@ -3716,25 +1915,6 @@
     if (!_init(this, mode.index, encodedPositions, encodedTextureCoordinates, encodedColors, encodedIndices))
       throw ArgumentError('Invalid configuration for vertices.');
   }
-
-  /// Creates a set of vertex data for use with [Canvas.drawVertices], directly
-  /// using the encoding methods of [new Vertices].
-  ///
-  /// The [mode] parameter must not be null.
-  ///
-  /// The [positions] list is interpreted as a list of repeated pairs of x,y
-  /// coordinates. It must not be null.
-  ///
-  /// The [textureCoordinates] list is interpreted as a list of repeated pairs
-  /// of x,y coordinates, and must be the same length of [positions] if it
-  /// is not null.
-  ///
-  /// The [colors] list is interpreted as a list of RGBA encoded colors, similar
-  /// to [Color.value]. It must be half length of [positions] if it is not
-  /// null.
-  ///
-  /// If the [indices] list is provided, all values in the list must be
-  /// valid index values for [positions].
   Vertices.raw(
     VertexMode mode,
     Float32List positions, {
@@ -3761,814 +1941,517 @@
              Int32List? colors,
              Uint16List? indices) { throw UnimplementedError(); }
 }
-
-/// Defines how a list of points is interpreted when drawing a set of points.
-///
 // ignore: deprecated_member_use
-/// Used by [Canvas.drawPoints].
 // These enum values must be kept in sync with SkCanvas::PointMode.
 enum PointMode {
-  /// Draw each point separately.
-  ///
-  /// If the [Paint.strokeCap] is [StrokeCap.round], then each point is drawn
-  /// as a circle with the diameter of the [Paint.strokeWidth], filled as
-  /// described by the [Paint] (ignoring [Paint.style]).
-  ///
-  /// Otherwise, each point is drawn as an axis-aligned square with sides of
-  /// length [Paint.strokeWidth], filled as described by the [Paint] (ignoring
-  /// [Paint.style]).
   points,
-
-  /// Draw each sequence of two points as a line segment.
-  ///
-  /// If the number of points is odd, then the last point is ignored.
-  ///
-  /// The lines are stroked as described by the [Paint] (ignoring
-  /// [Paint.style]).
   lines,
-
-  /// Draw the entire sequence of point as one line.
-  ///
-  /// The lines are stroked as described by the [Paint] (ignoring
-  /// [Paint.style]).
   polygon,
 }
-
-/// Defines how a new clip region should be merged with the existing clip
-/// region.
-///
-/// Used by [Canvas.clipRect].
 enum ClipOp {
-  /// Subtract the new region from the existing region.
   difference,
-
-  /// Intersect the new region from the existing region.
   intersect,
 }
 
-/// An interface for recording graphical operations.
-///
-/// [Canvas] objects are used in creating [Picture] objects, which can
-/// themselves be used with a [SceneBuilder] to build a [Scene]. In
-/// normal usage, however, this is all handled by the framework.
-///
-/// A canvas has a current transformation matrix which is applied to all
-/// operations. Initially, the transformation matrix is the identity transform.
-/// It can be modified using the [translate], [scale], [rotate], [skew],
-/// and [transform] methods.
-///
-/// A canvas also has a current clip region which is applied to all operations.
-/// Initially, the clip region is infinite. It can be modified using the
-/// [clipRect], [clipRRect], and [clipPath] methods.
-///
-/// The current transform and clip can be saved and restored using the stack
-/// managed by the [save], [saveLayer], and [restore] methods.
-class Canvas extends NativeFieldWrapperClass2 {
-  /// Creates a canvas for recording graphical operations into the
-  /// given picture recorder.
-  ///
-  /// Graphical operations that affect pixels entirely outside the given
-  /// `cullRect` might be discarded by the implementation. However, the
-  /// implementation might draw outside these bounds if, for example, a command
-  /// draws partially inside and outside the `cullRect`. To ensure that pixels
-  /// outside a given region are discarded, consider using a [clipRect]. The
-  /// `cullRect` is optional; by default, all operations are kept.
-  ///
-  /// To end the recording, call [PictureRecorder.endRecording] on the
-  /// given recorder.
-  @pragma('vm:entry-point')
-  Canvas(PictureRecorder recorder, [ Rect? cullRect ]) : assert(recorder != null) { // ignore: unnecessary_null_comparison
-    if (recorder.isRecording)
+class _CanvasMethods {
+  static const int save = 0;
+  static const int saveLayer = 1;
+  static const int restore = 2;
+  static const int translate = 3;
+  static const int scale = 4;
+  static const int rotate = 5;
+  static const int skew = 6;
+  static const int transform = 7;
+  static const int clipRect = 8;
+  static const int clipRRect = 9;
+  static const int clipPath = 10;
+  static const int drawColor = 11;
+  static const int drawLine = 12;
+  static const int drawPaint = 13;
+  static const int drawRect = 14;
+  static const int drawRRect = 15;
+  static const int drawDRRect = 16;
+  static const int drawOval = 17;
+  static const int drawCircle = 18;
+  static const int drawArc = 19;
+  static const int drawPath = 20;
+  static const int drawImage = 21;
+  static const int drawImageRect = 22;
+  static const int drawImageNine = 23;
+  static const int drawPicture = 24;
+  static const int drawParagraph = 25;
+  static const int drawPoints = 26;
+  static const int drawVertices = 27;
+  static const int drawAtlas = 28;
+  static const int drawShadow = 29;
+}
+class Canvas {
+  Canvas(this._recorder, [ Rect? cullRect ]) : _cullRect = cullRect ?? Rect.largest, assert(_recorder != null) { // ignore: unnecessary_null_comparison
+    if (_recorder!.isRecording)
       throw ArgumentError('"recorder" must not already be associated with another Canvas.');
-    _recorder = recorder;
     _recorder!._canvas = this;
-    cullRect ??= Rect.largest;
-    _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom);
   }
-  void _constructor(PictureRecorder recorder,
-                    double left,
-                    double top,
-                    double right,
-                    double bottom) { throw UnimplementedError(); }
 
   // The underlying Skia SkCanvas is owned by the PictureRecorder used to create this Canvas.
   // The Canvas holds a reference to the PictureRecorder to prevent the recorder from being
   // garbage collected until PictureRecorder.endRecording is called.
   PictureRecorder? _recorder;
+  final Rect _cullRect;
 
-  /// Saves a copy of the current transform and clip on the save stack.
-  ///
-  /// Call [restore] to pop the save stack.
-  ///
-  /// See also:
-  ///
-  ///  * [saveLayer], which does the same thing but additionally also groups the
-  ///    commands done until the matching [restore].
-  void save() { throw UnimplementedError(); }
+  double _currentX = 0;
+  double _currentY = 0;
+  Uint8List _methods = Uint8List(10);
+  int _methodsLength = 0;
+  Float32List _data = Float32List(30);
+  int _dataLength = 0;
+  List<Object> _objects = <Object>[];
+  bool _isEmpty = true;
+  double _left = 0;
+  double _top = 0;
+  double _right = 0;
+  double _bottom = 0;
+  int _saveCount = 0;
 
-  /// Saves a copy of the current transform and clip on the save stack, and then
-  /// creates a new group which subsequent calls will become a part of. When the
-  /// save stack is later popped, the group will be flattened into a layer and
-  /// have the given `paint`'s [Paint.colorFilter] and [Paint.blendMode]
-  /// applied.
-  ///
-  /// This lets you create composite effects, for example making a group of
-  /// drawing commands semi-transparent. Without using [saveLayer], each part of
-  /// the group would be painted individually, so where they overlap would be
-  /// darker than where they do not. By using [saveLayer] to group them
-  /// together, they can be drawn with an opaque color at first, and then the
-  /// entire group can be made transparent using the [saveLayer]'s paint.
-  ///
-  /// Call [restore] to pop the save stack and apply the paint to the group.
-  ///
-  /// ## Using saveLayer with clips
-  ///
-  /// When a rectangular clip operation (from [clipRect]) is not axis-aligned
-  /// with the raster buffer, or when the clip operation is not rectilinear
-  /// (e.g. because it is a rounded rectangle clip created by [clipRRect] or an
-  /// arbitrarily complicated path clip created by [clipPath]), the edge of the
-  /// clip needs to be anti-aliased.
-  ///
-  /// If two draw calls overlap at the edge of such a clipped region, without
-  /// using [saveLayer], the first drawing will be anti-aliased with the
-  /// background first, and then the second will be anti-aliased with the result
-  /// of blending the first drawing and the background. On the other hand, if
-  /// [saveLayer] is used immediately after establishing the clip, the second
-  /// drawing will cover the first in the layer, and thus the second alone will
-  /// be anti-aliased with the background when the layer is clipped and
-  /// composited (when [restore] is called).
-  ///
-  /// For example, this [CustomPainter.paint] method paints a clean white
-  /// rounded rectangle:
-  ///
-  /// ```dart
-  /// void paint(Canvas canvas, Size size) {
-  ///   Rect rect = Offset.zero & size;
-  ///   canvas.save();
-  ///   canvas.clipRRect(new RRect.fromRectXY(rect, 100.0, 100.0));
-  ///   canvas.saveLayer(rect, Paint());
-  ///   canvas.drawPaint(new Paint()..color = Colors.red);
-  ///   canvas.drawPaint(new Paint()..color = Colors.white);
-  ///   canvas.restore();
-  ///   canvas.restore();
-  /// }
-  /// ```
-  ///
-  /// On the other hand, this one renders a red outline, the result of the red
-  /// paint being anti-aliased with the background at the clip edge, then the
-  /// white paint being similarly anti-aliased with the background _including
-  /// the clipped red paint_:
-  ///
-  /// ```dart
-  /// void paint(Canvas canvas, Size size) {
-  ///   // (this example renders poorly, prefer the example above)
-  ///   Rect rect = Offset.zero & size;
-  ///   canvas.save();
-  ///   canvas.clipRRect(new RRect.fromRectXY(rect, 100.0, 100.0));
-  ///   canvas.drawPaint(new Paint()..color = Colors.red);
-  ///   canvas.drawPaint(new Paint()..color = Colors.white);
-  ///   canvas.restore();
-  /// }
-  /// ```
-  ///
-  /// This point is moot if the clip only clips one draw operation. For example,
-  /// the following paint method paints a pair of clean white rounded
-  /// rectangles, even though the clips are not done on a separate layer:
-  ///
-  /// ```dart
-  /// void paint(Canvas canvas, Size size) {
-  ///   canvas.save();
-  ///   canvas.clipRRect(new RRect.fromRectXY(Offset.zero & (size / 2.0), 50.0, 50.0));
-  ///   canvas.drawPaint(new Paint()..color = Colors.white);
-  ///   canvas.restore();
-  ///   canvas.save();
-  ///   canvas.clipRRect(new RRect.fromRectXY(size.center(Offset.zero) & (size / 2.0), 50.0, 50.0));
-  ///   canvas.drawPaint(new Paint()..color = Colors.white);
-  ///   canvas.restore();
-  /// }
-  /// ```
-  ///
-  /// (Incidentally, rather than using [clipRRect] and [drawPaint] to draw
-  /// rounded rectangles like this, prefer the [drawRRect] method. These
-  /// examples are using [drawPaint] as a proxy for "complicated draw operations
-  /// that will get clipped", to illustrate the point.)
-  ///
-  /// ## Performance considerations
-  ///
-  /// Generally speaking, [saveLayer] is relatively expensive.
-  ///
-  /// There are a several different hardware architectures for GPUs (graphics
-  /// processing units, the hardware that handles graphics), but most of them
-  /// involve batching commands and reordering them for performance. When layers
-  /// are used, they cause the rendering pipeline to have to switch render
-  /// target (from one layer to another). Render target switches can flush the
-  /// GPU's command buffer, which typically means that optimizations that one
-  /// could get with larger batching are lost. Render target switches also
-  /// generate a lot of memory churn because the GPU needs to copy out the
-  /// current frame buffer contents from the part of memory that's optimized for
-  /// writing, and then needs to copy it back in once the previous render target
-  /// (layer) is restored.
-  ///
-  /// See also:
-  ///
-  ///  * [save], which saves the current state, but does not create a new layer
-  ///    for subsequent commands.
-  ///  * [BlendMode], which discusses the use of [Paint.blendMode] with
-  ///    [saveLayer].
-  void saveLayer(Rect? bounds, Paint paint) {
-    assert(paint != null); // ignore: unnecessary_null_comparison
-    if (bounds == null) {
-      _saveLayerWithoutBounds(paint._objects, paint._data);
+  void _updateBounds(double x, double y) {
+    if (_isEmpty) {
+      _left = _right = x;
+      _top = _bottom = y;
+      _isEmpty = false;
     } else {
-      assert(_rectIsValid(bounds));
-      _saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
-                 paint._objects, paint._data);
+      if (x < _left) {
+        _left = x;
+      }
+      if (x > _right) {
+        _right = x;
+      }
+      if (y < _top) {
+        _top = y;
+      }
+      if (y > _bottom) {
+        _bottom = y;
+      }
     }
   }
-  void _saveLayerWithoutBounds(List<dynamic>? paintObjects, ByteData paintData)
-      { throw UnimplementedError(); }
-  void _saveLayer(double left,
-                  double top,
-                  double right,
-                  double bottom,
-                  List<dynamic>? paintObjects,
-                  ByteData paintData) { throw UnimplementedError(); }
 
-  /// Pops the current save stack, if there is anything to pop.
-  /// Otherwise, does nothing.
-  ///
-  /// Use [save] and [saveLayer] to push state onto the stack.
-  ///
-  /// If the state was pushed with with [saveLayer], then this call will also
-  /// cause the new layer to be composited into the previous layer.
-  void restore() { throw UnimplementedError(); }
+  _updateBoundsFromCurrent() {
+    _updateBounds(_currentX, _currentY);
+  }
 
-  /// Returns the number of items on the save stack, including the
-  /// initial state. This means it returns 1 for a clean canvas, and
-  /// that each call to [save] and [saveLayer] increments it, and that
-  /// each matching call to [restore] decrements it.
-  ///
-  /// This number cannot go below 1.
-  int getSaveCount() { throw UnimplementedError(); }
+  void _addObject(Object object) {
+    _objects.add(object);
+  }
 
-  /// Add a translation to the current transform, shifting the coordinate space
-  /// horizontally by the first argument and vertically by the second argument.
-  void translate(double dx, double dy) { throw UnimplementedError(); }
+  void _addMethod(int methodId) {
+    if (_methodsLength >= _methods.length) {
+      final Uint8List newList = Uint8List(_methods.length * 2);
+      for (int i = 0; i < _methodsLength; i++) {
+        newList[i] = _methods[i];
+      }
+      _methods = newList;
+    }
+    _methods[_methodsLength] = methodId;
+    _methodsLength += 1;
+  }
 
-  /// Add an axis-aligned scale to the current transform, scaling by the first
-  /// argument in the horizontal direction and the second in the vertical
-  /// direction.
-  ///
-  /// If [sy] is unspecified, [sx] will be used for the scale in both
-  /// directions.
-  void scale(double sx, [double? sy]) => _scale(sx, sy ?? sx);
+  void _ensureDataLength(int newLength) {
+    if (_data.length >= newLength) {
+      return;
+    }
 
-  void _scale(double sx, double sy) { throw UnimplementedError(); }
+    final Float32List newList = Float32List(_data.length * 2);
+    for (int i = 0; i < _dataLength; i++) {
+      newList[i] = _data[i];
+    }
+    _data = newList;
+  }
 
-  /// Add a rotation to the current transform. The argument is in radians clockwise.
-  void rotate(double radians) { throw UnimplementedError(); }
+  void _addData1(double a) {
+    _ensureDataLength(_dataLength + 1);
+    _data[_dataLength++] = a;
+  }
 
-  /// Add an axis-aligned skew to the current transform, with the first argument
-  /// being the horizontal skew in rise over run units clockwise around the
-  /// origin, and the second argument being the vertical skew in rise over run
-  /// units clockwise around the origin.
-  void skew(double sx, double sy) { throw UnimplementedError(); }
+  void _addData2(double a, double b) {
+    _ensureDataLength(_dataLength + 2);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+  }
 
-  /// Multiply the current transform by the specified 4⨉4 transformation matrix
-  /// specified as a list of values in column-major order.
+  void _addData4(double a, double b, double c, double d) {
+    _ensureDataLength(_dataLength + 4);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+  }
+
+  void _addData5(double a, double b, double c, double d, double e) {
+    _ensureDataLength(_dataLength + 5);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+    _data[_dataLength++] = e;
+  }
+
+  void _addData6(double a, double b, double c, double d, double e, double f) {
+    _ensureDataLength(_dataLength + 6);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+    _data[_dataLength++] = e;
+    _data[_dataLength++] = f;
+  }
+
+  void _addData7(double a, double b, double c, double d, double e, double f, double g) {
+    _ensureDataLength(_dataLength + 7);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+    _data[_dataLength++] = e;
+    _data[_dataLength++] = f;
+    _data[_dataLength++] = g;
+  }
+
+  void _addData12(double a, double b, double c, double d, double e, double f,
+                  double g, double h, double i, double j, double k, double l) {
+    _ensureDataLength(_dataLength + 12);
+    _data[_dataLength++] = a;
+    _data[_dataLength++] = b;
+    _data[_dataLength++] = c;
+    _data[_dataLength++] = d;
+    _data[_dataLength++] = e;
+    _data[_dataLength++] = f;
+    _data[_dataLength++] = g;
+    _data[_dataLength++] = h;
+    _data[_dataLength++] = i;
+    _data[_dataLength++] = j;
+    _data[_dataLength++] = k;
+    _data[_dataLength++] = l;
+  }
+
+  void save() {
+    _addMethod(_CanvasMethods.save);
+    _saveCount += 1;
+  }
+  void saveLayer(Rect? bounds, Paint paint) {
+    assert(paint != null); // ignore: unnecessary_null_comparison
+    _addMethod(_CanvasMethods.saveLayer);
+    _addObject(paint);
+    if (bounds != null) {
+      assert(_rectIsValid(bounds));
+      _addData4(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    }
+  }
+
+  void restore() {
+    _addMethod(_CanvasMethods.restore);
+    _saveCount -= 1;
+  }
+
+  int getSaveCount() => _saveCount;
+
+  void translate(double dx, double dy) {
+    _addMethod(_CanvasMethods.translate);
+    _addData2(dx, dy);
+  }
+
+  void scale(double sx, [double? sy]) {
+    _addMethod(_CanvasMethods.scale);
+    _addData2(sx, sy ?? 1.0);
+  }
+
+  void rotate(double radians) {
+    _addMethod(_CanvasMethods.rotate);
+    _addData1(radians);
+  }
+
+  void skew(double sx, double sy) {
+    _addMethod(_CanvasMethods.skew);
+    _addData2(sx, sy);
+  }
+
   void transform(Float64List matrix4) {
     assert(matrix4 != null); // ignore: unnecessary_null_comparison
     if (matrix4.length != 16)
       throw ArgumentError('"matrix4" must have 16 entries.');
-    _transform(matrix4);
-  }
-  void _transform(Float64List matrix4) { throw UnimplementedError(); }
 
-  /// Reduces the clip region to the intersection of the current clip and the
-  /// given rectangle.
-  ///
-  /// If [doAntiAlias] is true, then the clip will be anti-aliased.
-  ///
-  /// If multiple draw commands intersect with the clip boundary, this can result
-  /// in incorrect blending at the clip boundary. See [saveLayer] for a
-  /// discussion of how to address that.
-  ///
-  /// Use [ClipOp.difference] to subtract the provided rectangle from the
-  /// current clip.
+    _addMethod(_CanvasMethods.transform);
+    _addObject(matrix4);
+  }
+
   void clipRect(Rect rect, { ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = true }) {
     assert(_rectIsValid(rect));
     assert(clipOp != null); // ignore: unnecessary_null_comparison
     assert(doAntiAlias != null); // ignore: unnecessary_null_comparison
-    _clipRect(rect.left, rect.top, rect.right, rect.bottom, clipOp.index, doAntiAlias);
+    _addMethod(_CanvasMethods.clipRect);
+    _addData6(rect.left, rect.top, rect.right, rect.bottom, clipOp.index.toDouble(), doAntiAlias ? 1 : 0);
   }
-  void _clipRect(double left,
-                 double top,
-                 double right,
-                 double bottom,
-                 int clipOp,
-                 bool doAntiAlias) { throw UnimplementedError(); }
 
-  /// Reduces the clip region to the intersection of the current clip and the
-  /// given rounded rectangle.
-  ///
-  /// If [doAntiAlias] is true, then the clip will be anti-aliased.
-  ///
-  /// If multiple draw commands intersect with the clip boundary, this can result
-  /// in incorrect blending at the clip boundary. See [saveLayer] for a
-  /// discussion of how to address that and some examples of using [clipRRect].
   void clipRRect(RRect rrect, {bool doAntiAlias = true}) {
     assert(_rrectIsValid(rrect));
     assert(doAntiAlias != null); // ignore: unnecessary_null_comparison
-    _clipRRect(rrect._value32, doAntiAlias);
+    _addMethod(_CanvasMethods.clipRRect);
+    _addData12(
+      rrect.left,
+      rrect.top,
+      rrect.right,
+      rrect.bottom,
+      rrect.tlRadiusX,
+      rrect.tlRadiusY,
+      rrect.trRadiusX,
+      rrect.trRadiusY,
+      rrect.brRadiusX,
+      rrect.brRadiusY,
+      rrect.blRadiusX,
+      rrect.blRadiusY,
+    );
+    _addData1(doAntiAlias ? 1 : 0);
   }
-  void _clipRRect(Float32List rrect, bool doAntiAlias) { throw UnimplementedError(); }
 
-  /// Reduces the clip region to the intersection of the current clip and the
-  /// given [Path].
-  ///
-  /// If [doAntiAlias] is true, then the clip will be anti-aliased.
-  ///
-  /// If multiple draw commands intersect with the clip boundary, this can result
-  /// multiple draw commands intersect with the clip boundary, this can result
-  /// in incorrect blending at the clip boundary. See [saveLayer] for a
-  /// discussion of how to address that.
   void clipPath(Path path, {bool doAntiAlias = true}) {
     // ignore: unnecessary_null_comparison
     assert(path != null); // path is checked on the engine side
     assert(doAntiAlias != null); // ignore: unnecessary_null_comparison
-    _clipPath(path, doAntiAlias);
+    _addMethod(_CanvasMethods.clipPath);
+    _addObject(path);
+    _addData1(doAntiAlias ? 1 : 0);
   }
-  void _clipPath(Path path, bool doAntiAlias) { throw UnimplementedError(); }
 
-  /// Paints the given [Color] onto the canvas, applying the given
-  /// [BlendMode], with the given color being the source and the background
-  /// being the destination.
   void drawColor(Color color, BlendMode blendMode) {
     assert(color != null); // ignore: unnecessary_null_comparison
     assert(blendMode != null); // ignore: unnecessary_null_comparison
-    _drawColor(color.value, blendMode.index);
+    _addMethod(_CanvasMethods.drawColor);
+    _addData2(
+      color.value.toDouble(),
+      blendMode.index.toDouble(),
+    );
   }
-  void _drawColor(int color, int blendMode) { throw UnimplementedError(); }
 
-  /// Draws a line between the given points using the given paint. The line is
-  /// stroked, the value of the [Paint.style] is ignored for this call.
-  ///
-  /// The `p1` and `p2` arguments are interpreted as offsets from the origin.
   void drawLine(Offset p1, Offset p2, Paint paint) {
     assert(_offsetIsValid(p1));
     assert(_offsetIsValid(p2));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawLine(p1.dx, p1.dy, p2.dx, p2.dy, paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawLine);
+    _addObject(paint);
+    _addData4(p1.dx, p1.dy, p2.dx, p2.dy);
   }
-  void _drawLine(double x1,
-                 double y1,
-                 double x2,
-                 double y2,
-                 List<dynamic>? paintObjects,
-                 ByteData paintData) { throw UnimplementedError(); }
 
-  /// Fills the canvas with the given [Paint].
-  ///
-  /// To fill the canvas with a solid color and blend mode, consider
-  /// [drawColor] instead.
   void drawPaint(Paint paint) {
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawPaint(paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawPaint);
+    _addObject(paint);
   }
-  void _drawPaint(List<dynamic>? paintObjects, ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws a rectangle with the given [Paint]. Whether the rectangle is filled
-  /// or stroked (or both) is controlled by [Paint.style].
   void drawRect(Rect rect, Paint paint) {
     assert(_rectIsValid(rect));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawRect(rect.left, rect.top, rect.right, rect.bottom,
-              paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawRect);
+    _addObject(paint);
+    _addData4(rect.left, rect.top, rect.right, rect.bottom);
   }
-  void _drawRect(double left,
-                 double top,
-                 double right,
-                 double bottom,
-                 List<dynamic>? paintObjects,
-                 ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws a rounded rectangle with the given [Paint]. Whether the rectangle is
-  /// filled or stroked (or both) is controlled by [Paint.style].
   void drawRRect(RRect rrect, Paint paint) {
     assert(_rrectIsValid(rrect));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawRRect(rrect._value32, paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawRRect);
+    _addObject(paint);
+    _addData12(
+      rrect.left,
+      rrect.top,
+      rrect.right,
+      rrect.bottom,
+      rrect.tlRadiusX,
+      rrect.tlRadiusY,
+      rrect.trRadiusX,
+      rrect.trRadiusY,
+      rrect.brRadiusX,
+      rrect.brRadiusY,
+      rrect.blRadiusX,
+      rrect.blRadiusY,
+    );
   }
-  void _drawRRect(Float32List rrect,
-                  List<dynamic>? paintObjects,
-                  ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws a shape consisting of the difference between two rounded rectangles
-  /// with the given [Paint]. Whether this shape is filled or stroked (or both)
-  /// is controlled by [Paint.style].
-  ///
-  /// This shape is almost but not quite entirely unlike an annulus.
   void drawDRRect(RRect outer, RRect inner, Paint paint) {
     assert(_rrectIsValid(outer));
     assert(_rrectIsValid(inner));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawDRRect(outer._value32, inner._value32, paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawDRRect);
+    _addObject(paint);
+    _addData12(
+      outer.left,
+      outer.top,
+      outer.right,
+      outer.bottom,
+      outer.tlRadiusX,
+      outer.tlRadiusY,
+      outer.trRadiusX,
+      outer.trRadiusY,
+      outer.brRadiusX,
+      outer.brRadiusY,
+      outer.blRadiusX,
+      outer.blRadiusY,
+    );
+    _addData12(
+      inner.left,
+      inner.top,
+      inner.right,
+      inner.bottom,
+      inner.tlRadiusX,
+      inner.tlRadiusY,
+      inner.trRadiusX,
+      inner.trRadiusY,
+      inner.brRadiusX,
+      inner.brRadiusY,
+      inner.blRadiusX,
+      inner.blRadiusY,
+    );
   }
-  void _drawDRRect(Float32List outer,
-                   Float32List inner,
-                   List<dynamic>? paintObjects,
-                   ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws an axis-aligned oval that fills the given axis-aligned rectangle
-  /// with the given [Paint]. Whether the oval is filled or stroked (or both) is
-  /// controlled by [Paint.style].
   void drawOval(Rect rect, Paint paint) {
     assert(_rectIsValid(rect));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawOval(rect.left, rect.top, rect.right, rect.bottom,
-              paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawOval);
+    _addObject(paint);
+    _addData4(rect.left, rect.top, rect.right, rect.bottom);
   }
-  void _drawOval(double left,
-                 double top,
-                 double right,
-                 double bottom,
-                 List<dynamic>? paintObjects,
-                 ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws a circle centered at the point given by the first argument and
-  /// that has the radius given by the second argument, with the [Paint] given in
-  /// the third argument. Whether the circle is filled or stroked (or both) is
-  /// controlled by [Paint.style].
   void drawCircle(Offset c, double radius, Paint paint) {
     assert(_offsetIsValid(c));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawCircle(c.dx, c.dy, radius, paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawCircle);
+    _addObject(paint);
+    _addData2(c.dx, c.dy);
+    _addData1(radius);
   }
-  void _drawCircle(double x,
-                   double y,
-                   double radius,
-                   List<dynamic>? paintObjects,
-                   ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draw an arc scaled to fit inside the given rectangle.
-  ///
-  /// It starts from `startAngle` radians around the oval up to
-  /// `startAngle` + `sweepAngle` radians around the oval, with zero radians
-  /// being the point on the right hand side of the oval that crosses the
-  /// horizontal line that intersects the center of the rectangle and with positive
-  /// angles going clockwise around the oval. If `useCenter` is true, the arc is
-  /// closed back to the center, forming a circle sector. Otherwise, the arc is
-  /// not closed, forming a circle segment.
-  ///
-  /// This method is optimized for drawing arcs and should be faster than [Path.arcTo].
   void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) {
     assert(_rectIsValid(rect));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawArc(rect.left, rect.top, rect.right, rect.bottom, startAngle,
-             sweepAngle, useCenter, paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawArc);
+    _addObject(paint);
+    _addData7(rect.left, rect.top, rect.right, rect.bottom, startAngle,
+             sweepAngle, useCenter ? 1 : 0);
   }
-  void _drawArc(double left,
-                double top,
-                double right,
-                double bottom,
-                double startAngle,
-                double sweepAngle,
-                bool useCenter,
-                List<dynamic>? paintObjects,
-                ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws the given [Path] with the given [Paint].
-  ///
-  /// Whether this shape is filled or stroked (or both) is controlled by
-  /// [Paint.style]. If the path is filled, then sub-paths within it are
-  /// implicitly closed (see [Path.close]).
   void drawPath(Path path, Paint paint) {
     // ignore: unnecessary_null_comparison
     assert(path != null); // path is checked on the engine side
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawPath(path, paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawPath);
+    _addObject(paint);
+    _addObject(path);
   }
-  void _drawPath(Path path,
-                 List<dynamic>? paintObjects,
-                 ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws the given [Image] into the canvas with its top-left corner at the
-  /// given [Offset]. The image is composited into the canvas using the given [Paint].
   void drawImage(Image image, Offset offset, Paint paint) {
     // ignore: unnecessary_null_comparison
     assert(image != null); // image is checked on the engine side
     assert(_offsetIsValid(offset));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawImage(image._image, offset.dx, offset.dy, paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawImage);
+    _addObject(paint);
+    _addObject(image);
   }
-  void _drawImage(_Image image,
-                  double x,
-                  double y,
-                  List<dynamic>? paintObjects,
-                  ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws the subset of the given image described by the `src` argument into
-  /// the canvas in the axis-aligned rectangle given by the `dst` argument.
-  ///
-  /// This might sample from outside the `src` rect by up to half the width of
-  /// an applied filter.
-  ///
-  /// Multiple calls to this method with different arguments (from the same
-  /// image) can be batched into a single call to [drawAtlas] to improve
-  /// performance.
   void drawImageRect(Image image, Rect src, Rect dst, Paint paint) {
     // ignore: unnecessary_null_comparison
     assert(image != null); // image is checked on the engine side
     assert(_rectIsValid(src));
     assert(_rectIsValid(dst));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawImageRect(image._image,
-                   src.left,
-                   src.top,
-                   src.right,
-                   src.bottom,
-                   dst.left,
-                   dst.top,
-                   dst.right,
-                   dst.bottom,
-                   paint._objects,
-                   paint._data);
+    _addMethod(_CanvasMethods.drawImageRect);
+    _addObject(paint);
+    _addObject(image);
+    _addData4(
+      src.left,
+      src.top,
+      src.right,
+      src.bottom,
+    );
+    _addData4(
+      dst.left,
+      dst.top,
+      dst.right,
+      dst.bottom,
+    );
   }
-  void _drawImageRect(_Image image,
-                      double srcLeft,
-                      double srcTop,
-                      double srcRight,
-                      double srcBottom,
-                      double dstLeft,
-                      double dstTop,
-                      double dstRight,
-                      double dstBottom,
-                      List<dynamic>? paintObjects,
-                      ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws the given [Image] into the canvas using the given [Paint].
-  ///
-  /// The image is drawn in nine portions described by splitting the image by
-  /// drawing two horizontal lines and two vertical lines, where the `center`
-  /// argument describes the rectangle formed by the four points where these
-  /// four lines intersect each other. (This forms a 3-by-3 grid of regions,
-  /// the center region being described by the `center` argument.)
-  ///
-  /// The four regions in the corners are drawn, without scaling, in the four
-  /// corners of the destination rectangle described by `dst`. The remaining
-  /// five regions are drawn by stretching them to fit such that they exactly
-  /// cover the destination rectangle while maintaining their relative
-  /// positions.
   void drawImageNine(Image image, Rect center, Rect dst, Paint paint) {
     // ignore: unnecessary_null_comparison
     assert(image != null); // image is checked on the engine side
     assert(_rectIsValid(center));
     assert(_rectIsValid(dst));
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawImageNine(image._image,
-                   center.left,
-                   center.top,
-                   center.right,
-                   center.bottom,
-                   dst.left,
-                   dst.top,
-                   dst.right,
-                   dst.bottom,
-                   paint._objects,
-                   paint._data);
+    _addMethod(_CanvasMethods.drawImageNine);
+    _addObject(paint);
+    _addObject(image);
+    _addData4(
+      center.left,
+      center.top,
+      center.right,
+      center.bottom,
+    );
+    _addData4(
+      dst.left,
+      dst.top,
+      dst.right,
+      dst.bottom,
+    );
   }
-  void _drawImageNine(_Image image,
-                      double centerLeft,
-                      double centerTop,
-                      double centerRight,
-                      double centerBottom,
-                      double dstLeft,
-                      double dstTop,
-                      double dstRight,
-                      double dstBottom,
-                      List<dynamic>? paintObjects,
-                      ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draw the given picture onto the canvas. To create a picture, see
-  /// [PictureRecorder].
   void drawPicture(Picture picture) {
     // ignore: unnecessary_null_comparison
     assert(picture != null); // picture is checked on the engine side
-    _drawPicture(picture);
+    _addMethod(_CanvasMethods.drawPicture);
+    _addObject(picture);
   }
-  void _drawPicture(Picture picture) { throw UnimplementedError(); }
 
-  /// Draws the text in the given [Paragraph] into this canvas at the given
-  /// [Offset].
-  ///
-  /// The [Paragraph] object must have had [Paragraph.layout] called on it
-  /// first.
-  ///
-  /// To align the text, set the `textAlign` on the [ParagraphStyle] object
-  /// passed to the [new ParagraphBuilder] constructor. For more details see
-  /// [TextAlign] and the discussion at [new ParagraphStyle].
-  ///
-  /// If the text is left aligned or justified, the left margin will be at the
-  /// position specified by the `offset` argument's [Offset.dx] coordinate.
-  ///
-  /// If the text is right aligned or justified, the right margin will be at the
-  /// position described by adding the [ParagraphConstraints.width] given to
-  /// [Paragraph.layout], to the `offset` argument's [Offset.dx] coordinate.
-  ///
-  /// If the text is centered, the centering axis will be at the position
-  /// described by adding half of the [ParagraphConstraints.width] given to
-  /// [Paragraph.layout], to the `offset` argument's [Offset.dx] coordinate.
   void drawParagraph(Paragraph paragraph, Offset offset) {
     assert(paragraph != null); // ignore: unnecessary_null_comparison
     assert(_offsetIsValid(offset));
-    paragraph._paint(this, offset.dx, offset.dy);
+    _addMethod(_CanvasMethods.drawParagraph);
+    _addObject(paragraph);
   }
 
-  /// Draws a sequence of points according to the given [PointMode].
-  ///
-  /// The `points` argument is interpreted as offsets from the origin.
-  ///
-  /// See also:
-  ///
-  ///  * [drawRawPoints], which takes `points` as a [Float32List] rather than a
-  ///    [List<Offset>].
   void drawPoints(PointMode pointMode, List<Offset> points, Paint paint) {
     assert(pointMode != null); // ignore: unnecessary_null_comparison
     assert(points != null); // ignore: unnecessary_null_comparison
     assert(paint != null); // ignore: unnecessary_null_comparison
-    _drawPoints(paint._objects, paint._data, pointMode.index, _encodePointList(points));
+    _drawPoints(paint, pointMode.index, _encodePointList(points));
   }
 
-  /// Draws a sequence of points according to the given [PointMode].
-  ///
-  /// The `points` argument is interpreted as a list of pairs of floating point
-  /// numbers, where each pair represents an x and y offset from the origin.
-  ///
-  /// See also:
-  ///
-  ///  * [drawPoints], which takes `points` as a [List<Offset>] rather than a
-  ///    [List<Float32List>].
   void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) {
     assert(pointMode != null); // ignore: unnecessary_null_comparison
     assert(points != null); // ignore: unnecessary_null_comparison
     assert(paint != null); // ignore: unnecessary_null_comparison
     if (points.length % 2 != 0)
       throw ArgumentError('"points" must have an even number of values.');
-    _drawPoints(paint._objects, paint._data, pointMode.index, points);
+    _drawPoints(paint, pointMode.index, points);
   }
 
-  void _drawPoints(List<dynamic>? paintObjects,
-                   ByteData paintData,
-                   int pointMode,
-                   Float32List points) { throw UnimplementedError(); }
+  void _drawPoints(
+    Paint paint,
+    int pointMode,
+    Float32List points,
+  ) {
+    _addMethod(_CanvasMethods.drawPoints);
+    _addObject(paint);
+    _addObject(points);
+    _addData1(pointMode.toDouble());
+  }
 
-  /// Draws the set of [Vertices] onto the canvas.
-  ///
-  /// All parameters must not be null.
-  ///
-  /// See also:
-  ///   * [new Vertices], which creates a set of vertices to draw on the canvas.
-  ///   * [Vertices.raw], which creates the vertices using typed data lists
-  ///     rather than unencoded lists.
   void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) {
     // ignore: unnecessary_null_comparison
     assert(vertices != null); // vertices is checked on the engine side
     assert(paint != null); // ignore: unnecessary_null_comparison
     assert(blendMode != null); // ignore: unnecessary_null_comparison
-    _drawVertices(vertices, blendMode.index, paint._objects, paint._data);
+    _addMethod(_CanvasMethods.drawVertices);
+    _addObject(paint);
+    _addObject(vertices);
+    _addData1(blendMode.index.toDouble());
   }
-  void _drawVertices(Vertices vertices,
-                     int blendMode,
-                     List<dynamic>? paintObjects,
-                     ByteData paintData) { throw UnimplementedError(); }
 
-  /// Draws many parts of an image - the [atlas] - onto the canvas.
-  ///
-  /// This method allows for optimization when you want to draw many parts of an
-  /// image onto the canvas, such as when using sprites or zooming. It is more efficient
-  /// than using multiple calls to [drawImageRect] and provides more functionality
-  /// to individually transform each image part by a separate rotation or scale and
-  /// blend or modulate those parts with a solid color.
-  ///
-  /// The method takes a list of [Rect] objects that each define a piece of the
-  /// [atlas] image to be drawn independently. Each [Rect] is associated with an
-  /// [RSTransform] entry in the [transforms] list which defines the location,
-  /// rotation, and (uniform) scale with which to draw that portion of the image.
-  /// Each [Rect] can also be associated with an optional [Color] which will be
-  /// composed with the associated image part using the [blendMode] before blending
-  /// the result onto the canvas. The full operation can be broken down as:
-  ///
-  /// - Blend each rectangular portion of the image specified by an entry in the
-  /// [rects] argument with its associated entry in the [colors] list using the
-  /// [blendMode] argument (if a color is specified). In this part of the operation,
-  /// the image part will be considered the source of the operation and the associated
-  /// color will be considered the destination.
-  /// - Blend the result from the first step onto the canvas using the translation,
-  /// rotation, and scale properties expressed in the associated entry in the
-  /// [transforms] list using the properties of the [Paint] object.
-  ///
-  /// If the first stage of the operation which blends each part of the image with
-  /// a color is needed, then both the [colors] and [blendMode] arguments must
-  /// not be null and there must be an entry in the [colors] list for each
-  /// image part. If that stage is not needed, then the [colors] argument can
-  /// be either null or an empty list and the [blendMode] argument may also be null.
-  ///
-  /// The optional [cullRect] argument can provide an estimate of the bounds of the
-  /// coordinates rendered by all components of the atlas to be compared against
-  /// the clip to quickly reject the operation if it does not intersect.
-  ///
-  /// An example usage to render many sprites from a single sprite atlas with no
-  /// rotations or scales:
-  ///
-  /// ```dart
-  /// class Sprite {
-  ///   int index;
-  ///   double centerX;
-  ///   double centerY;
-  /// }
-  ///
-  /// class MyPainter extends CustomPainter {
-  ///   // assume spriteAtlas contains N 10x10 sprites side by side in a (N*10)x10 image
-  ///   ui.Image spriteAtlas;
-  ///   List<Sprite> allSprites;
-  ///
-  ///   @override
-  ///   void paint(Canvas canvas, Size size) {
-  ///     Paint paint = Paint();
-  ///     canvas.drawAtlas(spriteAtlas, <RSTransform>[
-  ///       for (Sprite sprite in allSprites)
-  ///         RSTransform.fromComponents(
-  ///           rotation: 0.0,
-  ///           scale: 1.0,
-  ///           // Center of the sprite relative to its rect
-  ///           anchorX: 5.0,
-  ///           anchorY: 5.0,
-  ///           // Location at which to draw the center of the sprite
-  ///           translateX: sprite.centerX,
-  ///           translateY: sprite.centerY,
-  ///         ),
-  ///     ], <Rect>[
-  ///       for (Sprite sprite in allSprites)
-  ///         Rect.fromLTWH(sprite.index * 10.0, 0.0, 10.0, 10.0),
-  ///     ], null, null, null, paint);
-  ///   }
-  ///
-  ///   ...
-  /// }
-  /// ```
-  ///
-  /// Another example usage which renders sprites with an optional opacity and rotation:
-  ///
-  /// ```dart
-  /// class Sprite {
-  ///   int index;
-  ///   double centerX;
-  ///   double centerY;
-  ///   int alpha;
-  ///   double rotation;
-  /// }
-  ///
-  /// class MyPainter extends CustomPainter {
-  ///   // assume spriteAtlas contains N 10x10 sprites side by side in a (N*10)x10 image
-  ///   ui.Image spriteAtlas;
-  ///   List<Sprite> allSprites;
-  ///
-  ///   @override
-  ///   void paint(Canvas canvas, Size size) {
-  ///     Paint paint = Paint();
-  ///     canvas.drawAtlas(spriteAtlas, <RSTransform>[
-  ///       for (Sprite sprite in allSprites)
-  ///         RSTransform.fromComponents(
-  ///           rotation: sprite.rotation,
-  ///           scale: 1.0,
-  ///           // Center of the sprite relative to its rect
-  ///           anchorX: 5.0,
-  ///           anchorY: 5.0,
-  ///           // Location at which to draw the center of the sprite
-  ///           translateX: sprite.centerX,
-  ///           translateY: sprite.centerY,
-  ///         ),
-  ///     ], <Rect>[
-  ///       for (Sprite sprite in allSprites)
-  ///         Rect.fromLTWH(sprite.index * 10.0, 0.0, 10.0, 10.0),
-  ///     ], <Color>[
-  ///       for (Sprite sprite in allSprites)
-  ///         Colors.white.withAlpha(sprite.alpha),
-  ///     ], BlendMode.srcIn, null, paint);
-  ///   }
-  ///
-  ///   ...
-  /// }
-  /// ```
-  ///
-  /// The length of the [transforms] and [rects] lists must be equal and
-  /// if the [colors] argument is not null then it must either be empty or
-  /// have the same length as the other two lists.
-  ///
-  /// See also:
-  ///
-  ///  * [drawRawAtlas], which takes its arguments as typed data lists rather
-  ///    than objects.
   void drawAtlas(Image atlas,
                  List<RSTransform> transforms,
                  List<Rect> rects,
@@ -4611,155 +2494,12 @@
     }
 
     final Int32List? colorBuffer = (colors == null || colors.isEmpty) ? null : _encodeColorList(colors);
-    final Float32List? cullRectBuffer = cullRect?._value32;
 
     _drawAtlas(
-      paint._objects, paint._data, atlas._image, rstTransformBuffer, rectBuffer,
-      colorBuffer, (blendMode ?? BlendMode.src).index, cullRectBuffer
+      paint, atlas._image, rstTransformBuffer, rectBuffer,
+      colorBuffer, (blendMode ?? BlendMode.src).index, cullRect ?? Rect.largest,
     );
   }
-
-  /// Draws many parts of an image - the [atlas] - onto the canvas.
-  ///
-  /// This method allows for optimization when you want to draw many parts of an
-  /// image onto the canvas, such as when using sprites or zooming. It is more efficient
-  /// than using multiple calls to [drawImageRect] and provides more functionality
-  /// to individually transform each image part by a separate rotation or scale and
-  /// blend or modulate those parts with a solid color. It is also more efficient
-  /// than [drawAtlas] as the data in the arguments is already packed in a format
-  /// that can be directly used by the rendering code.
-  ///
-  /// A full description of how this method uses its arguments to draw onto the
-  /// canvas can be found in the description of the [drawAtlas] method.
-  ///
-  /// The [rstTransforms] argument is interpreted as a list of four-tuples, with
-  /// each tuple being ([RSTransform.scos], [RSTransform.ssin],
-  /// [RSTransform.tx], [RSTransform.ty]).
-  ///
-  /// The [rects] argument is interpreted as a list of four-tuples, with each
-  /// tuple being ([Rect.left], [Rect.top], [Rect.right], [Rect.bottom]).
-  ///
-  /// The [colors] argument, which can be null, is interpreted as a list of
-  /// 32-bit colors, with the same packing as [Color.value]. If the [colors]
-  /// argument is not null then the [blendMode] argument must also not be null.
-  ///
-  /// An example usage to render many sprites from a single sprite atlas with no rotations
-  /// or scales:
-  ///
-  /// ```dart
-  /// class Sprite {
-  ///   int index;
-  ///   double centerX;
-  ///   double centerY;
-  /// }
-  ///
-  /// class MyPainter extends CustomPainter {
-  ///   // assume spriteAtlas contains N 10x10 sprites side by side in a (N*10)x10 image
-  ///   ui.Image spriteAtlas;
-  ///   List<Sprite> allSprites;
-  ///
-  ///   @override
-  ///   void paint(Canvas canvas, Size size) {
-  ///     // For best advantage, these lists should be cached and only specific
-  ///     // entries updated when the sprite information changes. This code is
-  ///     // illustrative of how to set up the data and not a recommendation for
-  ///     // optimal usage.
-  ///     Float32List rectList = Float32List(allSprites.length * 4);
-  ///     Float32List transformList = Float32List(allSprites.length * 4);
-  ///     for (int i = 0; i < allSprites.length; i++) {
-  ///       final double rectX = sprite.spriteIndex * 10.0;
-  ///       rectList[i * 4 + 0] = rectX;
-  ///       rectList[i * 4 + 1] = 0.0;
-  ///       rectList[i * 4 + 2] = rectX + 10.0;
-  ///       rectList[i * 4 + 3] = 10.0;
-  ///
-  ///       // This example sets the RSTransform values directly for a common case of no
-  ///       // rotations or scales and just a translation to position the atlas entry. For
-  ///       // more complicated transforms one could use the RSTransform class to compute
-  ///       // the necessary values or do the same math directly.
-  ///       transformList[i * 4 + 0] = 1.0;
-  ///       transformList[i * 4 + 1] = 0.0;
-  ///       transformList[i * 4 + 2] = sprite.centerX - 5.0;
-  ///       transformList[i * 4 + 3] = sprite.centerY - 5.0;
-  ///     }
-  ///     Paint paint = Paint();
-  ///     canvas.drawAtlas(spriteAtlas, transformList, rectList, null, null, null, paint);
-  ///   }
-  ///
-  ///   ...
-  /// }
-  /// ```
-  ///
-  /// Another example usage which renders sprites with an optional opacity and rotation:
-  ///
-  /// ```dart
-  /// class Sprite {
-  ///   int index;
-  ///   double centerX;
-  ///   double centerY;
-  ///   int alpha;
-  ///   double rotation;
-  /// }
-  ///
-  /// class MyPainter extends CustomPainter {
-  ///   // assume spriteAtlas contains N 10x10 sprites side by side in a (N*10)x10 image
-  ///   ui.Image spriteAtlas;
-  ///   List<Sprite> allSprites;
-  ///
-  ///   @override
-  ///   void paint(Canvas canvas, Size size) {
-  ///     // For best advantage, these lists should be cached and only specific
-  ///     // entries updated when the sprite information changes. This code is
-  ///     // illustrative of how to set up the data and not a recommendation for
-  ///     // optimal usage.
-  ///     Float32List rectList = Float32List(allSprites.length * 4);
-  ///     Float32List transformList = Float32List(allSprites.length * 4);
-  ///     Int32List colorList = Int32List(allSprites.length);
-  ///     for (int i = 0; i < allSprites.length; i++) {
-  ///       final double rectX = sprite.spriteIndex * 10.0;
-  ///       rectList[i * 4 + 0] = rectX;
-  ///       rectList[i * 4 + 1] = 0.0;
-  ///       rectList[i * 4 + 2] = rectX + 10.0;
-  ///       rectList[i * 4 + 3] = 10.0;
-  ///
-  ///       // This example uses an RSTransform object to compute the necessary values for
-  ///       // the transform using a factory helper method because the sprites contain
-  ///       // rotation values which are not trivial to work with. But if the math for the
-  ///       // values falls out from other calculations on the sprites then the values could
-  ///       // possibly be generated directly from the sprite update code.
-  ///       final RSTransform transform = RSTransform.fromComponents(
-  ///         rotation: sprite.rotation,
-  ///         scale: 1.0,
-  ///         // Center of the sprite relative to its rect
-  ///         anchorX: 5.0,
-  ///         anchorY: 5.0,
-  ///         // Location at which to draw the center of the sprite
-  ///         translateX: sprite.centerX,
-  ///         translateY: sprite.centerY,
-  ///       );
-  ///       transformList[i * 4 + 0] = transform.scos;
-  ///       transformList[i * 4 + 1] = transform.ssin;
-  ///       transformList[i * 4 + 2] = transform.tx;
-  ///       transformList[i * 4 + 3] = transform.ty;
-  ///
-  ///       // This example computes the color value directly, but one could also compute
-  ///       // an actual Color object and use its Color.value getter for the same result.
-  ///       // Since we are using BlendMode.srcIn, only the alpha component matters for
-  ///       // these colors which makes this a simple shift operation.
-  ///       colorList[i] = sprite.alpha << 24;
-  ///     }
-  ///     Paint paint = Paint();
-  ///     canvas.drawAtlas(spriteAtlas, transformList, rectList, colorList, BlendMode.srcIn, null, paint);
-  ///   }
-  ///
-  ///   ...
-  /// }
-  /// ```
-  ///
-  /// See also:
-  ///
-  ///  * [drawAtlas], which takes its arguments as objects rather than typed
-  ///    data lists.
   void drawRawAtlas(Image atlas,
                     Float32List rstTransforms,
                     Float32List rects,
@@ -4783,141 +2523,73 @@
       throw ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".');
 
     _drawAtlas(
-      paint._objects, paint._data, atlas._image, rstTransforms, rects,
-      colors, (blendMode ?? BlendMode.src).index, cullRect?._value32
+      paint, atlas._image, rstTransforms, rects,
+      colors, (blendMode ?? BlendMode.src).index, cullRect ?? Rect.largest,
     );
   }
 
-  void _drawAtlas(List<dynamic>? paintObjects,
-                  ByteData paintData,
-                  _Image atlas,
-                  Float32List rstTransforms,
-                  Float32List rects,
-                  Int32List? colors,
-                  int blendMode,
-                  Float32List? cullRect) { throw UnimplementedError(); }
+  void _drawAtlas(
+    Paint paint,
+    _Image atlas,
+    Float32List rstTransforms,
+    Float32List rects,
+    Int32List? colors,
+    int blendMode,
+    Rect cullRect,
+  ) {
+    _addMethod(_CanvasMethods.drawAtlas);
+    _addObject(paint);
+    _addObject(rstTransforms);
+    _addObject(rects);
+    _addObject(colors ?? Int32List(0));
+    _addData1(blendMode.toDouble());
+    _addData4(
+      cullRect.left,
+      cullRect.top,
+      cullRect.right,
+      cullRect.bottom,
+    );
+  }
 
-  /// Draws a shadow for a [Path] representing the given material elevation.
-  ///
-  /// The `transparentOccluder` argument should be true if the occluding object
-  /// is not opaque.
-  ///
-  /// The arguments must not be null.
   void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) {
     // ignore: unnecessary_null_comparison
     assert(path != null); // path is checked on the engine side
     assert(color != null); // ignore: unnecessary_null_comparison
     assert(transparentOccluder != null); // ignore: unnecessary_null_comparison
-    _drawShadow(path, color.value, elevation, transparentOccluder);
+    _addMethod(_CanvasMethods.drawShadow);
+    _addObject(path);
+    _addData2(color.value.toDouble(), elevation);
+    _addData1(transparentOccluder ? 1 : 0);
   }
-  void _drawShadow(Path path,
-                   int color,
-                   double elevation,
-                   bool transparentOccluder) { throw UnimplementedError(); }
 }
 
-/// An object representing a sequence of recorded graphical operations.
-///
-/// To create a [Picture], use a [PictureRecorder].
-///
-/// A [Picture] can be placed in a [Scene] using a [SceneBuilder], via
-/// the [SceneBuilder.addPicture] method. A [Picture] can also be
-/// drawn into a [Canvas], using the [Canvas.drawPicture] method.
-@pragma('vm:entry-point')
-class Picture extends NativeFieldWrapperClass2 {
-  /// This class is created by the engine, and should not be instantiated
-  /// or extended directly.
-  ///
-  /// To create a [Picture], use a [PictureRecorder].
-  @pragma('vm:entry-point')
-  Picture._();
-
-  /// Creates an image from this picture.
-  ///
-  /// The returned image will be `width` pixels wide and `height` pixels high.
-  /// The picture is rasterized within the 0 (left), 0 (top), `width` (right),
-  /// `height` (bottom) bounds. Content outside these bounds is clipped.
-  ///
-  /// Although the image is returned synchronously, the picture is actually
-  /// rasterized the first time the image is drawn and then cached.
-  Future<Image> toImage(int width, int height) {
+class Picture {
+    Picture._();
+  Future<Image> toImage(int width, int height) async {
     if (width <= 0 || height <= 0)
       throw Exception('Invalid image dimensions.');
-    return _futurize(
-      (_Callback<Image> callback) => _toImage(width, height, (_Image image) {
-        callback(Image._(image));
-      }),
-    );
+    return Image._(_Image._(width, height));
   }
 
-  String? _toImage(int width, int height, _Callback<_Image> callback) { throw UnimplementedError(); }
-
-  /// Release the resources used by this object. The object is no longer usable
-  /// after this method is called.
   void dispose() { throw UnimplementedError(); }
-
-  /// Returns the approximate number of bytes allocated for this object.
-  ///
-  /// The actual size of this picture may be larger, particularly if it contains
-  /// references to image or other large objects.
   int get approximateBytesUsed { throw UnimplementedError(); }
 }
 
-/// Records a [Picture] containing a sequence of graphical operations.
-///
-/// To begin recording, construct a [Canvas] to record the commands.
-/// To end recording, use the [PictureRecorder.endRecording] method.
-class PictureRecorder extends NativeFieldWrapperClass2 {
-  /// Creates a new idle PictureRecorder. To associate it with a
-  /// [Canvas] and begin recording, pass this [PictureRecorder] to the
-  /// [Canvas] constructor.
-  @pragma('vm:entry-point')
-  PictureRecorder() { _constructor(); }
-  void _constructor() { throw UnimplementedError(); }
-
-  /// Whether this object is currently recording commands.
-  ///
-  /// Specifically, this returns true if a [Canvas] object has been
-  /// created to record commands and recording has not yet ended via a
-  /// call to [endRecording], and false if either this
-  /// [PictureRecorder] has not yet been associated with a [Canvas],
-  /// or the [endRecording] method has already been called.
+class PictureRecorder {
+  PictureRecorder();
   bool get isRecording => _canvas != null;
-
-  /// Finishes recording graphical operations.
-  ///
-  /// Returns a picture containing the graphical operations that have been
-  /// recorded thus far. After calling this function, both the picture recorder
-  /// and the canvas objects are invalid and cannot be used further.
   Picture endRecording() {
     if (_canvas == null)
       throw StateError('PictureRecorder did not start recording.');
     final Picture picture = Picture._();
-    _endRecording(picture);
     _canvas!._recorder = null;
     _canvas = null;
     return picture;
   }
 
-  void _endRecording(Picture outPicture) { throw UnimplementedError(); }
-
   Canvas? _canvas;
 }
-
-/// A single shadow.
-///
-/// Multiple shadows are stacked together in a [TextStyle].
 class Shadow {
-  /// Construct a shadow.
-  ///
-  /// The default shadow is a black shadow with zero offset and zero blur.
-  /// Default shadows should be completely covered by the casting element,
-  /// and not be visible.
-  ///
-  /// Transparency should be adjusted through the [color] alpha.
-  ///
-  /// Shadow order matters due to compositing multiple translucent objects not
-  /// being commutative.
   const Shadow({
     this.color = const Color(_kColorDefault),
     this.offset = Offset.zero,
@@ -4933,56 +2605,20 @@
   static const int _kXOffset = 1 << 2;
   static const int _kYOffset = 2 << 2;
   static const int _kBlurOffset = 3 << 2;
-
-  /// Color that the shadow will be drawn with.
-  ///
-  /// The shadows are shapes composited directly over the base canvas, and do not
-  /// represent optical occlusion.
   final Color color;
-
-  /// The displacement of the shadow from the casting element.
-  ///
-  /// Positive x/y offsets will shift the shadow to the right and down, while
-  /// negative offsets shift the shadow to the left and up. The offsets are
-  /// relative to the position of the element that is casting it.
   final Offset offset;
-
-  /// The standard deviation of the Gaussian to convolve with the shadow's shape.
   final double blurRadius;
-
-  /// Converts a blur radius in pixels to sigmas.
-  ///
-  /// See the sigma argument to [MaskFilter.blur].
-  ///
   // See SkBlurMask::ConvertRadiusToSigma().
   // <https://github.com/google/skia/blob/bb5b77db51d2e149ee66db284903572a5aac09be/src/effects/SkBlurMask.cpp#L23>
   static double convertRadiusToSigma(double radius) {
     return radius * 0.57735 + 0.5;
   }
-
-  /// The [blurRadius] in sigmas instead of logical pixels.
-  ///
-  /// See the sigma argument to [MaskFilter.blur].
   double get blurSigma => convertRadiusToSigma(blurRadius);
-
-  /// Create the [Paint] object that corresponds to this shadow description.
-  ///
-  /// The [offset] is not represented in the [Paint] object.
-  /// To honor this as well, the shape should be translated by [offset] before
-  /// being filled using this [Paint].
-  ///
-  /// This class does not provide a way to disable shadows to avoid
-  /// inconsistencies in shadow blur rendering, primarily as a method of
-  /// reducing test flakiness. [toPaint] should be overridden in subclasses to
-  /// provide this functionality.
   Paint toPaint() {
     return Paint()
       ..color = color
       ..maskFilter = MaskFilter.blur(BlurStyle.normal, blurSigma);
   }
-
-  /// Returns a new shadow with its [offset] and [blurRadius] scaled by the given
-  /// factor.
   Shadow scale(double factor) {
     return Shadow(
       color: color,
@@ -4990,26 +2626,6 @@
       blurRadius: blurRadius * factor,
     );
   }
-
-  /// Linearly interpolate between two shadows.
-  ///
-  /// If either shadow is null, this function linearly interpolates from a
-  /// a shadow that matches the other shadow in color but has a zero
-  /// offset and a zero blurRadius.
-  ///
-  /// {@template dart.ui.shadow.lerp}
-  /// The `t` argument represents position on the timeline, with 0.0 meaning
-  /// that the interpolation has not started, returning `a` (or something
-  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
-  /// returning `b` (or something equivalent to `b`), and values in between
-  /// meaning that the interpolation is at the relevant point on the timeline
-  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
-  /// 1.0, so negative values and values greater than 1.0 are valid (and can
-  /// easily be generated by curves such as [Curves.elasticInOut]).
-  ///
-  /// Values for `t` are usually obtained from an [Animation<double>], such as
-  /// an [AnimationController].
-  /// {@endtemplate}
   static Shadow? lerp(Shadow? a, Shadow? b, double t) {
     assert(t != null); // ignore: unnecessary_null_comparison
     if (b == null) {
@@ -5030,12 +2646,6 @@
       }
     }
   }
-
-  /// Linearly interpolate between two lists of shadows.
-  ///
-  /// If the lists differ in length, excess items are lerped with null.
-  ///
-  /// {@macro dart.ui.shadow.lerp}
   static List<Shadow>? lerpList(List<Shadow>? a, List<Shadow>? b, double t) {
     assert(t != null); // ignore: unnecessary_null_comparison
     if (a == null && b == null)
@@ -5106,13 +2716,8 @@
   @override
   String toString() => 'TextShadow($color, $offset, $blurRadius)';
 }
-
-/// A handle to a read-only byte buffer that is managed by the engine.
-class ImmutableBuffer extends NativeFieldWrapperClass2 {
+class ImmutableBuffer {
   ImmutableBuffer._(this.length);
-
-  /// Creates a copy of the data from a [Uint8List] suitable for internal use
-  /// in the engine.
   static Future<ImmutableBuffer> fromUint8List(Uint8List list) {
     final ImmutableBuffer instance = ImmutableBuffer._(list.length);
     return _futurize((_Callback<void> callback) {
@@ -5120,23 +2725,11 @@
     }).then((_) => instance);
   }
   void _init(Uint8List list, _Callback<void> callback) { throw UnimplementedError(); }
-
-  /// The length, in bytes, of the underlying data.
   final int length;
-
-  /// Release the resources used by this object. The object is no longer usable
-  /// after this method is called.
   void dispose() { throw UnimplementedError(); }
 }
-
-/// A descriptor of data that can be turned into an [Image] via a [Codec].
-///
-/// Use this class to determine the height, width, and byte size of image data
-/// before decoding it.
-class ImageDescriptor extends NativeFieldWrapperClass2 {
+class ImageDescriptor {
   ImageDescriptor._();
-
-  /// Creates an image descriptor from encoded data in a supported format.
   static Future<ImageDescriptor> encoded(ImmutableBuffer buffer) {
     final ImageDescriptor descriptor = ImageDescriptor._();
     return _futurize((_Callback<void> callback) {
@@ -5144,15 +2737,6 @@
     }).then((_) => descriptor);
   }
   String? _initEncoded(ImmutableBuffer buffer, _Callback<void> callback) { throw UnimplementedError(); }
-
-  /// Creates an image descriptor from raw image pixels.
-  ///
-  /// The `pixels` parameter is the pixel data in the encoding described by
-  /// `format`.
-  ///
-  /// The `rowBytes` parameter is the number of bytes consumed by each row of
-  /// pixels in the data buffer. If unspecified, it defaults to `width` multiplied
-  /// by the number of bytes per pixel in the provided `format`.
   // Not async because there's no expensive work to do here.
   ImageDescriptor.raw(
     ImmutableBuffer buffer, {
@@ -5171,38 +2755,16 @@
 
   int? _width;
   int _getWidth() { throw UnimplementedError(); }
-  /// The width, in pixels, of the image.
-  ///
-  /// On the Web, this is only supported for [raw] images.
   int get width => _width ??= _getWidth();
 
   int? _height;
   int _getHeight() { throw UnimplementedError(); }
-  /// The height, in pixels, of the image.
-  ///
-  /// On the Web, this is only supported for [raw] images.
   int get height => _height ??= _getHeight();
 
   int? _bytesPerPixel;
   int _getBytesPerPixel() { throw UnimplementedError(); }
-  /// The number of bytes per pixel in the image.
-  ///
-  /// On web, this is only supported for [raw] images.
   int get bytesPerPixel => _bytesPerPixel ??= _getBytesPerPixel();
-
-  /// Release the resources used by this object. The object is no longer usable
-  /// after this method is called.
   void dispose() { throw UnimplementedError(); }
-
-  /// Creates a [Codec] object which is suitable for decoding the data in the
-  /// buffer to an [Image].
-  ///
-  /// If only one of targetWidth or  targetHeight are specified, the other
-  /// dimension will be scaled according to the aspect ratio of the supplied
-  /// dimension.
-  ///
-  /// If either targetWidth or targetHeight is less than or equal to zero, it
-  /// will be treated as if it is null.
   Future<Codec> instantiateCodec({int? targetWidth, int? targetHeight}) async {
     if (targetWidth != null && targetWidth <= 0) {
       targetWidth = null;
@@ -5230,37 +2792,8 @@
   }
   void _instantiateCodec(Codec outCodec, int targetWidth, int targetHeight) { throw UnimplementedError(); }
 }
-
-/// Generic callback signature, used by [_futurize].
 typedef _Callback<T> = void Function(T result);
-
-/// Signature for a method that receives a [_Callback].
-///
-/// Return value should be null on success, and a string error message on
-/// failure.
 typedef _Callbacker<T> = String? Function(_Callback<T> callback);
-
-/// Converts a method that receives a value-returning callback to a method that
-/// returns a Future.
-///
-/// Return a [String] to cause an [Exception] to be synchronously thrown with
-/// that string as a message.
-///
-/// If the callback is called with null, the future completes with an error.
-///
-/// Example usage:
-///
-/// ```dart
-/// typedef IntCallback = void Function(int result);
-///
-/// String _doSomethingAndCallback(IntCallback callback) {
-///   Timer(new Duration(seconds: 1), () { callback(1); });
-/// }
-///
-/// Future<int> doSomething() {
-///   return _futurize(_doSomethingAndCallback);
-/// }
-/// ```
 Future<T> _futurize<T>(_Callbacker<T> callbacker) {
   final Completer<T> completer = Completer<T>.sync();
   final String? error = callbacker((T t) {
diff --git a/lib/src/ui/platform_dispatcher.dart b/lib/src/ui/platform_dispatcher.dart
index 8c832ed..6e4ab0a 100644
--- a/lib/src/ui/platform_dispatcher.dart
+++ b/lib/src/ui/platform_dispatcher.dart
@@ -365,8 +365,8 @@
   }
 
   late _SetNeedsReportTimingsFunc _setNeedsReportTimings;
-  void _nativeSetNeedsReportTimings(bool value)
-      { throw UnimplementedError(); }
+
+  void _nativeSetNeedsReportTimings(bool value) {}
 
   // Called from the engine, via hooks.dart
   void _reportTimings(List<int> timings) {
@@ -394,8 +394,9 @@
       throw Exception(error);
   }
 
-  String? _sendPlatformMessage(String name, PlatformMessageResponseCallback? callback, ByteData? data)
-      { throw UnimplementedError(); }
+  String? _sendPlatformMessage(String name, PlatformMessageResponseCallback? callback, ByteData? data) {
+    return null;
+  }
 
   /// Called whenever this platform dispatcher receives a message from a
   /// platform-specific plugin.
@@ -492,6 +493,9 @@
   /// platform channel may be used.
   ByteData? getPersistentIsolateData() { throw UnimplementedError(); }
 
+  Timer? _frameTimer;
+  Duration _frameTime = Duration.zero;
+
   /// Requests that, at the next appropriate opportunity, the [onBeginFrame] and
   /// [onDrawFrame] callbacks be invoked.
   ///
@@ -499,7 +503,22 @@
   ///
   ///  * [SchedulerBinding], the Flutter framework class which manages the
   ///    scheduling of frames.
-  void scheduleFrame() { throw UnimplementedError(); }
+  void scheduleFrame() {
+    _frameTimer ??= new Timer(
+      const Duration(milliseconds: 16),
+      () {
+        _frameTimer = null;
+        int microseconds = _frameTime.inMicroseconds;
+        _frameTime += const Duration(milliseconds: 16);
+        Timer.run(() {
+          _beginFrame(microseconds);
+        });
+        Timer.run(() {
+          _drawFrame();
+        });
+      },
+    );
+  }
 
   /// Additional accessibility features that may be enabled by the platform.
   AccessibilityFeatures get accessibilityFeatures => configuration.accessibilityFeatures;
@@ -855,8 +874,7 @@
   ///  * [Navigator], a widget that handles routing.
   ///  * [SystemChannels.navigation], which handles subsequent navigation
   ///    requests from the embedder.
-  String get defaultRouteName => _defaultRouteName();
-  String _defaultRouteName() { throw UnimplementedError(); }
+  String get defaultRouteName => '/';
 }
 
 /// Configuration of the platform.
diff --git a/lib/src/ui/semantics.dart b/lib/src/ui/semantics.dart
index 5a08f50..3b78720 100644
--- a/lib/src/ui/semantics.dart
+++ b/lib/src/ui/semantics.dart
@@ -627,11 +627,9 @@
 /// Once created, the [SemanticsUpdate] objects can be passed to
 /// [PlatformDispatcher.updateSemantics] to update the semantics conveyed to the
 /// user.
-@pragma('vm:entry-point')
-class SemanticsUpdateBuilder extends NativeFieldWrapperClass2 {
+class SemanticsUpdateBuilder {
   /// Creates an empty [SemanticsUpdateBuilder] object.
-  @pragma('vm:entry-point')
-  SemanticsUpdateBuilder() { _constructor(); }
+    SemanticsUpdateBuilder() { _constructor(); }
   void _constructor() { throw UnimplementedError(); }
 
   /// Update the information associated with the node with the given `id`.
@@ -849,14 +847,12 @@
 ///
 /// Semantics updates can be applied to the system's retained semantics tree
 /// using the [PlatformDispatcher.updateSemantics] method.
-@pragma('vm:entry-point')
-class SemanticsUpdate extends NativeFieldWrapperClass2 {
+class SemanticsUpdate {
   /// This class is created by the engine, and should not be instantiated
   /// or extended directly.
   ///
   /// To create a SemanticsUpdate object, use a [SemanticsUpdateBuilder].
-  @pragma('vm:entry-point')
-  SemanticsUpdate._();
+    SemanticsUpdate._();
 
   /// Releases the resources used by this semantics update.
   ///
diff --git a/lib/src/ui/text.dart b/lib/src/ui/text.dart
index cf76fe7..5f9f0df 100644
--- a/lib/src/ui/text.dart
+++ b/lib/src/ui/text.dart
@@ -739,13 +739,20 @@
          shadows,
          fontFeatures,
        ),
-       _fontFamily = fontFamily ?? '',
+       _color = color,
+       _decoration = decoration,
+       _decorationColor = decorationColor,
+       _decorationStyle = decorationStyle,
+       _decorationThickness = decorationThickness,
+       _fontFamily = fontFamily,
        _fontFamilyFallback = fontFamilyFallback,
        _fontSize = fontSize,
+       _fontWeight = fontWeight,
+       _fontStyle = fontStyle,
+       _textBaseline = textBaseline,
        _letterSpacing = letterSpacing,
        _wordSpacing = wordSpacing,
        _height = height,
-       _decorationThickness = decorationThickness,
        _locale = locale,
        _background = background,
        _foreground = foreground,
@@ -753,7 +760,7 @@
        _fontFeatures = fontFeatures;
 
   final Int32List _encoded;
-  final String _fontFamily;
+  final String? _fontFamily;
   final List<String>? _fontFamilyFallback;
   final double? _fontSize;
   final double? _letterSpacing;
@@ -765,6 +772,50 @@
   final Paint? _foreground;
   final List<Shadow>? _shadows;
   final List<FontFeature>? _fontFeatures;
+  final Color? _color;
+  final TextDecoration? _decoration;
+  final Color? _decorationColor;
+  final TextDecorationStyle? _decorationStyle;
+  final FontWeight? _fontWeight;
+  final FontStyle? _fontStyle;
+  final TextBaseline? _textBaseline;
+
+
+  TextStyle _mergeInto(TextStyle other) {
+    return TextStyle(
+      color: _color ?? other._color,
+      decoration: _decoration ?? other._decoration,
+      decorationColor: _decorationColor ?? other._decorationColor,
+      decorationStyle: _decorationStyle ?? other._decorationStyle,
+      decorationThickness: _decorationThickness ?? other._decorationThickness,
+      fontWeight: _fontWeight ?? other._fontWeight,
+      fontStyle: _fontStyle ?? other._fontStyle,
+      textBaseline: _textBaseline ?? other._textBaseline,
+      fontFamily: _fontFamily ?? other._fontFamily,
+      fontFamilyFallback: _fontFamilyFallback ?? other._fontFamilyFallback,
+      fontSize: _fontSize ?? other._fontSize,
+      letterSpacing: _letterSpacing ?? other._letterSpacing,
+      wordSpacing: _wordSpacing ?? other._wordSpacing,
+      height: _height ?? other._height,
+      locale: _locale ?? other._locale,
+      background: _background ?? other._background,
+      foreground: _foreground ?? other._foreground,
+      shadows: _shadows == null
+        ? other._shadows == null
+          ? null
+          : other._shadows
+        : other._shadows == null
+          ? _shadows
+          : <Shadow>[..._shadows!, ...other._shadows!],
+      fontFeatures: _fontFeatures == null
+        ? other._fontFeatures == null
+          ? null
+          : other._fontFeatures
+        : other._fontFeatures == null
+          ? _fontFeatures
+          : <FontFeature>[..._fontFeatures!, ...other._fontFeatures!],
+    );
+  }
 
   @override
   bool operator ==(Object other) {
@@ -991,21 +1042,43 @@
          ellipsis,
          locale,
        ),
+       _textAlign = textAlign ?? TextAlign.start,
+       _textDirection = textDirection ?? TextDirection.ltr,
+       _maxLines = maxLines,
        _fontFamily = fontFamily,
        _fontSize = fontSize,
        _height = height,
+       _textHeightBehavior = textHeightBehavior ?? const TextHeightBehavior(),
+       _fontWeight = fontWeight ?? FontWeight.normal,
+       _fontStyle = fontStyle ?? FontStyle.normal,
        _strutStyle = strutStyle,
        _ellipsis = ellipsis,
        _locale = locale;
 
   final Int32List _encoded;
+  final TextAlign _textAlign;
+  final TextDirection _textDirection;
+  final int? _maxLines;
   final String? _fontFamily;
   final double? _fontSize;
   final double? _height;
+  final TextHeightBehavior _textHeightBehavior;
+  final FontWeight _fontWeight;
+  final FontStyle _fontStyle;
   final StrutStyle? _strutStyle;
   final String? _ellipsis;
   final Locale? _locale;
 
+  TextStyle _toTextStyle() {
+    return TextStyle(
+      fontFamily: _fontFamily,
+      fontSize: _fontSize,
+      fontStyle: _fontStyle,
+      fontWeight: _fontWeight,
+      height: _height,
+    );
+  }
+
   @override
   bool operator ==(Object other) {
     if (identical(this, other))
@@ -1298,7 +1371,6 @@
 /// A rectangle enclosing a run of text.
 ///
 /// This is similar to [Rect] but includes an inherent [TextDirection].
-@pragma('vm:entry-point')
 class TextBox {
   /// Creates an object that describes a box containing text.
   const TextBox.fromLTRBD(
@@ -1866,50 +1938,59 @@
 ///
 /// Paragraphs can be displayed on a [Canvas] using the [Canvas.drawParagraph]
 /// method.
-@pragma('vm:entry-point')
-class Paragraph extends NativeFieldWrapperClass2 {
+class Paragraph {
   /// This class is created by the engine, and should not be instantiated
   /// or extended directly.
   ///
   /// To create a [Paragraph] object, use a [ParagraphBuilder].
-  @pragma('vm:entry-point')
-  Paragraph._();
+  Paragraph._(this._paragraphStyle, this._spans);
+
+  final ParagraphStyle _paragraphStyle;
+  final List<_Span> _spans;
+  late List<List<_SpanBox>> _boxes;
 
   /// The amount of horizontal space this paragraph occupies.
   ///
   /// Valid only after [layout] has been called.
-  double get width { throw UnimplementedError(); }
+  double get width => _width;
+  double _width = 0;
 
   /// The amount of vertical space this paragraph occupies.
   ///
   /// Valid only after [layout] has been called.
-  double get height { throw UnimplementedError(); }
+  double get height => _height;
+  double _height = 0;
 
   /// The distance from the left edge of the leftmost glyph to the right edge of
   /// the rightmost glyph in the paragraph.
   ///
   /// Valid only after [layout] has been called.
-  double get longestLine { throw UnimplementedError(); }
+  double get longestLine => _longestLine;
+  double _longestLine = 0;
 
   /// The minimum width that this paragraph could be without failing to paint
   /// its contents within itself.
   ///
   /// Valid only after [layout] has been called.
-  double get minIntrinsicWidth { throw UnimplementedError(); }
+  double get minIntrinsicWidth => _minIntrinsicWidth;
+  double _minIntrinsicWidth = 0;
 
   /// Returns the smallest width beyond which increasing the width never
   /// decreases the height.
   ///
   /// Valid only after [layout] has been called.
-  double get maxIntrinsicWidth { throw UnimplementedError(); }
+  double get maxIntrinsicWidth => _maxIntrinsicWidth;
+  double _maxIntrinsicWidth = 0;
 
   /// The distance from the top of the paragraph to the alphabetic
   /// baseline of the first line, in logical pixels.
-  double get alphabeticBaseline { throw UnimplementedError(); }
+  double get alphabeticBaseline => _alphabeticBaseline;
+  double _alphabeticBaseline = 0;
 
   /// The distance from the top of the paragraph to the ideographic
   /// baseline of the first line, in logical pixels.
-  double get ideographicBaseline { throw UnimplementedError(); }
+  double get ideographicBaseline => _ideographicBaseline;
+  double _ideographicBaseline = 0;
 
   /// True if there is more vertical content, but the text was truncated, either
   /// because we reached `maxLines` lines of text or because the `maxLines` was
@@ -1918,28 +1999,59 @@
   ///
   /// See the discussion of the `maxLines` and `ellipsis` arguments at
   /// [new ParagraphStyle].
-  bool get didExceedMaxLines { throw UnimplementedError(); }
+  bool get didExceedMaxLines => _didExceedMaxLines;
+  bool _didExceedMaxLines = false;
 
   /// Computes the size and position of each glyph in the paragraph.
   ///
   /// The [ParagraphConstraints] control how wide the text is allowed to be.
-  void layout(ParagraphConstraints constraints) => _layout(constraints.width);
-  void _layout(double width) { throw UnimplementedError(); }
+  void layout(ParagraphConstraints constraints) {
+    _boxes = <List<_SpanBox>>[];
+    double paragraphRight = 0;
+    double minIntrinsicWidth = 0;
+    double maxIntrinsicWidth = 0;
 
-  List<TextBox> _decodeTextBoxes(Float32List encoded) {
-    final int count = encoded.length ~/ 5;
-    final List<TextBox> boxes = <TextBox>[];
-    int position = 0;
-    for (int index = 0; index < count; index += 1) {
-      boxes.add(TextBox.fromLTRBD(
-        encoded[position++],
-        encoded[position++],
-        encoded[position++],
-        encoded[position++],
-        TextDirection.values[encoded[position++].toInt()],
-      ));
+    double currentLineTop = 0;
+    double currentLineWidth = 0;
+    double currentLineHeight = 0;
+    List<_SpanBox>? currentLine;
+
+    for (_Span span in _spans) {
+      final double spanWidth = span.width;
+      minIntrinsicWidth = math.max(minIntrinsicWidth, spanWidth);
+      maxIntrinsicWidth += spanWidth;
+      final double availableWidth = constraints.width - currentLineWidth;
+
+      // First span in paragraph, or span doesn't fit? Start a new line.
+      if (currentLine == null || spanWidth > availableWidth) {
+        _boxes.add(currentLine = <_SpanBox>[]);
+        currentLineTop += currentLineHeight;
+        currentLineWidth = 0;
+        currentLineHeight = 0;
+      }
+
+      final _SpanBox _spanBox = _SpanBox.fromLTRBS(
+        currentLineWidth,
+        currentLineTop,
+        currentLineWidth + spanWidth,
+        currentLineTop + span.height,
+        span,
+      );
+      currentLine.add(_spanBox);
+
+      currentLineWidth += spanWidth;
+      currentLineHeight = math.max(currentLineHeight, span.height);
+      paragraphRight = math.max(paragraphRight, currentLineWidth);
     }
-    return boxes;
+
+    _minIntrinsicWidth = math.min(minIntrinsicWidth, maxIntrinsicWidth);
+    _maxIntrinsicWidth = maxIntrinsicWidth;
+    _width = paragraphRight;
+    _height = currentLineTop + currentLineHeight;
+    final int? maxLines = _paragraphStyle._maxLines;
+    _didExceedMaxLines = maxLines == null
+      ? false
+      : _boxes.length > maxLines;
   }
 
   /// Returns a list of text boxes that enclose the given text range.
@@ -1958,10 +2070,8 @@
   List<TextBox> getBoxesForRange(int start, int end, {BoxHeightStyle boxHeightStyle = BoxHeightStyle.tight, BoxWidthStyle boxWidthStyle = BoxWidthStyle.tight}) {
     assert(boxHeightStyle != null); // ignore: unnecessary_null_comparison
     assert(boxWidthStyle != null); // ignore: unnecessary_null_comparison
-    return _decodeTextBoxes(_getBoxesForRange(start, end, boxHeightStyle.index, boxWidthStyle.index));
+    throw UnimplementedError();
   }
-  // See paragraph.cc for the layout of this return value.
-  Float32List _getBoxesForRange(int start, int end, int boxHeightStyle, int boxWidthStyle) { throw UnimplementedError(); }
 
   /// Returns a list of text boxes that enclose all placeholders in the paragraph.
   ///
@@ -1971,16 +2081,27 @@
   /// Coordinates of the [TextBox] are relative to the upper-left corner of the paragraph,
   /// where positive y values indicate down.
   List<TextBox> getBoxesForPlaceholders() {
-    return _decodeTextBoxes(_getBoxesForPlaceholders());
+    final List<TextBox> result = <TextBox>[];
+    for (List<_SpanBox> line in _boxes) {
+      for (_SpanBox box in line) {
+        if (box.span is _Placeholder) {
+          result.add(TextBox.fromLTRBD(
+            box.left,
+            box.top,
+            box.right,
+            box.bottom,
+            _paragraphStyle._textDirection,
+          ));
+        }
+      }
+    }
+    return result;
   }
-  Float32List _getBoxesForPlaceholders() { throw UnimplementedError(); }
 
   /// Returns the text position closest to the given offset.
   TextPosition getPositionForOffset(Offset offset) {
-    final List<int> encoded = _getPositionForOffset(offset.dx, offset.dy);
-    return TextPosition(offset: encoded[0], affinity: TextAffinity.values[encoded[1]]);
+    throw UnimplementedError();
   }
-  List<int> _getPositionForOffset(double dx, double dy) { throw UnimplementedError(); }
 
   /// Returns the [TextRange] of the word at the given [TextPosition].
   ///
@@ -1989,10 +2110,8 @@
   /// [offset, offset+1]. Word boundaries are defined more precisely in Unicode
   /// Standard Annex #29 http://www.unicode.org/reports/tr29/#Word_Boundaries
   TextRange getWordBoundary(TextPosition position) {
-    final List<int> boundary = _getWordBoundary(position.offset);
-    return TextRange(start: boundary[0], end: boundary[1]);
+    throw UnimplementedError();
   }
-  List<int> _getWordBoundary(int offset) { throw UnimplementedError(); }
 
   /// Returns the [TextRange] of the line at the given [TextPosition].
   ///
@@ -2003,15 +2122,8 @@
   /// This can potentially be expensive, since it needs to compute the line
   /// metrics, so use it sparingly.
   TextRange getLineBoundary(TextPosition position) {
-    final List<int> boundary = _getLineBoundary(position.offset);
-    return TextRange(start: boundary[0], end: boundary[1]);
+    throw UnimplementedError();
   }
-  List<int> _getLineBoundary(int offset) { throw UnimplementedError(); }
-
-  // Redirecting the paint function in this way solves some dependency problems
-  // in the C++ code. If we straighten out the C++ dependencies, we can remove
-  // this indirection.
-  void _paint(Canvas canvas, double x, double y) { throw UnimplementedError(); }
 
   /// Returns the full list of [LineMetrics] that describe in detail the various
   /// metrics of each laid out line.
@@ -2043,6 +2155,48 @@
   Float64List _computeLineMetrics() { throw UnimplementedError(); }
 }
 
+abstract class _Span {
+  double get width;
+  double get height;
+}
+
+class _SpanBox {
+  _SpanBox.fromLTRBS(this.left, this.top, this.right, this.bottom, this.span);
+  final double left;
+  final double top;
+  final double right;
+  final double bottom;
+  final _Span span;
+}
+
+class _TextSpan extends _Span {
+  _TextSpan(this._style, this._text);
+  final TextStyle _style;
+  final String _text;
+
+  @override
+  double get width => _text.length * (_style._fontSize ?? 10.0);
+
+  @override
+  double get height => _style._height ?? _style._fontSize ?? 10.0;
+}
+
+class _Placeholder extends _Span {
+  _Placeholder(this._width, this._height, this._alignment, this._baselineOffset, this._baseline);
+
+  final double _width;
+  final double _height;
+  final int _alignment;
+  final double _baselineOffset;
+  final int? _baseline;
+
+  @override
+  double get width => _width;
+
+  @override
+  double get height => _height;
+}
+
 /// Builds a [Paragraph] containing text with the given styling information.
 ///
 /// To set the paragraph's alignment, truncation, and ellipsizing behavior, pass
@@ -2057,12 +2211,11 @@
 ///
 /// After constructing a [Paragraph], call [Paragraph.layout] on it and then
 /// paint it with [Canvas.drawParagraph].
-class ParagraphBuilder extends NativeFieldWrapperClass2 {
+class ParagraphBuilder {
 
   /// Creates a new [ParagraphBuilder] object, which is used to create a
   /// [Paragraph].
-  @pragma('vm:entry-point')
-  ParagraphBuilder(ParagraphStyle style) {
+  factory ParagraphBuilder(ParagraphStyle style) {
     List<String>? strutFontFamilies;
     final StrutStyle? strutStyle = style._strutStyle;
     if (strutStyle != null) {
@@ -2073,28 +2226,21 @@
       if (strutStyle._fontFamilyFallback != null)
         strutFontFamilies.addAll(strutStyle._fontFamilyFallback!);
     }
-    _constructor(
-      style._encoded,
-      strutStyle?._encoded,
-      style._fontFamily,
-      strutFontFamilies,
-      style._fontSize,
-      style._height,
-      style._ellipsis,
-      _encodeLocale(style._locale)
-    );
+    return ParagraphBuilder._(style, style._toTextStyle(), strutFontFamilies);
   }
 
-  void _constructor(
-    Int32List encoded,
-    ByteData? strutData,
-    String? fontFamily,
-    List<dynamic>? strutFontFamily,
-    double? fontSize,
-    double? height,
-    String? ellipsis,
-    String locale
-  ) { throw UnimplementedError(); }
+  ParagraphBuilder._(this._style, TextStyle textStyle, this._strutFontFamilies)
+      : _currentStyle = textStyle {
+    _styleStack.add(_currentStyle);
+  }
+
+  final ParagraphStyle _style;
+  final List<String>? _strutFontFamilies;
+
+  final List<TextStyle> _styleStack = <TextStyle>[];
+  TextStyle _currentStyle;
+
+  List<_Span> _spans = <_Span>[];
 
   /// The number of placeholders currently in the paragraph.
   int get placeholderCount => _placeholderCount;
@@ -2108,8 +2254,11 @@
   ///
   /// See [pop] for details.
   void pushStyle(TextStyle style) {
+    _currentStyle = style._mergeInto(_currentStyle);
+    _styleStack.add(_currentStyle);
+
     final List<String> fullFontFamilies = <String>[];
-    fullFontFamilies.add(style._fontFamily);
+    fullFontFamilies.add(style._fontFamily ?? '');
     if (style._fontFamilyFallback != null)
     fullFontFamilies.addAll(style._fontFamilyFallback!);
 
@@ -2123,109 +2272,29 @@
         byteOffset += FontFeature._kEncodedSize;
       }
     }
-
-    _pushStyle(
-      style._encoded,
-      fullFontFamilies,
-      style._fontSize,
-      style._letterSpacing,
-      style._wordSpacing,
-      style._height,
-      style._decorationThickness,
-      _encodeLocale(style._locale),
-      style._background?._objects,
-      style._background?._data,
-      style._foreground?._objects,
-      style._foreground?._data,
-      Shadow._encodeShadows(style._shadows),
-      encodedFontFeatures,
-    );
   }
 
-  void _pushStyle(
-    Int32List encoded,
-    List<dynamic> fontFamilies,
-    double? fontSize,
-    double? letterSpacing,
-    double? wordSpacing,
-    double? height,
-    double? decorationThickness,
-    String locale,
-    List<dynamic>? backgroundObjects,
-    ByteData? backgroundData,
-    List<dynamic>? foregroundObjects,
-    ByteData? foregroundData,
-    ByteData shadowsData,
-    ByteData? fontFeaturesData,
-  ) { throw UnimplementedError(); }
-
-  static String _encodeLocale(Locale? locale) => locale?.toString() ?? '';
-
   /// Ends the effect of the most recent call to [pushStyle].
   ///
   /// Internally, the paragraph builder maintains a stack of text styles. Text
   /// added to the paragraph is affected by all the styles in the stack. Calling
   /// [pop] removes the topmost style in the stack, leaving the remaining styles
   /// in effect.
-  void pop() { throw UnimplementedError(); }
+  void pop() {
+    _currentStyle = _styleStack.removeLast();
+  }
+
+  static final RegExp _whitespace = RegExp(r'\s+');
 
   /// Adds the given text to the paragraph.
   ///
   /// The text will be styled according to the current stack of text styles.
   void addText(String text) {
-    final String? error = _addText(text);
-    if (error != null)
-      throw ArgumentError(error);
+    for (String span in text.split(_whitespace)) {
+      _spans.add(_TextSpan(_currentStyle, span));
+    }
   }
-  String? _addText(String text) { throw UnimplementedError(); }
 
-  /// Adds an inline placeholder space to the paragraph.
-  ///
-  /// The paragraph will contain a rectangular space with no text of the dimensions
-  /// specified.
-  ///
-  /// The `width` and `height` parameters specify the size of the placeholder rectangle.
-  ///
-  /// The `alignment` parameter specifies how the placeholder rectangle will be vertically
-  /// aligned with the surrounding text. When [PlaceholderAlignment.baseline],
-  /// [PlaceholderAlignment.aboveBaseline], and [PlaceholderAlignment.belowBaseline]
-  /// alignment modes are used, the baseline needs to be set with the `baseline`.
-  /// When using [PlaceholderAlignment.baseline], `baselineOffset` indicates the distance
-  /// of the baseline down from the top of of the rectangle. The default `baselineOffset`
-  /// is the `height`.
-  ///
-  /// Examples:
-  ///
-  /// * For a 30x50 placeholder with the bottom edge aligned with the bottom of the text, use:
-  /// `addPlaceholder(30, 50, PlaceholderAlignment.bottom);`
-  /// * For a 30x50 placeholder that is vertically centered around the text, use:
-  /// `addPlaceholder(30, 50, PlaceholderAlignment.middle);`.
-  /// * For a 30x50 placeholder that sits completely on top of the alphabetic baseline, use:
-  /// `addPlaceholder(30, 50, PlaceholderAlignment.aboveBaseline, baseline: TextBaseline.alphabetic)`.
-  /// * For a 30x50 placeholder with 40 pixels above and 10 pixels below the alphabetic baseline, use:
-  /// `addPlaceholder(30, 50, PlaceholderAlignment.baseline, baseline: TextBaseline.alphabetic, baselineOffset: 40)`.
-  ///
-  /// Lines are permitted to break around each placeholder.
-  ///
-  /// Decorations will be drawn based on the font defined in the most recently
-  /// pushed [TextStyle]. The decorations are drawn as if unicode text were present
-  /// in the placeholder space, and will draw the same regardless of the height and
-  /// alignment of the placeholder. To hide or manually adjust decorations to fit,
-  /// a text style with the desired decoration behavior should be pushed before
-  /// adding a placeholder.
-  ///
-  /// Any decorations drawn through a placeholder will exist on the same canvas/layer
-  /// as the text. This means any content drawn on top of the space reserved by
-  /// the placeholder will be drawn over the decoration, possibly obscuring the
-  /// decoration.
-  ///
-  /// Placeholders are represented by a unicode 0xFFFC "object replacement character"
-  /// in the text buffer. For each placeholder, one object replacement character is
-  /// added on to the text buffer.
-  ///
-  /// The `scale` parameter will scale the `width` and `height` by the specified amount,
-  /// and keep track of the scale. The scales of placeholders added can be accessed
-  /// through [placeholderScales]. This is primarily used for accessibility scaling.
   void addPlaceholder(double width, double height, PlaceholderAlignment alignment, {
     double scale = 1.0,
     double? baselineOffset,
@@ -2238,23 +2307,22 @@
     // Default the baselineOffset to height if null. This will place the placeholder
     // fully above the baseline, similar to [PlaceholderAlignment.aboveBaseline].
     baselineOffset = baselineOffset ?? height;
-    _addPlaceholder(width * scale, height * scale, alignment.index, baselineOffset * scale, baseline == null ? null : baseline.index);
+    _spans.add(_Placeholder(
+      width * scale,
+      height * scale,
+      alignment.index,
+      baselineOffset * scale,
+      baseline?.index,
+    ));
     _placeholderCount++;
     _placeholderScales.add(scale);
   }
-  String? _addPlaceholder(double width, double height, int alignment, double baselineOffset, int? baseline) { throw UnimplementedError(); }
 
-  /// Applies the given paragraph style and returns a [Paragraph] containing the
-  /// added text and associated styling.
-  ///
-  /// After calling this function, the paragraph builder object is invalid and
-  /// cannot be used further.
   Paragraph build() {
-    final Paragraph paragraph = Paragraph._();
-    _build(paragraph);
+    final Paragraph paragraph = Paragraph._(_style, _spans);
+    _spans = <_Span>[];
     return paragraph;
   }
-  void _build(Paragraph outParagraph) { throw UnimplementedError(); }
 }
 
 /// Loads a font from a buffer and makes it available for rendering text.
diff --git a/lib/src/ui/window.dart b/lib/src/ui/window.dart
index 3654a17..ac3c855 100644
--- a/lib/src/ui/window.dart
+++ b/lib/src/ui/window.dart
@@ -253,8 +253,9 @@
   ///   scheduling of frames.
   /// * [RendererBinding], the Flutter framework class which manages layout and
   ///   painting.
-  void render(Scene scene) => _render(scene, this);
-  void _render(Scene scene, FlutterView view) { throw UnimplementedError(); }
+  void render(Scene scene) {
+    // TODO(yjbanov): implement a basic preroll for better benchmark realism.
+  }
 }
 
 /// A top-level platform window displaying a Flutter layer tree drawn from a
@@ -306,7 +307,27 @@
 /// [PlatformDispatcher.instance] for more details about this recommendation.
 class SingletonFlutterWindow extends FlutterWindow {
   SingletonFlutterWindow._(Object windowId, PlatformDispatcher platformDispatcher)
-      : super._(windowId, platformDispatcher);
+      : super._(windowId, platformDispatcher) {
+    platformDispatcher._updateLifecycleState('resumed');
+    _updateWindowMetrics(
+      0, // id
+      1.0, // devicePixelRatio
+      1024, // width
+      768, // height
+      0, // viewPaddingTop
+      0, // viewPaddingRight
+      0, // viewPaddingBottom
+      0, // viewPaddingLeft
+      0, // viewInsetTop
+      0, // viewInsetRight
+      0, // viewInsetBottom
+      0, // viewInsetLeft
+      0, // systemGestureInsetTop
+      0, // systemGestureInsetRight
+      0, // systemGestureInsetBottom
+      0, // systemGestureInsetLeft
+    );
+  }
 
   /// A callback that is invoked whenever the [devicePixelRatio],
   /// [physicalSize], [padding], [viewInsets], [PlatformDispatcher.views], or