[web] Don't get break type from v8BreakIterator (flutter/engine#43053)

In some languages, when the text contains a new line "\n", the `v8BreakIterator` starts returning different values from `breakType()`. This caused our code to think that those line breaks were hard line breaks when in fact they were soft line breaks. Still unclear if this is a `v8BreakIterator` bug or a wrong expectation on our side regarding how `breakType()` is supposed to work.

Instead of using `v8BreakIterator.breakType()`, let's do the `soft` vs `hard` detection ourselves (we already have all the necessary pieces).

Fixes https://github.com/flutter/flutter/issues/127379
This commit is contained in:
Mouad Debbar
2023-06-22 13:35:44 -04:00
committed by GitHub
parent 6998943fab
commit 907fcd3245
2 changed files with 49 additions and 16 deletions

View File

@@ -84,8 +84,6 @@ List<LineBreakFragment> breakLinesUsingV8BreakIterator(String text, JSString jsT
iterator.adoptText(jsText);
iterator.first();
while (iterator.next() != -1) {
final LineBreakType type = _getV8BreakType(text, iterator);
final int fragmentEnd = iterator.current().toInt();
int trailingNewlines = 0;
int trailingSpaces = 0;
@@ -115,6 +113,15 @@ List<LineBreakFragment> breakLinesUsingV8BreakIterator(String text, JSString jsT
}
}
final LineBreakType type;
if (trailingNewlines > 0) {
type = LineBreakType.mandatory;
} else if (fragmentEnd == text.length) {
type = LineBreakType.endOfText;
} else {
type = LineBreakType.opportunity;
}
breaks.add(LineBreakFragment(
fragmentStart,
fragmentEnd,
@@ -132,20 +139,6 @@ List<LineBreakFragment> breakLinesUsingV8BreakIterator(String text, JSString jsT
return breaks;
}
/// Gets break type from v8BreakIterator.
LineBreakType _getV8BreakType(String text, DomV8BreakIterator iterator) {
final int fragmentEnd = iterator.current().toInt();
// I don't know why v8BreakIterator uses the type "none" to mean "soft break".
if (iterator.breakType() != 'none') {
return LineBreakType.mandatory;
}
if (fragmentEnd == text.length) {
return LineBreakType.endOfText;
}
return LineBreakType.opportunity;
}
class LineBreakFragment extends TextFragment {
const LineBreakFragment(super.start, super.end, this.type, {
required this.trailingNewlines,

View File

@@ -410,6 +410,46 @@ void testMain() {
}
});
});
group('v8BreakIterator hard line breaks', () {
List<Line> split(String text) {
return V8LineBreakFragmenter(text)
.fragment()
.map((LineBreakFragment fragment) => Line.fromLineBreakFragment(text, fragment))
.toList();
}
test('thai text with hard line breaks', () {
const String thaiText = '\u0E1A\u0E38\u0E1C\u0E25\u0E01\u0E32\u0E23';
expect(split(thaiText), <Line>[
Line('\u0E1A\u0E38', opportunity),
Line('\u0E1C\u0E25', opportunity),
Line('\u0E01\u0E32\u0E23', endOfText),
]);
expect(split('$thaiText\n'), <Line>[
Line('\u0E1A\u0E38', opportunity),
Line('\u0E1C\u0E25', opportunity),
Line('\u0E01\u0E32\u0E23\n', mandatory, nl: 1, sp: 1),
Line('', endOfText),
]);
});
test('khmer text with hard line breaks', () {
const String khmerText =
'\u179B\u1792\u17D2\u179C\u17BE\u17B2\u17D2\u1799';
expect(split(khmerText), <Line>[
Line('\u179B', opportunity),
Line('\u1792\u17D2\u179C\u17BE', opportunity),
Line('\u17B2\u17D2\u1799', endOfText),
]);
expect(split('$khmerText\n'), <Line>[
Line('\u179B', opportunity),
Line('\u1792\u17D2\u179C\u17BE', opportunity),
Line('\u17B2\u17D2\u1799\n', mandatory, nl: 1, sp: 1),
Line('', endOfText),
]);
});
}, skip: domIntl.v8BreakIterator == null);
}
typedef CreateLineBreakFragmenter = LineBreakFragmenter Function(String text);