Skip to content

Commit

Permalink
Expose LineMetrics in dart:ui (flutter#10670)
Browse files Browse the repository at this point in the history
  • Loading branch information
GaryQian authored Aug 26, 2019
1 parent eb92b09 commit 9f1eab2
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 91 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.cc
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
Expand Down
2 changes: 2 additions & 0 deletions lib/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ source_set("ui") {
"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",
Expand Down
110 changes: 110 additions & 0 deletions lib/ui/text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1569,6 +1569,107 @@ enum PlaceholderAlignment {
middle,
}

/// [LineMetrics] stores the measurements and statistics of a single line in the
/// paragraph.
///
/// The measurements here are for the line as a whole, and represent the maximum
/// extent of the line instead of per-run or per-glyph metrics. For more detailed
/// metrics, see [TextBox] and [Paragraph.getBoxesForRange].
///
/// [LineMetrics] should be obtained directly from the [Paragraph.computeLineMetrics]
/// method.
class LineMetrics {
/// Creates a [LineMetrics] object with only the specified values.
///
/// Omitted values will remain null. [Paragraph.computeLineMetrics] produces
/// fully defined [LineMetrics] with no null values.
LineMetrics({
this.hardBreak,
this.ascent,
this.descent,
this.unscaledAscent,
this.height,
this.width,
this.left,
this.baseline,
this.lineNumber,
});

@pragma('vm:entry-point')
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;

/// The rise from the [baseline] as calculated from the font and style for this line.
///
/// This is the final computed ascent and can be impacted by the strut, height, scaling,
/// as well as outlying runs that are very tall.
///
/// The [ascent] is provided as a positive value, even though it is typically defined
/// in fonts as negative. This is to ensure the signage of operations with these
/// metrics directly reflects the intended signage of the value. For example,
/// the y coordinate of the top edge of the line is `baseline - ascent`.
final double ascent;

/// The drop from the [baseline] as calculated from the font and style for this line.
///
/// This is the final computed ascent and can be impacted by the strut, height, scaling,
/// as well as outlying runs that are very tall.
///
/// The y coordinate of the bottom edge of the line is `baseline + descent`.
final double descent;

/// The rise from the [baseline] as calculated from the font and style for this line
/// ignoring the [TextStyle.height].
///
/// The [unscaledAscent] is provided as a positive value, even though it is typically
/// defined in fonts as negative. This is to ensure the signage of operations with
/// these metrics directly reflects the intended signage of the value.
final double unscaledAscent;

/// Total height of the line from the top edge to the bottom edge.
///
/// This is equivalent to `ascent + descent`
final double height;

/// Width of the line from the left edge of the leftmost glyph to the right
/// edge of the rightmost glyph.
///
/// This is not the same as the width of the pargraph.
///
/// See also:
///
/// * [Paragraph.width], the max width passed in during layout.
/// * [Paragraph.longestLine], the width of the longest line in the paragraph.
final double width;

/// The x coordinate of left edge of the line.
///
/// The right edge can be obtained with `left + width`.
final double left;

/// The y coordinate of the baseline for this line from the top of the paragraph.
final double baseline;

/// The number of this line in the overall paragraph, with the first line being
/// index zero.
///
/// For example, the first line is line 0, second line is line 1.
final int lineNumber;
}

/// A paragraph of text.
///
/// A paragraph retains the size and position of each glyph in the text and can
Expand Down Expand Up @@ -1684,6 +1785,15 @@ class Paragraph extends NativeFieldWrapperClass2 {
// in the C++ code. If we straighten out the C++ dependencies, we can remove
// this indirection.
void _paint(Canvas canvas, double x, double y) native 'Paragraph_paint';

/// Returns the full list of [LineMetrics] that describe in detail the various
/// metrics of each laid out line.
///
/// Not valid until after layout.
///
/// 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';
}

/// Builds a [Paragraph] containing text with the given styling information.
Expand Down
45 changes: 45 additions & 0 deletions lib/ui/text/line_metrics.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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),
tonic::ToDart(*val.height), 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
75 changes: 75 additions & 0 deletions lib/ui/text/line_metrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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.

#ifndef FLUTTER_LIB_UI_TEXT_LINE_METRICS_H_
#define FLUTTER_LIB_UI_TEXT_LINE_METRICS_H_

#include "third_party/dart/runtime/include/dart_api.h"
#include "third_party/tonic/converter/dart_converter.h"

namespace flutter {

struct LineMetrics {
const bool* hard_break;

// The final computed ascent and descent for the line. This can be impacted by
// the strut, height, scaling, as well as outlying runs that are very tall.
//
// The top edge is `baseline - ascent` and the bottom edge is `baseline +
// descent`. Ascent and descent are provided as positive numbers. Raw numbers
// for specific runs of text can be obtained in run_metrics_map. These values
// are the cumulative metrics for the entire line.
const double* ascent;
const double* descent;
const double* unscaled_ascent;
// Height of the line.
const double* height;
// Width of the line.
const double* width;
// The left edge of the line. The right edge can be obtained with `left +
// width`
const double* left;
// The y position of the baseline for this line from the top of the paragraph.
const double* baseline;
// Zero indexed line number.
const size_t* line_number;

LineMetrics();

LineMetrics(const bool* hard_break,
const double* ascent,
const double* descent,
const double* unscaled_ascent,
const double* height,
const double* width,
const double* left,
const double* baseline,
const size_t* line_number)
: hard_break(hard_break),
ascent(ascent),
descent(descent),
unscaled_ascent(unscaled_ascent),
height(height),
width(width),
left(left),
baseline(baseline),
line_number(line_number) {}
};

} // 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_
14 changes: 13 additions & 1 deletion lib/ui/text/paragraph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Paragraph);
V(Paragraph, getWordBoundary) \
V(Paragraph, getRectsForRange) \
V(Paragraph, getRectsForPlaceholders) \
V(Paragraph, getPositionForOffset)
V(Paragraph, getPositionForOffset) \
V(Paragraph, computeLineMetrics)

