remove usage of Dart_New for paragraph/libtxt (#16837)

diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 21d438c..d0182f4 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -354,13 +354,11 @@
 FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.h
 FILE: ../../../flutter/lib/ui/text/font_collection.cc
 FILE: ../../../flutter/lib/ui/text/font_collection.h
-FILE: ../../../flutter/lib/ui/text/line_metrics.cc
 FILE: ../../../flutter/lib/ui/text/line_metrics.h
 FILE: ../../../flutter/lib/ui/text/paragraph.cc
 FILE: ../../../flutter/lib/ui/text/paragraph.h
 FILE: ../../../flutter/lib/ui/text/paragraph_builder.cc
 FILE: ../../../flutter/lib/ui/text/paragraph_builder.h
-FILE: ../../../flutter/lib/ui/text/text_box.cc
 FILE: ../../../flutter/lib/ui/text/text_box.h
 FILE: ../../../flutter/lib/ui/ui.dart
 FILE: ../../../flutter/lib/ui/ui_dart_state.cc
diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn
index 4cc81df..c904141 100644
--- a/lib/ui/BUILD.gn
+++ b/lib/ui/BUILD.gn
@@ -81,13 +81,11 @@
     "text/asset_manager_font_provider.h",
     "text/font_collection.cc",
     "text/font_collection.h",
-    "text/line_metrics.cc",
     "text/line_metrics.h",
     "text/paragraph.cc",
     "text/paragraph.h",
     "text/paragraph_builder.cc",
     "text/paragraph_builder.h",
-    "text/text_box.cc",
     "text/text_box.h",
     "ui_dart_state.cc",
     "ui_dart_state.h",
diff --git a/lib/ui/text.dart b/lib/ui/text.dart
index bba18de..01b4b8c 100644
--- a/lib/ui/text.dart
+++ b/lib/ui/text.dart
@@ -1306,16 +1306,6 @@
     this.direction,
   );
 
-  @pragma('vm:entry-point')
-  // ignore: unused_element
-  TextBox._(
-    this.left,
-    this.top,
-    this.right,
-    this.bottom,
-    int directionIndex,
-  ) : direction = TextDirection.values[directionIndex];
-
   /// The left edge of the text box, irrespective of direction.
   ///
   /// To get the leading edge (which may depend on the [direction]), consider [start].
@@ -1764,20 +1754,6 @@
     this.lineNumber,
   });
 
-  @pragma('vm:entry-point')
-  // ignore: unused_element
-  LineMetrics._(
-    this.hardBreak,
-    this.ascent,
-    this.descent,
-    this.unscaledAscent,
-    this.height,
-    this.width,
-    this.left,
-    this.baseline,
-    this.lineNumber,
-  );
-
   /// True if this line ends with an explicit line break (e.g. '\n') or is the end
   /// of the paragraph. False otherwise.
   final bool hardBreak;
@@ -1843,6 +1819,39 @@
   ///
   /// For example, the first line is line 0, second line is line 1.
   final int lineNumber;
+
+  @override
+  bool operator ==(Object other) {
+    if (other.runtimeType != runtimeType) {
+      return false;
+    }
+    return other is LineMetrics
+        && other.hardBreak == hardBreak
+        && other.ascent == ascent
+        && other.descent == descent
+        && other.unscaledAscent == unscaledAscent
+        && other.height == height
+        && other.width == width
+        && other.left == left
+        && other.baseline == baseline
+        && other.lineNumber == lineNumber;
+  }
+
+  @override
+  int get hashCode => hashValues(hardBreak, ascent, descent, unscaledAscent, height, width, left, baseline, lineNumber);
+
+  @override
+  String toString() {
+    return 'LineMetrics(hardBreak: $hardBreak, '
+                       'ascent: $ascent, '
+                       'descent: $descent, '
+                       'unscaledAscent: $unscaledAscent, '
+                       'height: $height, '
+                       'width: $width, '
+                       'left: $left, '
+                       'baseline: $baseline, '
+                       'lineNumber: $lineNumber)';
+  }
 }
 
 /// A paragraph of text.
@@ -1914,6 +1923,21 @@
   void layout(ParagraphConstraints constraints) => _layout(constraints.width);
   void _layout(double width) native 'Paragraph_layout';
 
+  List<TextBox> _decodeTextBoxes(Float32List encoded) {
+    final int count = encoded.length ~/ 5;
+    final List<TextBox> boxes = List<TextBox>(count);
+    int position = 0;
+    for (int index = 0; index < count; index += 1) {
+      boxes[index] = TextBox.fromLTRBD(
+        encoded[position++],
+        encoded[position++],
+        encoded[position++],
+        encoded[position++],
+        TextDirection.values[encoded[position++].toInt()],
+      );
+    }
+    return boxes;
+  }
   /// Returns a list of text boxes that enclose the given text range.
   ///
   /// The [boxHeightStyle] and [boxWidthStyle] parameters allow customization
