mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add line boundary information to LineMetrics. (#13727)
This exposes the line boundary information a line by adding getLineBoundary to return the indices corresponding to a line around a TextPosition. The information is already calculated when calculating line metrics, so that we can enable moving the selection/cursor to the beginning/end of a line in a text field.
This commit is contained in:
parent
ce0e9e79e6
commit
f68de3f451
@ -1866,23 +1866,32 @@ class Paragraph extends NativeFieldWrapperClass2 {
|
||||
}
|
||||
List<int> _getPositionForOffset(double dx, double dy) native 'Paragraph_getPositionForOffset';
|
||||
|
||||
/// Returns the [start, end] of the word at the given offset. Characters not
|
||||
/// part of a word, such as spaces, symbols, and punctuation, have word breaks
|
||||
/// on both sides. In such cases, this method will return [offset, offset+1].
|
||||
/// Word boundaries are defined more precisely in Unicode Standard Annex #29
|
||||
/// http://www.unicode.org/reports/tr29/#Word_Boundaries
|
||||
List<int> getWordBoundary(dynamic position) {
|
||||
// TODO(gspencergoog): have this take only a TextPosition once the framework
|
||||
// code is calling it with that.
|
||||
if (position is TextPosition) {
|
||||
return _getWordBoundary(position.offset);
|
||||
} else {
|
||||
final int offset = position;
|
||||
return _getWordBoundary(offset);
|
||||
}
|
||||
/// Returns the [TextRange] of the word at the given [TextPosition].
|
||||
///
|
||||
/// Characters not part of a word, such as spaces, symbols, and punctuation,
|
||||
/// have word breaks on both sides. In such cases, this method will return
|
||||
/// [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]);
|
||||
}
|
||||
List<int> _getWordBoundary(int offset) native 'Paragraph_getWordBoundary';
|
||||
|
||||
/// Returns the [TextRange] of the line at the given [TextPosition].
|
||||
///
|
||||
/// The newline (if any) is returned as part of the range.
|
||||
///
|
||||
/// Not valid until after layout.
|
||||
///
|
||||
/// 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]);
|
||||
}
|
||||
List<int> _getLineBoundary(int offset) native 'Paragraph_getLineBoundary';
|
||||
|
||||
// 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.
|
||||
|
||||
@ -31,6 +31,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Paragraph);
|
||||
V(Paragraph, layout) \
|
||||
V(Paragraph, paint) \
|
||||
V(Paragraph, getWordBoundary) \
|
||||
V(Paragraph, getLineBoundary) \
|
||||
V(Paragraph, getRectsForRange) \
|
||||
V(Paragraph, getRectsForPlaceholders) \
|
||||
V(Paragraph, getPositionForOffset) \
|
||||
@ -134,6 +135,23 @@ Dart_Handle Paragraph::getWordBoundary(unsigned offset) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Dart_Handle Paragraph::getLineBoundary(unsigned offset) {
|
||||
std::vector<txt::LineMetrics> metrics = m_paragraph->GetLineMetrics();
|
||||
int line_start = -1;
|
||||
int line_end = -1;
|
||||
for (txt::LineMetrics& line : metrics) {
|
||||
if (offset >= line.start_index && offset < line.end_index) {
|
||||
line_start = line.start_index;
|
||||
line_end = line.end_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Dart_Handle result = Dart_NewListOf(Dart_CoreType_Int, 2);
|
||||
Dart_ListSetAt(result, 0, ToDart(line_start));
|
||||
Dart_ListSetAt(result, 1, ToDart(line_end));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<LineMetrics> Paragraph::computeLineMetrics() {
|
||||
std::vector<LineMetrics> result;
|
||||
std::vector<txt::LineMetrics> metrics = m_paragraph->GetLineMetrics();
|
||||
|
||||
@ -49,6 +49,7 @@ class Paragraph : public RefCountedDartWrappable<Paragraph> {
|
||||
std::vector<TextBox> getRectsForPlaceholders();
|
||||
Dart_Handle getPositionForOffset(double dx, double dy);
|
||||
Dart_Handle getWordBoundary(unsigned offset);
|
||||
Dart_Handle getLineBoundary(unsigned offset);
|
||||
std::vector<LineMetrics> computeLineMetrics();
|
||||
|
||||
size_t GetAllocationSize() override;
|
||||
|
||||
@ -281,27 +281,22 @@ class EngineParagraph implements ui.Paragraph {
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> getWordBoundary(dynamic position) {
|
||||
// TODO(gspencergoog): have this take only a TextPosition once the framework
|
||||
// code is calling it with that.
|
||||
if (position is ui.TextPosition) {
|
||||
ui.TextPosition textPosition = position;
|
||||
if (_plainText == null) {
|
||||
return <int>[textPosition.offset, textPosition.offset];
|
||||
}
|
||||
|
||||
final int start = WordBreaker.prevBreakIndex(_plainText, textPosition.offset);
|
||||
final int end = WordBreaker.nextBreakIndex(_plainText, textPosition.offset);
|
||||
return <int>[start, end];
|
||||
}
|
||||
|
||||
ui.TextRange getWordBoundary(ui.TextPosition position) {
|
||||
ui.TextPosition textPosition = position;
|
||||
if (_plainText == null) {
|
||||
return <int>[position, position];
|
||||
return ui.TextRange(start: textPosition.offset, end: textPosition.offset);
|
||||
}
|
||||
|
||||
final int start = WordBreaker.prevBreakIndex(_plainText, position);
|
||||
final int end = WordBreaker.nextBreakIndex(_plainText, position);
|
||||
return <int>[start, end];
|
||||
final int start = WordBreaker.prevBreakIndex(_plainText, textPosition.offset);
|
||||
final int end = WordBreaker.nextBreakIndex(_plainText, textPosition.offset);
|
||||
return ui.TextRange(start: start, end: end);
|
||||
}
|
||||
|
||||
@override
|
||||
ui.TextRange getLineBoundary(ui.TextPosition position) {
|
||||
// TODO(flutter_web): https://github.com/flutter/flutter/issues/39537
|
||||
// Depends upon LineMetrics measurement.
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -1237,12 +1237,23 @@ abstract class Paragraph {
|
||||
/// within the text.
|
||||
TextPosition getPositionForOffset(Offset offset);
|
||||
|
||||
/// Returns the [start, end] of the word at the given offset. Characters not
|
||||
/// part of a word, such as spaces, symbols, and punctuation, have word breaks
|
||||
/// on both sides. In such cases, this method will return [offset, offset+1].
|
||||
/// Word boundaries are defined more precisely in Unicode Standard Annex #29
|
||||
/// http://www.unicode.org/reports/tr29/#Word_Boundaries
|
||||
List<int> getWordBoundary(dynamic position);
|
||||
/// Returns the [TextRange] of the word at the given [TextPosition].
|
||||
///
|
||||
/// Characters not part of a word, such as spaces, symbols, and punctuation,
|
||||
/// have word breaks on both sides. In such cases, this method will return
|
||||
/// [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);
|
||||
|
||||
/// Returns the [TextRange] of the line at the given [TextPosition].
|
||||
///
|
||||
/// The newline (if any) is returned as part of the range.
|
||||
///
|
||||
/// Not valid until after layout.
|
||||
///
|
||||
/// This can potentially be expensive, since it needs to compute the line
|
||||
/// metrics, so use it sparingly.
|
||||
TextRange getLineBoundary(TextPosition position);
|
||||
|
||||
/// Returns a list of text boxes that enclose all placeholders in the paragraph.
|
||||
///
|
||||
@ -1252,6 +1263,13 @@ abstract class Paragraph {
|
||||
/// where positive y values indicate down.
|
||||
List<TextBox> getBoxesForPlaceholders();
|
||||
|
||||
/// 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();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user