DART_BIND_ALL(Paragraph, FOR_EACH_BINDING)

Expand Down Expand Up @@ -133,4 +134,15 @@ Dart_Handle Paragraph::getWordBoundary(unsigned offset) {
return result;
}

std::vector<LineMetrics> Paragraph::computeLineMetrics() {
std::vector<LineMetrics> result;
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);
}
return result;
}

} // namespace flutter
2 changes: 2 additions & 0 deletions lib/ui/text/paragraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "flutter/fml/message_loop.h"
#include "flutter/lib/ui/dart_wrapper.h"
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/text/line_metrics.h"
#include "flutter/lib/ui/text/text_box.h"
#include "flutter/third_party/txt/src/txt/paragraph.h"

Expand Down Expand Up @@ -48,6 +49,7 @@ class Paragraph : public RefCountedDartWrappable<Paragraph> {
std::vector<TextBox> getRectsForPlaceholders();
Dart_Handle getPositionForOffset(double dx, double dy);
Dart_Handle getWordBoundary(unsigned offset);
std::vector<LineMetrics> computeLineMetrics();

size_t GetAllocationSize() override;

Expand Down
6 changes: 6 additions & 0 deletions lib/web_ui/lib/src/engine/text/paragraph.dart
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ class EngineParagraph implements ui.Paragraph {
final int end = WordBreaker.nextBreakIndex(_plainText, offset);
return <int>[start, end];
}

@override
List<ui.LineMetrics> computeLineMetrics() {
// TODO(flutter_web): Implement this.
return null;
}
}

/// The web implementation of [ui.ParagraphStyle].
Expand Down
47 changes: 47 additions & 0 deletions lib/web_ui/lib/src/ui/text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,51 @@ enum BoxWidthStyle {
max,
}

class LineMetrics {
LineMetrics({
this.hardBreak,
this.ascent,
this.descent,
this.unscaledAscent,
this.height,
this.width,
this.left,
this.baseline,
this.lineNumber,
});

@pragma('vm:entry-point')
LineMetrics._(
this.hardBreak,
this.ascent,
this.descent,
this.unscaledAscent,
this.height,
this.width,
this.left,
this.baseline,
this.lineNumber,
);

final bool hardBreak;

final double ascent;

final double descent;

final double unscaledAscent;

final double height;

final double width;

final double left;

final double baseline;

final int lineNumber;
}

/// A paragraph of text.
///
/// A paragraph retains the size and position of each glyph in the text and can
Expand Down Expand Up @@ -1125,6 +1170,8 @@ abstract class Paragraph {
/// Coordinates of the [TextBox] are relative to the upper-left corner of the paragraph,
/// where positive y values indicate down.
List<TextBox> getBoxesForPlaceholders();

List<LineMetrics> computeLineMetrics();
}

/// Builds a [Paragraph] containing text with the given styling information.
Expand Down
2 changes: 1 addition & 1 deletion third_party/txt/src/txt/paragraph_txt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,7 @@ void ParagraphTxt::Layout(double width) {
size_t run_key = run.end() - 1;
line_metrics.run_metrics.emplace(run_key, &run.style());
SkFontMetrics* metrics =
&line_metrics.run_metrics.at(run_key).GetFontMetrics();
&line_metrics.run_metrics.at(run_key).font_metrics;
font.getMetrics(metrics);

Range<double> record_x_pos(
Expand Down
Loading

0 comments on commit 9f1eab2

Please sign in to comment.