Unverified Commit 90b8a549 authored by Harry Terkelsen's avatar Harry Terkelsen Committed by GitHub

Only stop search for upstream character if we hit a newline (#86960)

parent 184e5871
...@@ -690,6 +690,9 @@ class TextPainter { ...@@ -690,6 +690,9 @@ class TextPainter {
if (prevCodeUnit == null) if (prevCodeUnit == null)
return null; return null;
// If the upstream character is a newline, cursor is at start of next line
const int NEWLINE_CODE_UNIT = 10;
// Check for multi-code-unit glyphs such as emojis or zero width joiner. // Check for multi-code-unit glyphs such as emojis or zero width joiner.
final bool needsSearch = _isUtf16Surrogate(prevCodeUnit) || _text!.codeUnitAt(offset) == _zwjUtf16 || _isUnicodeDirectionality(prevCodeUnit); final bool needsSearch = _isUtf16Surrogate(prevCodeUnit) || _text!.codeUnitAt(offset) == _zwjUtf16 || _isUnicodeDirectionality(prevCodeUnit);
int graphemeClusterLength = needsSearch ? 2 : 1; int graphemeClusterLength = needsSearch ? 2 : 1;
...@@ -703,7 +706,7 @@ class TextPainter { ...@@ -703,7 +706,7 @@ class TextPainter {
if (boxes.isEmpty) { if (boxes.isEmpty) {
// When we are at the beginning of the line, a non-surrogate position will // When we are at the beginning of the line, a non-surrogate position will
// return empty boxes. We break and try from downstream instead. // return empty boxes. We break and try from downstream instead.
if (!needsSearch) { if (!needsSearch && prevCodeUnit == NEWLINE_CODE_UNIT) {
break; // Only perform one iteration if no search is required. break; // Only perform one iteration if no search is required.
} }
if (prevRuneOffset < -flattenedText.length) { if (prevRuneOffset < -flattenedText.length) {
...@@ -718,8 +721,6 @@ class TextPainter { ...@@ -718,8 +721,6 @@ class TextPainter {
} }
final TextBox box = boxes.first; final TextBox box = boxes.first;
// If the upstream character is a newline, cursor is at start of next line
const int NEWLINE_CODE_UNIT = 10;
if (prevCodeUnit == NEWLINE_CODE_UNIT) { if (prevCodeUnit == NEWLINE_CODE_UNIT) {
return Rect.fromLTRB(_emptyOffset.dx, box.bottom, _emptyOffset.dx, box.bottom + box.bottom - box.top); return Rect.fromLTRB(_emptyOffset.dx, box.bottom, _emptyOffset.dx, box.bottom + box.bottom - box.top);
} }
......
...@@ -8,6 +8,9 @@ import 'package:flutter/foundation.dart'; ...@@ -8,6 +8,9 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
const bool isCanvasKit =
bool.fromEnvironment('FLUTTER_WEB_USE_SKIA', defaultValue: false);
void main() { void main() {
test('TextPainter caret test', () { test('TextPainter caret test', () {
final TextPainter painter = TextPainter() final TextPainter painter = TextPainter()
...@@ -123,7 +126,7 @@ void main() { ...@@ -123,7 +126,7 @@ void main() {
expect(caretOffset.dx, 98); // <medium skin tone modifier> expect(caretOffset.dx, 98); // <medium skin tone modifier>
caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 23), ui.Rect.zero); caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 23), ui.Rect.zero);
expect(caretOffset.dx, 126); // end of string expect(caretOffset.dx, 126); // end of string
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/56308 }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308
test('TextPainter caret center space test', () { test('TextPainter caret center space test', () {
final TextPainter painter = TextPainter() final TextPainter painter = TextPainter()
...@@ -145,7 +148,7 @@ void main() { ...@@ -145,7 +148,7 @@ void main() {
expect(caretOffset.dx, 35); expect(caretOffset.dx, 35);
caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 2), ui.Rect.zero); caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 2), ui.Rect.zero);
expect(caretOffset.dx, 49); expect(caretOffset.dx, 49);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/56308 }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308
test('TextPainter error test', () { test('TextPainter error test', () {
final TextPainter painter = TextPainter(textDirection: TextDirection.ltr); final TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
...@@ -743,7 +746,7 @@ void main() { ...@@ -743,7 +746,7 @@ void main() {
expect(painter.inlinePlaceholderBoxes![11], const TextBox.fromLTRBD(250, 30, 300, 60, TextDirection.ltr)); expect(painter.inlinePlaceholderBoxes![11], const TextBox.fromLTRBD(250, 30, 300, 60, TextDirection.ltr));
expect(painter.inlinePlaceholderBoxes![12], const TextBox.fromLTRBD(300, 30, 351, 60, TextDirection.ltr)); expect(painter.inlinePlaceholderBoxes![12], const TextBox.fromLTRBD(300, 30, 351, 60, TextDirection.ltr));
expect(painter.inlinePlaceholderBoxes![13], const TextBox.fromLTRBD(351, 30, 401, 60, TextDirection.ltr)); expect(painter.inlinePlaceholderBoxes![13], const TextBox.fromLTRBD(351, 30, 401, 60, TextDirection.ltr));
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/42086 }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/42086
// Null values are valid. See https://github.com/flutter/flutter/pull/48346#issuecomment-584839221 // Null values are valid. See https://github.com/flutter/flutter/pull/48346#issuecomment-584839221
test('TextPainter set TextHeightBehavior null test', () { test('TextPainter set TextHeightBehavior null test', () {
...@@ -832,7 +835,7 @@ void main() { ...@@ -832,7 +835,7 @@ void main() {
ui.Rect.zero, ui.Rect.zero,
)!; )!;
expect(caretHeight, 50.0); expect(caretHeight, 50.0);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/56308 }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308
group('TextPainter line-height', () { group('TextPainter line-height', () {
test('half-leading', () { test('half-leading', () {
...@@ -952,7 +955,7 @@ void main() { ...@@ -952,7 +955,7 @@ void main() {
).first.toRect(); ).first.toRect();
expect(glyphBox, newGlyphBox); expect(glyphBox, newGlyphBox);
}); });
}, skip: isBrowser); }, skip: isBrowser && !isCanvasKit);
test('TextPainter handles invalid UTF-16', () { test('TextPainter handles invalid UTF-16', () {
Object? exception; Object? exception;
...@@ -971,6 +974,22 @@ void main() { ...@@ -971,6 +974,22 @@ void main() {
expect(painter.width, equals(fontSize)); expect(painter.width, equals(fontSize));
expect(exception, isNotNull); expect(exception, isNotNull);
}, skip: kIsWeb); }, skip: kIsWeb);
test('Diacritic', () {
final TextPainter painter = TextPainter()
..textDirection = TextDirection.ltr;
// Two letters followed by a diacritic
const String text = 'ฟห้';
painter.text = const TextSpan(text: text);
painter.layout();
final ui.Offset caretOffset = painter.getOffsetForCaret(
const ui.TextPosition(
offset: text.length, affinity: TextAffinity.upstream),
ui.Rect.zero);
expect(caretOffset.dx, painter.width);
}, skip: kIsWeb && !isCanvasKit);
} }
class MockCanvas extends Fake implements Canvas { class MockCanvas extends Fake implements Canvas {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment