@@ -8,7 +8,7 @@ import 'package:ui/ui.dart';
88import 'package:test/test.dart' ;
99
1010void testEachMeasurement (String description, VoidCallback body, {bool skip}) {
11- test (description, () async {
11+ test ('$ description (dom measurement)' , () async {
1212 try {
1313 TextMeasurementService .initialize (rulerCacheCapacity: 2 );
1414 return body ();
@@ -130,6 +130,154 @@ void main() async {
130130 }, // TODO(nurhan): https://github.com/flutter/flutter/issues/46638
131131 skip: (browserEngine == BrowserEngine .firefox));
132132
133+ testEachMeasurement ('getPositionForOffset single-line' , () {
134+ final ParagraphBuilder builder = ParagraphBuilder (ParagraphStyle (
135+ fontFamily: 'Ahem' ,
136+ fontStyle: FontStyle .normal,
137+ fontWeight: FontWeight .normal,
138+ fontSize: 10 ,
139+ textDirection: TextDirection .ltr,
140+ ));
141+ builder.addText ('abcd efg' );
142+ final Paragraph paragraph = builder.build ();
143+ paragraph.layout (const ParagraphConstraints (width: 1000 ));
144+
145+ // At the beginning of the line.
146+ expect (
147+ paragraph.getPositionForOffset (Offset (0 , 5 )),
148+ TextPosition (offset: 0 , affinity: TextAffinity .downstream),
149+ );
150+ // Below the line.
151+ expect (
152+ paragraph.getPositionForOffset (Offset (0 , 12 )),
153+ TextPosition (offset: 8 , affinity: TextAffinity .upstream),
154+ );
155+ // Above the line.
156+ expect (
157+ paragraph.getPositionForOffset (Offset (0 , - 5 )),
158+ TextPosition (offset: 0 , affinity: TextAffinity .downstream),
159+ );
160+ // At the end of the line.
161+ expect (
162+ paragraph.getPositionForOffset (Offset (80 , 5 )),
163+ TextPosition (offset: 8 , affinity: TextAffinity .upstream),
164+ );
165+ // On the left side of "b".
166+ expect (
167+ paragraph.getPositionForOffset (Offset (14 , 5 )),
168+ TextPosition (offset: 1 , affinity: TextAffinity .downstream),
169+ );
170+ // On the right side of "b".
171+ expect (
172+ paragraph.getPositionForOffset (Offset (16 , 5 )),
173+ TextPosition (offset: 2 , affinity: TextAffinity .upstream),
174+ );
175+ });
176+
177+ test ('getPositionForOffset multi-line' , () {
178+ // [Paragraph.getPositionForOffset] for multi-line text doesn't work well
179+ // with dom-based measurement.
180+ TextMeasurementService .enableExperimentalCanvasImplementation = true ;
181+ TextMeasurementService .initialize (rulerCacheCapacity: 2 );
182+
183+ final ParagraphBuilder builder = ParagraphBuilder (ParagraphStyle (
184+ fontFamily: 'Ahem' ,
185+ fontStyle: FontStyle .normal,
186+ fontWeight: FontWeight .normal,
187+ fontSize: 10 ,
188+ textDirection: TextDirection .ltr,
189+ ));
190+ builder.addText ('abcd\n ' );
191+ builder.addText ('abcdefg\n ' );
192+ builder.addText ('ab' );
193+ final Paragraph paragraph = builder.build ();
194+ paragraph.layout (const ParagraphConstraints (width: 1000 ));
195+
196+ // First line: "abcd\n"
197+
198+ // At the beginning of the first line.
199+ expect (
200+ paragraph.getPositionForOffset (Offset (0 , 5 )),
201+ TextPosition (offset: 0 , affinity: TextAffinity .downstream),
202+ );
203+ // Above the first line.
204+ expect (
205+ paragraph.getPositionForOffset (Offset (0 , - 5 )),
206+ TextPosition (offset: 0 , affinity: TextAffinity .downstream),
207+ );
208+ // At the end of the first line.
209+ expect (
210+ paragraph.getPositionForOffset (Offset (50 , 5 )),
211+ TextPosition (offset: 5 , affinity: TextAffinity .upstream),
212+ );
213+ // On the left side of "b" in the first line.
214+ expect (
215+ paragraph.getPositionForOffset (Offset (14 , 5 )),
216+ TextPosition (offset: 1 , affinity: TextAffinity .downstream),
217+ );
218+ // On the right side of "b" in the first line.
219+ expect (
220+ paragraph.getPositionForOffset (Offset (16 , 5 )),
221+ TextPosition (offset: 2 , affinity: TextAffinity .upstream),
222+ );
223+
224+
225+ // Second line: "abcdefg\n"
226+
227+ // At the beginning of the second line.
228+ expect (
229+ paragraph.getPositionForOffset (Offset (0 , 15 )),
230+ TextPosition (offset: 5 , affinity: TextAffinity .downstream),
231+ );
232+ // At the end of the second line.
233+ expect (
234+ paragraph.getPositionForOffset (Offset (100 , 15 )),
235+ TextPosition (offset: 13 , affinity: TextAffinity .upstream),
236+ );
237+ // On the left side of "e" in the second line.
238+ expect (
239+ paragraph.getPositionForOffset (Offset (44 , 15 )),
240+ TextPosition (offset: 9 , affinity: TextAffinity .downstream),
241+ );
242+ // On the right side of "e" in the second line.
243+ expect (
244+ paragraph.getPositionForOffset (Offset (46 , 15 )),
245+ TextPosition (offset: 10 , affinity: TextAffinity .upstream),
246+ );
247+
248+
249+ // Last (third) line: "ab"
250+
251+ // At the beginning of the last line.
252+ expect (
253+ paragraph.getPositionForOffset (Offset (0 , 25 )),
254+ TextPosition (offset: 13 , affinity: TextAffinity .downstream),
255+ );
256+ // At the end of the last line.
257+ expect (
258+ paragraph.getPositionForOffset (Offset (40 , 25 )),
259+ TextPosition (offset: 15 , affinity: TextAffinity .upstream),
260+ );
261+ // Below the last line.
262+ expect (
263+ paragraph.getPositionForOffset (Offset (0 , 32 )),
264+ TextPosition (offset: 15 , affinity: TextAffinity .upstream),
265+ );
266+ // On the left side of "b" in the last line.
267+ expect (
268+ paragraph.getPositionForOffset (Offset (12 , 25 )),
269+ TextPosition (offset: 14 , affinity: TextAffinity .downstream),
270+ );
271+ // On the right side of "a" in the last line.
272+ expect (
273+ paragraph.getPositionForOffset (Offset (9 , 25 )),
274+ TextPosition (offset: 14 , affinity: TextAffinity .upstream),
275+ );
276+
277+ TextMeasurementService .clearCache ();
278+ TextMeasurementService .enableExperimentalCanvasImplementation = false ;
279+ });
280+
133281 testEachMeasurement ('getBoxesForRange returns a box' , () {
134282 final ParagraphBuilder builder = ParagraphBuilder (ParagraphStyle (
135283 fontFamily: 'Ahem' ,
0 commit comments