@@ -594,15 +594,16 @@ mixin _FragmentBox on _CombinedFragment, _FragmentMetrics, _FragmentPosition {
594594 return x;
595595 }
596596
597- // A naive implementation that only accounts for valid surrogate pairs. This
598- // is only used if Intl.Segmenter() is not supported so _fromDomSegmenter can't
599- // be called .
597+ // This is the fallback graphme breaker that is only used if Intl.Segmenter()
598+ // is not supported so _fromDomSegmenter can't be called. This implementation
599+ // breaks the text into UTF-16 codepoints instead of graphme clusters .
600600 List <int > _fallbackGraphemeStartIterable (String fragmentText) {
601601 final List <int > graphemeStarts = < int > [];
602602 bool precededByHighSurrogate = false ;
603603 for (int i = 0 ; i < fragmentText.length; i++ ) {
604604 final int maskedCodeUnit = fragmentText.codeUnitAt (i) & 0xFC00 ;
605- if (maskedCodeUnit != 0xDC00 || precededByHighSurrogate) {
605+ // Only skip `i` if it points to a low surrogate in a valid surrogate pair.
606+ if (maskedCodeUnit != 0xDC00 || ! precededByHighSurrogate) {
606607 graphemeStarts.add (start + i);
607608 }
608609 precededByHighSurrogate = maskedCodeUnit == 0xD800 ;
@@ -625,7 +626,7 @@ mixin _FragmentBox on _CombinedFragment, _FragmentMetrics, _FragmentPosition {
625626 return graphemeStarts;
626627 }
627628
628- // This List is an ordered ( ascending) sequence of UTF16 offsets that points to
629+ // This List contains an ascending sequence of UTF16 offsets that points to
629630 // grapheme starts within the fragment. Each UTF16 offset is relative to the
630631 // start of the paragraph, instead of the start of the fragment.
631632 late final List <int > _graphemeStarts = _breakFragmentText (
@@ -640,10 +641,8 @@ mixin _FragmentBox on _CombinedFragment, _FragmentMetrics, _FragmentPosition {
640641 return graphemeStarts;
641642 }
642643
643- // Returns the GlyphCluster within the range
644- // [_graphemeStarts[startIndex], _graphemeStarts[endIndex]) in the fragment
645- // that's visually closeset to the given horizontal offset `x` (in the
646- // paragraph's coordinates).
644+ // Returns the GlyphInfo within the range [_graphemeStarts[startIndex], _graphemeStarts[endIndex]),
645+ // that's visually closeset to the given horizontal offset `x` (in the paragraph's coordinates).
647646 ui.GlyphInfo _getClosestCharacterInRange (double x, int startIndex, int endIndex) {
648647 final ui.TextRange fullRange = ui.TextRange (start: _graphemeStarts[startIndex], end: _graphemeStarts[endIndex]);
649648 final ui.TextBox fullBox = toTextBox (start: fullRange.start, end: fullRange.end);
@@ -652,8 +651,11 @@ mixin _FragmentBox on _CombinedFragment, _FragmentMetrics, _FragmentPosition {
652651 }
653652 assert (startIndex + 1 < endIndex);
654653 final ui.TextBox (: double left, : double right) = fullBox;
655- // The toTextBox call is potentially expensive so we'll try avoiding
656- // measuring every character in the fragment.
654+
655+ // The toTextBox call is potentially expensive so we'll try reducing the
656+ // search steps with a binary search.
657+ //
658+ // x ∈ (left, right),
657659 if (left < x && x < right) {
658660 final int midIndex = (startIndex + endIndex) ~ / 2 ;
659661 // endIndex >= startIndex + 2, so midIndex >= start + 1
@@ -672,15 +674,14 @@ mixin _FragmentBox on _CombinedFragment, _FragmentMetrics, _FragmentPosition {
672674 return distanceToFirst > distanceToSecond ? firstHalf : secondHalf;
673675 }
674676
675- // Whether the first character or the last character is the closest.
677+ // x ∉ (left, right), it's either the first character or the last, since
678+ // there can only be one writing direction in the fragment.
676679 final ui.TextRange range = switch ((fullBox.direction, x <= left)) {
677- (ui.TextDirection .ltr, true ) ||
678- (ui.TextDirection .rtl, false ) => ui.TextRange (
680+ (ui.TextDirection .ltr, true ) || (ui.TextDirection .rtl, false ) => ui.TextRange (
679681 start: start + _graphemeStarts[startIndex],
680682 end: start + _graphemeStarts[startIndex + 1 ],
681683 ),
682- (ui.TextDirection .ltr, false ) ||
683- (ui.TextDirection .rtl, true ) => ui.TextRange (
684+ (ui.TextDirection .ltr, false ) || (ui.TextDirection .rtl, true ) => ui.TextRange (
684685 start: start + _graphemeStarts[endIndex - 1 ],
685686 end: start + _graphemeStarts[endIndex],
686687 ),
@@ -689,6 +690,8 @@ mixin _FragmentBox on _CombinedFragment, _FragmentMetrics, _FragmentPosition {
689690 return ui.GlyphInfo (box.toRect (), range, box.direction);
690691 }
691692
693+ /// Returns the UTF-16 range of the character that encloses the code unit at
694+ /// the given offset.
692695 ui.TextRange ? getCharacterRangeAt (int codeUnitOffset) {
693696 if (end == start) {
694697 return null ;
@@ -710,8 +713,8 @@ mixin _FragmentBox on _CombinedFragment, _FragmentMetrics, _FragmentPosition {
710713 return null ;
711714 }
712715
713- // There doesn't seem to be na easy way to get GlyphClusters using the web API.
714- // Pretend each grapheme cluster corresponds to a glyph cluster .
716+ /// Returns the GlyphInfo of the character in the fragment that is closest to
717+ /// the given offset x .
715718 ui.GlyphInfo ? getClosestCharacterBox (double x) {
716719 if (end == start) {
717720 return null ;
0 commit comments