@@ -1930,9 +1954,10 @@
   List<TextBox> getBoxesForRange(int start, int end, {BoxHeightStyle boxHeightStyle = BoxHeightStyle.tight, BoxWidthStyle boxWidthStyle = BoxWidthStyle.tight}) {
     assert(boxHeightStyle != null);
     assert(boxWidthStyle != null);
-    return _getBoxesForRange(start, end, boxHeightStyle.index, boxWidthStyle.index);
+    return _decodeTextBoxes(_getBoxesForRange(start, end, boxHeightStyle.index, boxWidthStyle.index));
   }
-  List<TextBox> _getBoxesForRange(int start, int end, int boxHeightStyle, int boxWidthStyle) native 'Paragraph_getRectsForRange';
+  // See paragraph.cc for the layout of this return value.
+  Float32List _getBoxesForRange(int start, int end, int boxHeightStyle, int boxWidthStyle) native 'Paragraph_getRectsForRange';
 
   /// Returns a list of text boxes that enclose all placeholders in the paragraph.
   ///
@@ -1940,7 +1965,10 @@
   ///
   /// Coordinates of the [TextBox] are relative to the upper-left corner of the paragraph,
   /// where positive y values indicate down.
-  List<TextBox> getBoxesForPlaceholders() native 'Paragraph_getRectsForPlaceholders';
+  List<TextBox> getBoxesForPlaceholders() {
+    return _decodeTextBoxes(_getBoxesForPlaceholders());
+  }
+  Float32List _getBoxesForPlaceholders() native 'Paragraph_getRectsForPlaceholders';
 
   /// Returns the text position closest to the given offset.
   TextPosition getPositionForOffset(Offset offset) {
@@ -1987,7 +2015,27 @@
   ///
   /// This can potentially return a large amount of data, so it is not recommended
   /// to repeatedly call this. Instead, cache the results.
-  List<LineMetrics> computeLineMetrics() native 'Paragraph_computeLineMetrics';
+  List<LineMetrics> computeLineMetrics() {
+    final Float64List encoded = _computeLineMetrics();
+    final int count = encoded.length ~/ 9;
+    int position = 0;
+    final List<LineMetrics> metrics = List<LineMetrics>(count);
+    for (int index = 0; index < metrics.length; index += 1) {
+      metrics[index] = LineMetrics(
+        hardBreak:      encoded[position++] != 0,
+        ascent:         encoded[position++],
+        descent:        encoded[position++],
+        unscaledAscent: encoded[position++],
+        height:         encoded[position++],
+        width:          encoded[position++],
+        left:           encoded[position++],
+        baseline:       encoded[position++],
+        lineNumber:     encoded[position++].toInt(),
+      );
+    }
+    return metrics;
+  }
+  Float64List _computeLineMetrics() native 'Paragraph_computeLineMetrics';
 }
 
 /// Builds a [Paragraph] containing text with the given styling information.
@@ -2195,7 +2243,12 @@
   ///
   /// After calling this function, the paragraph builder object is invalid and
   /// cannot be used further.
-  Paragraph build() native 'ParagraphBuilder_build';
+  Paragraph build() {
+    final Paragraph paragraph = Paragraph._();
+    _build(paragraph);
+    return paragraph;
+  }
+  void _build(Paragraph outParagraph) native 'ParagraphBuilder_build';
 }
 
 /// Loads a font from a buffer and makes it available for rendering text.
diff --git a/lib/ui/text/line_metrics.cc b/lib/ui/text/line_metrics.cc
deleted file mode 100644
index a224e9b..0000000
--- a/lib/ui/text/line_metrics.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "flutter/lib/ui/text/line_metrics.h"
-
-#include "flutter/fml/logging.h"
-#include "third_party/tonic/dart_class_library.h"
-#include "third_party/tonic/dart_state.h"
-#include "third_party/tonic/logging/dart_error.h"
-
-using namespace flutter;
-
-namespace tonic {
-
-namespace {
-
-Dart_Handle GetLineMetricsType() {
-  DartClassLibrary& class_library = DartState::Current()->class_library();
-  Dart_Handle type =
-      Dart_HandleFromPersistent(class_library.GetClass("ui", "LineMetrics"));
-  FML_DCHECK(!LogIfError(type));
-  return type;
-}
-
-}  // anonymous namespace
-
-Dart_Handle DartConverter<flutter::LineMetrics>::ToDart(
-    const flutter::LineMetrics& val) {
-  constexpr int argc = 9;
-
-  Dart_Handle argv[argc] = {
-      tonic::ToDart(*val.hard_break), tonic::ToDart(*val.ascent),
-      tonic::ToDart(*val.descent), tonic::ToDart(*val.unscaled_ascent),
-      // We add then round to get the height. The
-      // definition of height here is different
-      // than the one in LibTxt.
-      tonic::ToDart(round(*val.ascent + *val.descent)),
-      tonic::ToDart(*val.width), tonic::ToDart(*val.left),
-      tonic::ToDart(*val.baseline), tonic::ToDart(*val.line_number)};
-  return Dart_New(GetLineMetricsType(), tonic::ToDart("_"), argc, argv);
-}
-
-Dart_Handle DartListFactory<flutter::LineMetrics>::NewList(intptr_t length) {
-  return Dart_NewListOfType(GetLineMetricsType(), length);
-}
-
-}  // namespace tonic
diff --git a/lib/ui/text/line_metrics.h b/lib/ui/text/line_metrics.h
index bcd53c3..f5f656c 100644
--- a/lib/ui/text/line_metrics.h
+++ b/lib/ui/text/line_metrics.h
@@ -59,17 +59,4 @@
 
 }  // namespace flutter
 
-namespace tonic {
-template <>
-struct DartConverter<flutter::LineMetrics> {
-  static Dart_Handle ToDart(const flutter::LineMetrics& val);
-};
-
-template <>
-struct DartListFactory<flutter::LineMetrics> {
-  static Dart_Handle NewList(intptr_t length);
-};
-
-}  // namespace tonic
-
 #endif  // FLUTTER_LIB_UI_TEXT_LINE_METRICS_H_
diff --git a/lib/ui/text/paragraph.cc b/lib/ui/text/paragraph.cc
index 2618c3f..92800db 100644
--- a/lib/ui/text/paragraph.cc
+++ b/lib/ui/text/paragraph.cc
@@ -94,28 +94,40 @@
   m_paragraph->Paint(sk_canvas, x, y);
 }
 
-std::vector<TextBox> Paragraph::getRectsForRange(unsigned start,
-                                                 unsigned end,
-                                                 unsigned boxHeightStyle,
-                                                 unsigned boxWidthStyle) {
-  std::vector<TextBox> result;
-  std::vector<txt::Paragraph::TextBox> boxes = m_paragraph->GetRectsForRange(
-      start, end, static_cast<txt::Paragraph::RectHeightStyle>(boxHeightStyle),
-      static_cast<txt::Paragraph::RectWidthStyle>(boxWidthStyle));
-  for (const txt::Paragraph::TextBox& box : boxes) {
-    result.emplace_back(box.rect, static_cast<TextDirection>(box.direction));
+static tonic::Float32List EncodeTextBoxes(
+    const std::vector<txt::Paragraph::TextBox>& boxes) {
+  // Layout:
+  // First value is the number of values.
+  // Then there are boxes.size() groups of 5 which are LTRBD, where D is the
+  // text direction index.
+  tonic::Float32List result(
+      Dart_NewTypedData(Dart_TypedData_kFloat32, boxes.size() * 5));
+  unsigned long position = 0;
+  for (unsigned long i = 0; i < boxes.size(); i++) {
+    const txt::Paragraph::TextBox& box = boxes[i];
+    result[position++] = box.rect.fLeft;
+    result[position++] = box.rect.fTop;
+    result[position++] = box.rect.fRight;
+    result[position++] = box.rect.fBottom;
+    result[position++] = static_cast<float>(box.direction);
   }
   return result;
 }
 
-std::vector<TextBox> Paragraph::getRectsForPlaceholders() {
-  std::vector<TextBox> result;
+tonic::Float32List Paragraph::getRectsForRange(unsigned start,
+                                               unsigned end,
+                                               unsigned boxHeightStyle,
+                                               unsigned boxWidthStyle) {
+  std::vector<txt::Paragraph::TextBox> boxes = m_paragraph->GetRectsForRange(
+      start, end, static_cast<txt::Paragraph::RectHeightStyle>(boxHeightStyle),
+      static_cast<txt::Paragraph::RectWidthStyle>(boxWidthStyle));
+  return EncodeTextBoxes(boxes);
+}
+
+tonic::Float32List Paragraph::getRectsForPlaceholders() {
   std::vector<txt::Paragraph::TextBox> boxes =
       m_paragraph->GetRectsForPlaceholders();
-  for (const txt::Paragraph::TextBox& box : boxes) {
-    result.emplace_back(box.rect, static_cast<TextDirection>(box.direction));
-  }
-  return result;
+  return EncodeTextBoxes(boxes);
 }
 
 Dart_Handle Paragraph::getPositionForOffset(double dx, double dy) {
@@ -152,14 +164,31 @@
   return result;
 }
 
-std::vector<LineMetrics> Paragraph::computeLineMetrics() {
-  std::vector<LineMetrics> result;
+tonic::Float64List Paragraph::computeLineMetrics() {
   std::vector<txt::LineMetrics> metrics = m_paragraph->GetLineMetrics();
-  for (txt::LineMetrics& line : metrics) {
-    result.emplace_back(&line.hard_break, &line.ascent, &line.descent,
-                        &line.unscaled_ascent, &line.height, &line.width,
-                        &line.left, &line.baseline, &line.line_number);
+
+  // Layout:
+  // boxes.size() groups of 9 which are the line metrics
+  // properties
+  tonic::Float64List result(
+      Dart_NewTypedData(Dart_TypedData_kFloat64, metrics.size() * 9));
+  unsigned long position = 0;
+  for (unsigned long i = 0; i < metrics.size(); i++) {
+    const txt::LineMetrics& line = metrics[i];
+    result[position++] = static_cast<double>(line.hard_break);
+    result[position++] = line.ascent;
+    result[position++] = line.descent;
+    result[position++] = line.unscaled_ascent;
+    // We add then round to get the height. The
+    // definition of height here is different
+    // than the one in LibTxt.
+    result[position++] = round(line.ascent + line.descent);
+    result[position++] = line.width;
+    result[position++] = line.left;
+    result[position++] = line.baseline;
+    result[position++] = static_cast<double>(line.line_number);
   }
+
   return result;
 }
 
diff --git a/lib/ui/text/paragraph.h b/lib/ui/text/paragraph.h
index 7aea607..73c79d3 100644
--- a/lib/ui/text/paragraph.h
+++ b/lib/ui/text/paragraph.h
@@ -23,9 +23,10 @@
   FML_FRIEND_MAKE_REF_COUNTED(Paragraph);
 
  public:
-  static fml::RefPtr<Paragraph> Create(
-      std::unique_ptr<txt::Paragraph> paragraph) {
-    return fml::MakeRefCounted<Paragraph>(std::move(paragraph));
+  static void Create(Dart_Handle paragraph_handle,
+                     std::unique_ptr<txt::Paragraph> txt_paragraph) {
+    auto paragraph = fml::MakeRefCounted<Paragraph>(std::move(txt_paragraph));
+    paragraph->AssociateWithDartWrapper(paragraph_handle);
   }
 
   ~Paragraph() override;
@@ -42,15 +43,15 @@
   void layout(double width);
   void paint(Canvas* canvas, double x, double y);
 
-  std::vector<TextBox> getRectsForRange(unsigned start,
-                                        unsigned end,
-                                        unsigned boxHeightStyle,
-                                        unsigned boxWidthStyle);
-  std::vector<TextBox> getRectsForPlaceholders();
+  tonic::Float32List getRectsForRange(unsigned start,
+                                      unsigned end,
+                                      unsigned boxHeightStyle,
+                                      unsigned boxWidthStyle);
+  tonic::Float32List getRectsForPlaceholders();
   Dart_Handle getPositionForOffset(double dx, double dy);
   Dart_Handle getWordBoundary(unsigned offset);
   Dart_Handle getLineBoundary(unsigned offset);
-  std::vector<LineMetrics> computeLineMetrics();
+  tonic::Float64List computeLineMetrics();
 
   size_t GetAllocationSize() override;
 
diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc
index 51739fc..0b6eea6 100644
--- a/lib/ui/text/paragraph_builder.cc
+++ b/lib/ui/text/paragraph_builder.cc
@@ -493,8 +493,8 @@
   return Dart_Null();
 }
 
-fml::RefPtr<Paragraph> ParagraphBuilder::build() {
-  return Paragraph::Create(m_paragraphBuilder->Build());
+void ParagraphBuilder::build(Dart_Handle paragraph_handle) {
+  Paragraph::Create(paragraph_handle, m_paragraphBuilder->Build());
 }
 
 }  // namespace flutter
diff --git a/lib/ui/text/paragraph_builder.h b/lib/ui/text/paragraph_builder.h
index eebc5e7..4f4a00b 100644
--- a/lib/ui/text/paragraph_builder.h
+++ b/lib/ui/text/paragraph_builder.h
@@ -69,7 +69,7 @@
                              double baseline_offset,
                              unsigned baseline);
 
-  fml::RefPtr<Paragraph> build();
+  void build(Dart_Handle paragraph_handle);
 
   static void RegisterNatives(tonic::DartLibraryNatives* natives);
 
diff --git a/lib/ui/text/text_box.cc b/lib/ui/text/text_box.cc
deleted file mode 100644
index 99438cf..0000000
--- a/lib/ui/text/text_box.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "flutter/lib/ui/text/text_box.h"
-
-#include "flutter/fml/logging.h"
-#include "third_party/tonic/dart_class_library.h"
-#include "third_party/tonic/dart_state.h"
-#include "third_party/tonic/logging/dart_error.h"
-
-using namespace flutter;
-
-namespace tonic {
-
-namespace {
-
-Dart_Handle GetTextBoxType() {
-  DartClassLibrary& class_library = DartState::Current()->class_library();
-  Dart_Handle type =
-      Dart_HandleFromPersistent(class_library.GetClass("ui", "TextBox"));
-  FML_DCHECK(!LogIfError(type));
-  return type;
-}
-
-}  // anonymous namespace
-
-Dart_Handle DartConverter<flutter::TextBox>::ToDart(
-    const flutter::TextBox& val) {
-  constexpr int argc = 5;
-  Dart_Handle argv[argc] = {
-      tonic::ToDart(val.rect.fLeft),
-      tonic::ToDart(val.rect.fTop),
-      tonic::ToDart(val.rect.fRight),
-      tonic::ToDart(val.rect.fBottom),
-      tonic::ToDart(static_cast<int>(val.direction)),
-  };
-  return Dart_New(GetTextBoxType(), tonic::ToDart("_"), argc, argv);
-}
-
-Dart_Handle DartListFactory<flutter::TextBox>::NewList(intptr_t length) {
-  return Dart_NewListOfType(GetTextBoxType(), length);
-}
-
-}  // namespace tonic
diff --git a/testing/dart/paragraph_builder_test.dart b/testing/dart/paragraph_builder_test.dart
index 81862dd..cf8ccce 100644
--- a/testing/dart/paragraph_builder_test.dart
+++ b/testing/dart/paragraph_builder_test.dart
@@ -8,6 +8,9 @@
 import 'package:test/test.dart';
 
 void main() {
+  // The actual values for font measurements will vary by platform slightly.
+  const double epsillon = 0.0001;
+
   test('Should be able to build and layout a paragraph', () {
     final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle());
     builder.addText('Hello');
@@ -25,4 +28,46 @@
     paragraphBuilder.build();
     paragraphBuilder.pushStyle(TextStyle());
   });
+
+  test('GetRectsForRange smoke test', () {
+    final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle());
+    builder.addText('Hello');
+    final Paragraph paragraph = builder.build();
+    expect(paragraph, isNotNull);
+
+    paragraph.layout(const ParagraphConstraints(width: 800.0));
+    expect(paragraph.width, isNonZero);
+    expect(paragraph.height, isNonZero);
+
+    final List<TextBox> boxes = paragraph.getBoxesForRange(0, 3);
+    expect(boxes.length, 1);
+    expect(boxes.first.left, 0);
+    expect(boxes.first.top, closeTo(0, epsillon));
+    expect(boxes.first.right, closeTo(42, epsillon));
+    expect(boxes.first.bottom, closeTo(14, epsillon));
+    expect(boxes.first.direction, TextDirection.ltr);
+  });
+
+  test('LineMetrics smoke test', () {
+    final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle());
+    builder.addText('Hello');
+    final Paragraph paragraph = builder.build();
+    expect(paragraph, isNotNull);
+
+    paragraph.layout(const ParagraphConstraints(width: 800.0));
+    expect(paragraph.width, isNonZero);
+    expect(paragraph.height, isNonZero);
+
+    final List<LineMetrics> metrics = paragraph.computeLineMetrics();
+    expect(metrics.length, 1);
+    expect(metrics.first.hardBreak, true);
+    expect(metrics.first.ascent, closeTo(11.200042724609375, epsillon));
+    expect(metrics.first.descent, closeTo(2.799957275390625, epsillon));
+    expect(metrics.first.unscaledAscent, closeTo(11.200042724609375, epsillon));
+    expect(metrics.first.height, 14.0);
+    expect(metrics.first.width, 70.0);
+    expect(metrics.first.left, 0.0);
+    expect(metrics.first.baseline, closeTo(11.200042724609375, epsillon));
+    expect(metrics.first.lineNumber, 0);
+  });
 }