Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2fedf31

Browse files
committed
[web] Consider maxLines when calculating boxes for a range
1 parent 0d87160 commit 2fedf31

File tree

3 files changed

+216
-10
lines changed

3 files changed

+216
-10
lines changed

lib/web_ui/lib/src/engine/text/paragraph.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,10 @@ class EngineParagraph implements ui.Paragraph {
374374
}
375375

376376
final List<EngineLineMetrics> lines = _measurementResult.lines;
377+
if (start >= lines.last.endIndex) {
378+
return <ui.TextBox>[];
379+
}
380+
377381
final EngineLineMetrics startLine = _getLineForIndex(start);
378382
EngineLineMetrics endLine = _getLineForIndex(end);
379383

@@ -535,8 +539,7 @@ class EngineParagraph implements ui.Paragraph {
535539
EngineLineMetrics _getLineForIndex(int index) {
536540
assert(_hasLineMetrics);
537541
final List<EngineLineMetrics> lines = _measurementResult.lines;
538-
assert(index >= lines.first.startIndex);
539-
assert(index <= lines.last.endIndex);
542+
assert(index >= 0);
540543

541544
for (int i = 0; i < lines.length; i++) {
542545
final EngineLineMetrics line = lines[i];
@@ -545,7 +548,6 @@ class EngineParagraph implements ui.Paragraph {
545548
}
546549
}
547550

548-
assert(index == lines.last.endIndex);
549551
return lines.last;
550552
}
551553

lib/web_ui/lib/src/engine/text/ruler.dart

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -733,14 +733,20 @@ class ParagraphRuler {
733733
final List<html.Rectangle<num>> clientRects = rangeSpan.getClientRects();
734734
final List<ui.TextBox> boxes = <ui.TextBox>[];
735735

736+
final double maxLinesLimit = style.maxLines == null
737+
? double.infinity
738+
: style.maxLines * lineHeightDimensions.height;
739+
736740
for (html.Rectangle<num> rect in clientRects) {
737-
boxes.add(ui.TextBox.fromLTRBD(
738-
rect.left + alignOffset,
739-
rect.top,
740-
rect.right + alignOffset,
741-
rect.bottom,
742-
textDirection,
743-
));
741+
if (rect.top < maxLinesLimit) {
742+
boxes.add(ui.TextBox.fromLTRBD(
743+
rect.left + alignOffset,
744+
rect.top,
745+
rect.right + alignOffset,
746+
rect.bottom,
747+
textDirection,
748+
));
749+
}
744750
}
745751

746752
// Cleanup after measuring the boxes.

lib/web_ui/test/paragraph_test.dart

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,204 @@ void main() async {
630630
);
631631
});
632632

