Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
50cd7377
Unverified
Commit
50cd7377
authored
Sep 26, 2022
by
chunhtai
Committed by
GitHub
Sep 26, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Expose text boundary combiner class (#112085)
parent
2adee31c
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
249 additions
and
154 deletions
+249
-154
text_painter.dart
packages/flutter/lib/src/painting/text_painter.dart
+0
-6
text_boundary.dart
packages/flutter/lib/src/services/text_boundary.dart
+172
-3
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+11
-145
text_boundary_test.dart
packages/flutter/test/services/text_boundary_test.dart
+66
-0
No files found.
packages/flutter/lib/src/painting/text_painter.dart
View file @
50cd7377
...
...
@@ -1129,12 +1129,6 @@ class TextPainter {
/// {@endtemplate}
TextRange
getWordBoundary
(
TextPosition
position
)
{
assert
(
_debugAssertTextLayoutIsValid
);
// TODO(chunhtai): remove this workaround once ui.Paragraph.getWordBoundary
// can handle caret position.
// https://github.com/flutter/flutter/issues/111751.
if
(
position
.
affinity
==
TextAffinity
.
upstream
)
{
position
=
TextPosition
(
offset:
position
.
offset
-
1
);
}
return
_paragraph
!.
getWordBoundary
(
position
);
}
...
...
packages/flutter/lib/src/services/text_boundary.dart
View file @
50cd7377
...
...
@@ -38,6 +38,18 @@ abstract class TextBoundary {
end:
getTrailingTextBoundaryAt
(
position
).
offset
,
);
}
/// Gets the boundary by calling the left-hand side and pipe the result to
/// right-hand side.
///
/// Combining two text boundaries can be useful if one wants to ignore certain
/// text before finding the text boundary. For example, use
/// [WhitespaceBoundary] + [WordBoundary] to ignores any white space before
/// finding word boundary if the input position happens to be a whitespace
/// character.
TextBoundary
operator
+(
TextBoundary
other
)
{
return
_ExpandedTextBoundary
(
inner:
other
,
outer:
this
);
}
}
/// A text boundary that uses characters as logical boundaries.
...
...
@@ -110,7 +122,7 @@ class CharacterBoundary extends TextBoundary {
/// This class uses [UAX #29](https://unicode.org/reports/tr29/) defined word
/// boundaries to calculate its logical boundaries.
class
WordBoundary
extends
TextBoundary
{
/// Creates a [
Character
Boundary] with the text and layout information.
/// Creates a [
Word
Boundary] with the text and layout information.
const
WordBoundary
(
this
.
_textLayout
);
final
TextLayoutMetrics
_textLayout
;
...
...
@@ -122,6 +134,7 @@ class WordBoundary extends TextBoundary {
affinity:
TextAffinity
.
downstream
,
// ignore: avoid_redundant_argument_values
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
return
TextPosition
(
...
...
@@ -129,6 +142,11 @@ class WordBoundary extends TextBoundary {
affinity:
TextAffinity
.
upstream
,
);
}
@override
TextRange
getTextBoundaryAt
(
TextPosition
position
)
{
return
_textLayout
.
getWordBoundary
(
position
);
}
}
/// A text boundary that uses line breaks as logical boundaries.
...
...
@@ -136,7 +154,7 @@ class WordBoundary extends TextBoundary {
/// The input [TextPosition]s will be interpreted as caret locations if
/// [TextLayoutMetrics.getLineAtOffset] is text-affinity-aware.
class
LineBreak
extends
TextBoundary
{
/// Creates a [
CharacterBoundary
] with the text and layout information.
/// Creates a [
LineBreak
] with the text and layout information.
const
LineBreak
(
this
.
_textLayout
);
final
TextLayoutMetrics
_textLayout
;
...
...
@@ -155,6 +173,11 @@ class LineBreak extends TextBoundary {
affinity:
TextAffinity
.
upstream
,
);
}
@override
TextRange
getTextBoundaryAt
(
TextPosition
position
)
{
return
_textLayout
.
getLineAtOffset
(
position
);
}
}
/// A text boundary that uses the entire document as logical boundary.
...
...
@@ -162,7 +185,7 @@ class LineBreak extends TextBoundary {
/// The document boundary is unique and is a constant function of the input
/// position.
class
DocumentBoundary
extends
TextBoundary
{
/// Creates a [
Character
Boundary] with the text
/// Creates a [
Document
Boundary] with the text
const
DocumentBoundary
(
this
.
_text
);
final
String
_text
;
...
...
@@ -177,3 +200,149 @@ class DocumentBoundary extends TextBoundary {
);
}
}
/// A text boundary that uses the first non-whitespace character as the logical
/// boundary.
///
/// This text boundary uses [TextLayoutMetrics.isWhitespace] to identify white
/// spaces, this includes newline characters from ASCII and separators from the
/// [unicode separator category](https://en.wikipedia.org/wiki/Whitespace_character).
class
WhitespaceBoundary
extends
TextBoundary
{
/// Creates a [WhitespaceBoundary] with the text.
const
WhitespaceBoundary
(
this
.
_text
);
final
String
_text
;
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
{
// Handles outside of string end.
if
(
position
.
offset
>
_text
.
length
||
(
position
.
offset
==
_text
.
length
&&
position
.
affinity
==
TextAffinity
.
downstream
))
{
position
=
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
);
}
// Handles outside of string start.
if
(
position
.
offset
<=
0
)
{
return
const
TextPosition
(
offset:
0
);
}
int
index
=
position
.
offset
;
if
(
position
.
affinity
==
TextAffinity
.
downstream
&&
!
TextLayoutMetrics
.
isWhitespace
(
_text
.
codeUnitAt
(
index
)))
{
return
position
;
}
while
((
index
-=
1
)
>=
0
)
{
if
(!
TextLayoutMetrics
.
isWhitespace
(
_text
.
codeUnitAt
(
index
)))
{
return
TextPosition
(
offset:
index
+
1
,
affinity:
TextAffinity
.
upstream
);
}
}
return
const
TextPosition
(
offset:
0
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
// Handles outside of right bound.
if
(
position
.
offset
>=
_text
.
length
)
{
return
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
);
}
// Handles outside of left bound.
if
(
position
.
offset
<
0
||
(
position
.
offset
==
0
&&
position
.
affinity
==
TextAffinity
.
upstream
))
{
position
=
const
TextPosition
(
offset:
0
);
}
int
index
=
position
.
offset
;
if
(
position
.
affinity
==
TextAffinity
.
upstream
&&
!
TextLayoutMetrics
.
isWhitespace
(
_text
.
codeUnitAt
(
index
-
1
)))
{
return
position
;
}
for
(;
index
<
_text
.
length
;
index
+=
1
)
{
if
(!
TextLayoutMetrics
.
isWhitespace
(
_text
.
codeUnitAt
(
index
)))
{
return
TextPosition
(
offset:
index
);
}
}
return
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
);
}
}
/// Gets the boundary by calling the [outer] and pipe the result to
/// [inner].
class
_ExpandedTextBoundary
extends
TextBoundary
{
/// Creates a [_ExpandedTextBoundary] with inner and outter boundaries
const
_ExpandedTextBoundary
({
required
this
.
inner
,
required
this
.
outer
});
/// The inner boundary to call with the result from [outer].
final
TextBoundary
inner
;
/// The outer boundary to call with the input position.
///
/// The result is piped to the [inner] before returning to the caller.
final
TextBoundary
outer
;
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
{
return
inner
.
getLeadingTextBoundaryAt
(
outer
.
getLeadingTextBoundaryAt
(
position
),
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
return
inner
.
getTrailingTextBoundaryAt
(
outer
.
getTrailingTextBoundaryAt
(
position
),
);
}
}
/// A text boundary that will push input text position forward or backward
/// one affinity
///
/// To push a text position forward one affinity unit, this proxy converts
/// affinity to downstream if it is upstream; otherwise it increase the offset
/// by one with its affinity sets to upstream. For example,
/// `TextPosition(1, upstream)` becomes `TextPosition(1, downstream)`,
/// `TextPosition(4, downstream)` becomes `TextPosition(5, upstream)`.
///
/// See also:
/// * [PushTextPosition.forward], a text boundary to push the input position
/// forward.
/// * [PushTextPosition.backward], a text boundary to push the input position
/// backward.
class
PushTextPosition
extends
TextBoundary
{
const
PushTextPosition
.
_
(
this
.
_forward
);
/// A text boundary that pushes the input position forward.
static
const
TextBoundary
forward
=
PushTextPosition
.
_
(
true
);
/// A text boundary that pushes the input position backward.
static
const
TextBoundary
backward
=
PushTextPosition
.
_
(
false
);
/// Whether to push the input position forward or backward.
final
bool
_forward
;
TextPosition
_calculateTargetPosition
(
TextPosition
position
)
{
if
(
_forward
)
{
switch
(
position
.
affinity
)
{
case
TextAffinity
.
upstream
:
return
TextPosition
(
offset:
position
.
offset
);
case
TextAffinity
.
downstream
:
return
position
=
TextPosition
(
offset:
position
.
offset
+
1
,
affinity:
TextAffinity
.
upstream
,
);
}
}
else
{
switch
(
position
.
affinity
)
{
case
TextAffinity
.
upstream
:
return
position
=
TextPosition
(
offset:
position
.
offset
-
1
);
case
TextAffinity
.
downstream
:
return
TextPosition
(
offset:
position
.
offset
,
affinity:
TextAffinity
.
upstream
,
);
}
}
}
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
=>
_calculateTargetPosition
(
position
);
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
=>
_calculateTargetPosition
(
position
);
}
packages/flutter/lib/src/widgets/editable_text.dart
View file @
50cd7377
...
...
@@ -3481,7 +3481,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
TextBoundary
_characterBoundary
(
DirectionalTextEditingIntent
intent
)
{
final
TextBoundary
atomicTextBoundary
=
widget
.
obscureText
?
_CodeUnitBoundary
(
_value
.
text
)
:
CharacterBoundary
(
_value
.
text
);
return
_PushTextPosition
(
atomicTextBoundary
,
intent
.
forward
)
;
return
intent
.
forward
?
PushTextPosition
.
forward
+
atomicTextBoundary
:
PushTextPosition
.
backward
+
atomicTextBoundary
;
}
TextBoundary
_nextWordBoundary
(
DirectionalTextEditingIntent
intent
)
{
...
...
@@ -3495,7 +3495,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
final
TextEditingValue
textEditingValue
=
_textEditingValueforTextLayoutMetrics
;
atomicTextBoundary
=
CharacterBoundary
(
textEditingValue
.
text
);
// This isn't enough. Newline characters.
boundary
=
_ExpandedTextBoundary
(
_WhitespaceBoundary
(
textEditingValue
.
text
),
WordBoundary
(
renderEditable
)
);
boundary
=
WhitespaceBoundary
(
textEditingValue
.
text
)
+
WordBoundary
(
renderEditable
);
}
final
_MixedBoundary
mixedBoundary
=
intent
.
forward
...
...
@@ -3503,7 +3503,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
:
_MixedBoundary
(
boundary
,
atomicTextBoundary
);
// Use a _MixedBoundary to make sure we don't leave invalid codepoints in
// the field after deletion.
return
_PushTextPosition
(
mixedBoundary
,
intent
.
forward
)
;
return
intent
.
forward
?
PushTextPosition
.
forward
+
mixedBoundary
:
PushTextPosition
.
backward
+
mixedBoundary
;
}
TextBoundary
_linebreak
(
DirectionalTextEditingIntent
intent
)
{
...
...
@@ -3524,9 +3524,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
// `boundary` doesn't need to be wrapped in a _CollapsedSelectionBoundary,
// since the document boundary is unique and the linebreak boundary is
// already caret-location based.
return
intent
.
forward
?
_MixedBoundary
(
_PushTextPosition
(
atomicTextBoundary
,
true
),
boundary
)
:
_MixedBoundary
(
boundary
,
_PushTextPosition
(
atomicTextBoundary
,
false
));
final
TextBoundary
pushed
=
intent
.
forward
?
PushTextPosition
.
forward
+
atomicTextBoundary
:
PushTextPosition
.
backward
+
atomicTextBoundary
;
return
intent
.
forward
?
_MixedBoundary
(
pushed
,
boundary
)
:
_MixedBoundary
(
boundary
,
pushed
);
}
TextBoundary
_documentBoundary
(
DirectionalTextEditingIntent
intent
)
=>
DocumentBoundary
(
_value
.
text
);
...
...
@@ -4270,149 +4271,14 @@ class _CodeUnitBoundary extends TextBoundary {
// ------------------------ Text Boundary Combinators ------------------------
/// A text boundary that use the first non-whitespace character as the logical
/// boundary.
///
/// This text boundary uses [TextLayoutMetrics.isWhitespace] to identify white
/// spaces, this include newline characters from ASCII and separators from the
/// [unicode separator category](https://www.compart.com/en/unicode/category/Zs).
class
_WhitespaceBoundary
extends
TextBoundary
{
/// Creates a [_WhitespaceBoundary] with the text.
const
_WhitespaceBoundary
(
this
.
_text
);
final
String
_text
;
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
{
// Handles outside of right bound.
if
(
position
.
offset
>
_text
.
length
||
(
position
.
offset
==
_text
.
length
&&
position
.
affinity
==
TextAffinity
.
downstream
))
{
position
=
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
);
}
// Handles outside of left bound.
if
(
position
.
offset
<=
0
)
{
return
const
TextPosition
(
offset:
0
);
}
int
index
=
position
.
offset
;
if
(!
TextLayoutMetrics
.
isWhitespace
(
_text
.
codeUnitAt
(
index
))
&&
position
.
affinity
==
TextAffinity
.
downstream
)
{
return
position
;
}
for
(
index
-=
1
;
index
>=
0
;
index
-=
1
)
{
if
(!
TextLayoutMetrics
.
isWhitespace
(
_text
.
codeUnitAt
(
index
)))
{
return
TextPosition
(
offset:
index
+
1
,
affinity:
TextAffinity
.
upstream
);
}
}
return
const
TextPosition
(
offset:
0
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
// Handles outside of right bound.
if
(
position
.
offset
>=
_text
.
length
)
{
return
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
);
}
// Handles outside of left bound.
if
(
position
.
offset
<
0
||
(
position
.
offset
==
0
&&
position
.
affinity
==
TextAffinity
.
upstream
))
{
position
=
const
TextPosition
(
offset:
0
);
}
int
index
=
position
.
offset
;
if
(!
TextLayoutMetrics
.
isWhitespace
(
_text
.
codeUnitAt
(
index
))
&&
position
.
affinity
==
TextAffinity
.
downstream
)
{
return
position
;
}
for
(
index
+=
1
;
index
<
_text
.
length
;
index
+=
1
)
{
if
(!
TextLayoutMetrics
.
isWhitespace
(
_text
.
codeUnitAt
(
index
)))
{
return
TextPosition
(
offset:
index
);
}
}
return
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
);
}
}
// Expands the innerTextBoundary with outerTextBoundary.
class
_ExpandedTextBoundary
extends
TextBoundary
{
_ExpandedTextBoundary
(
this
.
innerTextBoundary
,
this
.
outerTextBoundary
);
final
TextBoundary
innerTextBoundary
;
final
TextBoundary
outerTextBoundary
;
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
{
return
outerTextBoundary
.
getLeadingTextBoundaryAt
(
innerTextBoundary
.
getLeadingTextBoundaryAt
(
position
),
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
return
outerTextBoundary
.
getTrailingTextBoundaryAt
(
innerTextBoundary
.
getTrailingTextBoundaryAt
(
position
),
);
}
}
/// A proxy text boundary that will push input text position forward or backward
/// one affinity unit before sending it to the [innerTextBoundary].
///
/// If the [isForward] is true, this proxy text boundary push the position
/// forward; otherwise, backward.
///
/// To push a text position forward one affinity unit, this proxy converts
/// affinity to downstream if it is upstream; otherwise it increase the offset
/// by one with its affinity sets to upstream. For example,
/// `TextPosition(1, upstream)` becomes `TextPosition(1, downstream)`,
/// `TextPosition(4, downstream)` becomes `TextPosition(5, upstream)`.
///
/// This class is used to kick-start the text position to find the next boundary
/// determined by [innerTextBoundary] so that it won't be trapped if the input
/// text position is right at the edge.
class
_PushTextPosition
extends
TextBoundary
{
_PushTextPosition
(
this
.
innerTextBoundary
,
this
.
isForward
);
final
TextBoundary
innerTextBoundary
;
final
bool
isForward
;
TextPosition
_calculateTargetPosition
(
TextPosition
position
)
{
if
(
isForward
)
{
switch
(
position
.
affinity
)
{
case
TextAffinity
.
upstream
:
return
TextPosition
(
offset:
position
.
offset
);
case
TextAffinity
.
downstream
:
return
position
=
TextPosition
(
offset:
position
.
offset
+
1
,
affinity:
TextAffinity
.
upstream
,
);
}
}
else
{
switch
(
position
.
affinity
)
{
case
TextAffinity
.
upstream
:
return
position
=
TextPosition
(
offset:
position
.
offset
-
1
);
case
TextAffinity
.
downstream
:
return
TextPosition
(
offset:
position
.
offset
,
affinity:
TextAffinity
.
upstream
,
);
}
}
}
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
{
return
innerTextBoundary
.
getLeadingTextBoundaryAt
(
_calculateTargetPosition
(
position
));
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
return
innerTextBoundary
.
getTrailingTextBoundaryAt
(
_calculateTargetPosition
(
position
));
}
}
// A _TextBoundary that creates a [TextRange] where its start is from the
// specified leading text boundary and its end is from the specified trailing
// text boundary.
class
_MixedBoundary
extends
TextBoundary
{
_MixedBoundary
(
this
.
leadingTextBoundary
,
this
.
trailingTextBoundary
);
_MixedBoundary
(
this
.
leadingTextBoundary
,
this
.
trailingTextBoundary
);
final
TextBoundary
leadingTextBoundary
;
final
TextBoundary
trailingTextBoundary
;
...
...
packages/flutter/test/services/text_boundary_test.dart
View file @
50cd7377
...
...
@@ -63,6 +63,72 @@ void main() {
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
0
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
text
.
length
,
affinity:
TextAffinity
.
upstream
));
});
test
(
'white space boundary works'
,
()
{
const
String
text
=
'abcd efg'
;
const
WhitespaceBoundary
boundary
=
WhitespaceBoundary
(
text
);
TextPosition
position
=
const
TextPosition
(
offset:
1
);
// Should return the same position if the position points to a non white space.
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
position
);
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
position
);
position
=
const
TextPosition
(
offset:
1
,
affinity:
TextAffinity
.
upstream
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
position
);
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
position
);
position
=
const
TextPosition
(
offset:
4
,
affinity:
TextAffinity
.
upstream
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
position
);
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
position
);
// white space
position
=
const
TextPosition
(
offset:
4
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
4
,
affinity:
TextAffinity
.
upstream
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
8
));
// white space
position
=
const
TextPosition
(
offset:
6
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
4
,
affinity:
TextAffinity
.
upstream
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
8
));
position
=
const
TextPosition
(
offset:
8
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
position
);
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
position
);
});
test
(
'extended boundary should work'
,
()
{
const
String
text
=
'abcd efg'
;
const
WhitespaceBoundary
outer
=
WhitespaceBoundary
(
text
);
const
CharacterBoundary
inner
=
CharacterBoundary
(
text
);
final
TextBoundary
expanded
=
outer
+
inner
;
TextPosition
position
=
const
TextPosition
(
offset:
1
);
expect
(
expanded
.
getLeadingTextBoundaryAt
(
position
),
position
);
expect
(
expanded
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
2
,
affinity:
TextAffinity
.
upstream
));
position
=
const
TextPosition
(
offset:
5
);
// should skip white space
expect
(
expanded
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
3
));
expect
(
expanded
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
9
,
affinity:
TextAffinity
.
upstream
));
});
test
(
'push text position works'
,
()
{
const
String
text
=
'abcd efg'
;
const
CharacterBoundary
inner
=
CharacterBoundary
(
text
);
final
TextBoundary
forward
=
PushTextPosition
.
forward
+
inner
;
final
TextBoundary
backward
=
PushTextPosition
.
backward
+
inner
;
TextPosition
position
=
const
TextPosition
(
offset:
1
,
affinity:
TextAffinity
.
upstream
);
const
TextPosition
pushedForward
=
TextPosition
(
offset:
1
);
// the forward should push position one affinity
expect
(
forward
.
getLeadingTextBoundaryAt
(
position
),
inner
.
getLeadingTextBoundaryAt
(
pushedForward
));
expect
(
forward
.
getTrailingTextBoundaryAt
(
position
),
inner
.
getTrailingTextBoundaryAt
(
pushedForward
));
position
=
const
TextPosition
(
offset:
5
);
const
TextPosition
pushedBackward
=
TextPosition
(
offset:
5
,
affinity:
TextAffinity
.
upstream
);
// should skip white space
expect
(
backward
.
getLeadingTextBoundaryAt
(
position
),
inner
.
getLeadingTextBoundaryAt
(
pushedBackward
));
expect
(
backward
.
getTrailingTextBoundaryAt
(
position
),
inner
.
getTrailingTextBoundaryAt
(
pushedBackward
));
});
}
class
TestTextLayoutMetrics
extends
TextLayoutMetrics
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment