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);
+ });
}