633+
testEachMeasurement('getBoxesForRange with maxLines', () {
634+
final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle(
635+
fontFamily: 'Ahem',
636+
fontStyle: FontStyle.normal,
637+
fontWeight: FontWeight.normal,
638+
fontSize: 10,
639+
textDirection: TextDirection.ltr,
640+
maxLines: 2,
641+
));
642+
builder.addText('abcd\n');
643+
builder.addText('abcdefg\n');
644+
builder.addText('ab');
645+
final Paragraph paragraph = builder.build();
646+
paragraph.layout(const ParagraphConstraints(width: 100));
647+
648+
// In the dom-based measurement (except Firefox), there will be some
649+
// discrepancies around line ends.
650+
final isDiscrepancyExpected =
651+
!TextMeasurementService.enableExperimentalCanvasImplementation &&
652+
browserEngine != BrowserEngine.firefox;
653+
654+
// First line: "abcd\n"
655+
656+
// At the beginning of the first line.
657+
expect(
658+
paragraph.getBoxesForRange(0, 0),
659+
<TextBox>[],
660+
);
661+
// At the end of the first line.
662+
expect(
663+
paragraph.getBoxesForRange(4, 4),
664+
<TextBox>[],
665+
);
666+
// Between "b" and "c" in the first line.
667+
expect(
668+
paragraph.getBoxesForRange(2, 2),
669+
<TextBox>[],
670+
);
671+
// The range "ab" in the first line.
672+
expect(
673+
paragraph.getBoxesForRange(0, 2),
674+
<TextBox>[
675+
TextBox.fromLTRBD(0.0, 0.0, 20.0, 10.0, TextDirection.ltr),
676+
],
677+
);
678+
// The range "bc" in the first line.
679+
expect(
680+
paragraph.getBoxesForRange(1, 3),
681+
<TextBox>[
682+
TextBox.fromLTRBD(10.0, 0.0, 30.0, 10.0, TextDirection.ltr),
683+
],
684+
);
685+
// The range "d" in the first line.
686+
expect(
687+
paragraph.getBoxesForRange(3, 4),
688+
<TextBox>[
689+
TextBox.fromLTRBD(30.0, 0.0, 40.0, 10.0, TextDirection.ltr),
690+
],
691+
);
692+
// The range "\n" in the first line.
693+
expect(
694+
paragraph.getBoxesForRange(4, 5),
695+
<TextBox>[
696+
TextBox.fromLTRBD(40.0, 0.0, 40.0, 10.0, TextDirection.ltr),
697+
],
698+
);
699+
// The range "cd\n" in the first line.
700+
expect(
701+
paragraph.getBoxesForRange(2, 5),
702+
<TextBox>[
703+
TextBox.fromLTRBD(20.0, 0.0, 40.0, 10.0, TextDirection.ltr),
704+
if (isDiscrepancyExpected)
705+
TextBox.fromLTRBD(40.0, 0.0, 40.0, 10.0, TextDirection.ltr),
706+
],
707+
);
708+
709+
// Second line: "abcdefg\n"
710+
711+
// At the beginning of the second line.
712+
expect(
713+
paragraph.getBoxesForRange(5, 5),
714+
<TextBox>[],
715+
);
716+
// At the end of the second line.
717+
expect(
718+
paragraph.getBoxesForRange(12, 12),
719+
<TextBox>[],
720+
);
721+
// The range "efg" in the second line.
722+
expect(
723+
paragraph.getBoxesForRange(9, 12),
724+
<TextBox>[
725+
TextBox.fromLTRBD(40.0, 10.0, 70.0, 20.0, TextDirection.ltr),
726+
],
727+
);
728+
// The range "bcde" in the second line.
729+
expect(
730+
paragraph.getBoxesForRange(6, 10),
731+
<TextBox>[
732+
TextBox.fromLTRBD(10.0, 10.0, 50.0, 20.0, TextDirection.ltr),
733+
],
734+
);
735+
// The range "fg\n" in the second line.
736+
expect(
737+
paragraph.getBoxesForRange(10, 13),
738+
<TextBox>[
739+
TextBox.fromLTRBD(50.0, 10.0, 70.0, 20.0, TextDirection.ltr),
740+
if (isDiscrepancyExpected)
741+
TextBox.fromLTRBD(70.0, 10.0, 70.0, 20.0, TextDirection.ltr),
742+
],
743+
);
744+
745+
// Last (third) line: "ab"
746+
747+
// At the beginning of the last line.
748+
expect(
749+
paragraph.getBoxesForRange(13, 13),
750+
<TextBox>[],
751+
);
752+
// At the end of the last line.
753+
expect(
754+
paragraph.getBoxesForRange(15, 15),
755+
<TextBox>[],
756+
);
757+
// The range "a" in the last line.
758+
expect(
759+
paragraph.getBoxesForRange(14, 15),
760+
<TextBox>[],
761+
);
762+
// The range "ab" in the last line.
763+
expect(
764+
paragraph.getBoxesForRange(13, 15),
765+
<TextBox>[],
766+
);
767+
768+
769+
// Combine multiple lines
770+
771+
// The range "cd\nabc".
772+
expect(
773+
paragraph.getBoxesForRange(2, 8),
774+
<TextBox>[
775+
TextBox.fromLTRBD(20.0, 0.0, 40.0, 10.0, TextDirection.ltr),
776+
if (isDiscrepancyExpected)
777+
TextBox.fromLTRBD(40.0, 0.0, 40.0, 10.0, TextDirection.ltr),
778+
TextBox.fromLTRBD(0.0, 10.0, 30.0, 20.0, TextDirection.ltr),
779+
],
780+
);
781+
782+
// The range "\nabcd".
783+
expect(
784+
paragraph.getBoxesForRange(4, 9),
785+
<TextBox>[
786+
TextBox.fromLTRBD(40.0, 0.0, 40.0, 10.0, TextDirection.ltr),
787+
TextBox.fromLTRBD(0.0, 10.0, 40.0, 20.0, TextDirection.ltr),
788+
],
789+
);
790+
791+
// The range "d\nabcdefg\na".
792+
expect(
793+
paragraph.getBoxesForRange(3, 14),
794+
<TextBox>[
795+
TextBox.fromLTRBD(30.0, 0.0, 40.0, 10.0, TextDirection.ltr),
796+
if (isDiscrepancyExpected)
797+
TextBox.fromLTRBD(40.0, 0.0, 40.0, 10.0, TextDirection.ltr),
798+
TextBox.fromLTRBD(0.0, 10.0, 70.0, 20.0, TextDirection.ltr),
799+
if (isDiscrepancyExpected)
800+
TextBox.fromLTRBD(70.0, 10.0, 70.0, 20.0, TextDirection.ltr),
801+
],
802+
);
803+
804+
// The range "abcd\nabcdefg\n".
805+
expect(
806+
paragraph.getBoxesForRange(0, 13),
807+
<TextBox>[
808+
TextBox.fromLTRBD(0.0, 0.0, 40.0, 10.0, TextDirection.ltr),
809+
if (isDiscrepancyExpected)
810+
TextBox.fromLTRBD(40.0, 0.0, 40.0, 10.0, TextDirection.ltr),
811+
TextBox.fromLTRBD(0.0, 10.0, 70.0, 20.0, TextDirection.ltr),
812+
if (isDiscrepancyExpected)
813+
TextBox.fromLTRBD(70.0, 10.0, 70.0, 20.0, TextDirection.ltr),
814+
],
815+
);
816+
817+
// The range "abcd\nabcdefg\nab".
818+
expect(
819+
paragraph.getBoxesForRange(0, 15),
820+
<TextBox>[
821+
TextBox.fromLTRBD(0.0, 0.0, 40.0, 10.0, TextDirection.ltr),
822+
if (isDiscrepancyExpected)
823+
TextBox.fromLTRBD(40.0, 0.0, 40.0, 10.0, TextDirection.ltr),
824+
TextBox.fromLTRBD(0.0, 10.0, 70.0, 20.0, TextDirection.ltr),
825+
if (isDiscrepancyExpected)
826+
TextBox.fromLTRBD(70.0, 10.0, 70.0, 20.0, TextDirection.ltr),
827+
],
828+
);
829+
});
830+
633831
test('longestLine', () {
634832
// [Paragraph.longestLine] is only supported by canvas-based measurement.
635833
TextMeasurementService.enableExperimentalCanvasImplementation = true;

0 commit comments

Comments
 (0)