1cb93a386Sopenharmony_cidescribe('Font Behavior', () => {
2cb93a386Sopenharmony_ci    let container;
3cb93a386Sopenharmony_ci
4cb93a386Sopenharmony_ci    let notoSerifFontBuffer = null;
5cb93a386Sopenharmony_ci    // This font is known to support kerning
6cb93a386Sopenharmony_ci    const notoSerifFontLoaded = fetch('/assets/NotoSerif-Regular.ttf').then(
7cb93a386Sopenharmony_ci        (response) => response.arrayBuffer()).then(
8cb93a386Sopenharmony_ci        (buffer) => {
9cb93a386Sopenharmony_ci            notoSerifFontBuffer = buffer;
10cb93a386Sopenharmony_ci        });
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci    let bungeeFontBuffer = null;
13cb93a386Sopenharmony_ci    // This font has tofu for incorrect null terminators
14cb93a386Sopenharmony_ci    // see https://bugs.chromium.org/p/skia/issues/detail?id=9314
15cb93a386Sopenharmony_ci    const bungeeFontLoaded = fetch('/assets/Bungee-Regular.ttf').then(
16cb93a386Sopenharmony_ci        (response) => response.arrayBuffer()).then(
17cb93a386Sopenharmony_ci        (buffer) => {
18cb93a386Sopenharmony_ci            bungeeFontBuffer = buffer;
19cb93a386Sopenharmony_ci        });
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci    beforeEach(async () => {
22cb93a386Sopenharmony_ci        await LoadCanvasKit;
23cb93a386Sopenharmony_ci        await notoSerifFontLoaded;
24cb93a386Sopenharmony_ci        await bungeeFontLoaded;
25cb93a386Sopenharmony_ci        container = document.createElement('div');
26cb93a386Sopenharmony_ci        container.innerHTML = `
27cb93a386Sopenharmony_ci            <canvas width=600 height=600 id=test></canvas>
28cb93a386Sopenharmony_ci            <canvas width=600 height=600 id=report></canvas>`;
29cb93a386Sopenharmony_ci        document.body.appendChild(container);
30cb93a386Sopenharmony_ci    });
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci    afterEach(() => {
33cb93a386Sopenharmony_ci        document.body.removeChild(container);
34cb93a386Sopenharmony_ci    });
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci    gm('monospace_text_on_path', (canvas) => {
37cb93a386Sopenharmony_ci        const paint = new CanvasKit.Paint();
38cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
39cb93a386Sopenharmony_ci        paint.setStyle(CanvasKit.PaintStyle.Stroke);
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci        const font = new CanvasKit.Font(null, 24);
42cb93a386Sopenharmony_ci        const fontPaint = new CanvasKit.Paint();
43cb93a386Sopenharmony_ci        fontPaint.setAntiAlias(true);
44cb93a386Sopenharmony_ci        fontPaint.setStyle(CanvasKit.PaintStyle.Fill);
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci        const arc = new CanvasKit.Path();
48cb93a386Sopenharmony_ci        arc.arcToOval(CanvasKit.LTRBRect(20, 40, 280, 300), -160, 140, true);
49cb93a386Sopenharmony_ci        arc.lineTo(210, 140);
50cb93a386Sopenharmony_ci        arc.arcToOval(CanvasKit.LTRBRect(20, 0, 280, 260), 160, -140, true);
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci        // Only 1 dot should show up in the image, because we run out of path.
53cb93a386Sopenharmony_ci        const str = 'This téxt should follow the curve across contours...';
54cb93a386Sopenharmony_ci        const textBlob = CanvasKit.TextBlob.MakeOnPath(str, arc, font);
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci        canvas.drawPath(arc, paint);
57cb93a386Sopenharmony_ci        canvas.drawTextBlob(textBlob, 0, 0, fontPaint);
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci        textBlob.delete();
60cb93a386Sopenharmony_ci        arc.delete();
61cb93a386Sopenharmony_ci        paint.delete();
62cb93a386Sopenharmony_ci        font.delete();
63cb93a386Sopenharmony_ci        fontPaint.delete();
64cb93a386Sopenharmony_ci    });
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci    gm('serif_text_on_path', (canvas) => {
67cb93a386Sopenharmony_ci        const notoSerif = CanvasKit.Typeface.MakeFreeTypeFaceFromData(notoSerifFontBuffer);
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci        const paint = new CanvasKit.Paint();
70cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
71cb93a386Sopenharmony_ci        paint.setStyle(CanvasKit.PaintStyle.Stroke);
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ci        const font = new CanvasKit.Font(notoSerif, 24);
74cb93a386Sopenharmony_ci        const fontPaint = new CanvasKit.Paint();
75cb93a386Sopenharmony_ci        fontPaint.setAntiAlias(true);
76cb93a386Sopenharmony_ci        fontPaint.setStyle(CanvasKit.PaintStyle.Fill);
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci        const arc = new CanvasKit.Path();
79cb93a386Sopenharmony_ci        arc.arcToOval(CanvasKit.LTRBRect(20, 40, 280, 300), -160, 140, true);
80cb93a386Sopenharmony_ci        arc.lineTo(210, 140);
81cb93a386Sopenharmony_ci        arc.arcToOval(CanvasKit.LTRBRect(20, 0, 280, 260), 160, -140, true);
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci        const str = 'This téxt should follow the curve across contours...';
84cb93a386Sopenharmony_ci        const textBlob = CanvasKit.TextBlob.MakeOnPath(str, arc, font, 60.5);
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci        canvas.drawPath(arc, paint);
87cb93a386Sopenharmony_ci        canvas.drawTextBlob(textBlob, 0, 0, fontPaint);
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci        textBlob.delete();
90cb93a386Sopenharmony_ci        arc.delete();
91cb93a386Sopenharmony_ci        paint.delete();
92cb93a386Sopenharmony_ci        notoSerif.delete();
93cb93a386Sopenharmony_ci        font.delete();
94cb93a386Sopenharmony_ci        fontPaint.delete();
95cb93a386Sopenharmony_ci    });
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci    // https://bugs.chromium.org/p/skia/issues/detail?id=9314
98cb93a386Sopenharmony_ci    gm('nullterminators_skbug_9314', (canvas) => {
99cb93a386Sopenharmony_ci        const bungee = CanvasKit.Typeface.MakeFreeTypeFaceFromData(bungeeFontBuffer);
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci        // yellow, to make sure tofu is plainly visible
102cb93a386Sopenharmony_ci        canvas.clear(CanvasKit.Color(255, 255, 0, 1));
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ci        const font = new CanvasKit.Font(bungee, 24);
105cb93a386Sopenharmony_ci        const fontPaint = new CanvasKit.Paint();
106cb93a386Sopenharmony_ci        fontPaint.setAntiAlias(true);
107cb93a386Sopenharmony_ci        fontPaint.setStyle(CanvasKit.PaintStyle.Fill);
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci        const str = 'This is téxt';
111cb93a386Sopenharmony_ci        const textBlob = CanvasKit.TextBlob.MakeFromText(str + ' text blob', font);
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci        canvas.drawTextBlob(textBlob, 10, 50, fontPaint);
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci        canvas.drawText(str + ' normal', 10, 100, fontPaint, font);
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci        canvas.drawText('null terminator ->\u0000<- on purpose', 10, 150, fontPaint, font);
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci        textBlob.delete();
120cb93a386Sopenharmony_ci        bungee.delete();
121cb93a386Sopenharmony_ci        font.delete();
122cb93a386Sopenharmony_ci        fontPaint.delete();
123cb93a386Sopenharmony_ci    });
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci    gm('textblobs_with_glyphs', (canvas) => {
126cb93a386Sopenharmony_ci        canvas.clear(CanvasKit.WHITE);
127cb93a386Sopenharmony_ci        const notoSerif = CanvasKit.Typeface.MakeFreeTypeFaceFromData(notoSerifFontBuffer);
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci        const font = new CanvasKit.Font(notoSerif, 24);
130cb93a386Sopenharmony_ci        const bluePaint = new CanvasKit.Paint();
131cb93a386Sopenharmony_ci        bluePaint.setColor(CanvasKit.parseColorString('#04083f')); // arbitrary deep blue
132cb93a386Sopenharmony_ci        bluePaint.setAntiAlias(true);
133cb93a386Sopenharmony_ci        bluePaint.setStyle(CanvasKit.PaintStyle.Fill);
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci        const redPaint = new CanvasKit.Paint();
136cb93a386Sopenharmony_ci        redPaint.setColor(CanvasKit.parseColorString('#770b1e')); // arbitrary deep red
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci        const ids = notoSerif.getGlyphIDs('AEGIS ægis');
139cb93a386Sopenharmony_ci        expect(ids.length).toEqual(10); // one glyph id per glyph
140cb93a386Sopenharmony_ci        expect(ids[0]).toEqual(36); // spot check this, should be consistent as long as the font is.
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci        const bounds = font.getGlyphBounds(ids, bluePaint);
143cb93a386Sopenharmony_ci        expect(bounds.length).toEqual(40); // 4 measurements per glyph
144cb93a386Sopenharmony_ci        expect(bounds[0]).toEqual(0); // again, spot check the measurements for the first glyph.
145cb93a386Sopenharmony_ci        expect(bounds[1]).toEqual(-17);
146cb93a386Sopenharmony_ci        expect(bounds[2]).toEqual(17);
147cb93a386Sopenharmony_ci        expect(bounds[3]).toEqual(0);
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_ci        const widths = font.getGlyphWidths(ids, bluePaint);
150cb93a386Sopenharmony_ci        expect(widths.length).toEqual(10); // 1 width per glyph
151cb93a386Sopenharmony_ci        expect(widths[0]).toEqual(17);
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci        const topBlob = CanvasKit.TextBlob.MakeFromGlyphs(ids, font);
154cb93a386Sopenharmony_ci        canvas.drawTextBlob(topBlob, 5, 30, bluePaint);
155cb93a386Sopenharmony_ci        canvas.drawTextBlob(topBlob, 5, 60, redPaint);
156cb93a386Sopenharmony_ci        topBlob.delete();
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci        const mIDs = CanvasKit.MallocGlyphIDs(ids.length);
159cb93a386Sopenharmony_ci        const mArr = mIDs.toTypedArray();
160cb93a386Sopenharmony_ci        mArr.set(ids);
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci        const mXforms = CanvasKit.Malloc(Float32Array, ids.length * 4);
163cb93a386Sopenharmony_ci        const mXformsArr = mXforms.toTypedArray();
164cb93a386Sopenharmony_ci        // Draw each glyph rotated slightly and slightly lower than the glyph before it.
165cb93a386Sopenharmony_ci        let currX = 0;
166cb93a386Sopenharmony_ci        for (let i = 0; i < ids.length; i++) {
167cb93a386Sopenharmony_ci            mXformsArr[i * 4] = Math.cos(-Math.PI / 16); // scos
168cb93a386Sopenharmony_ci            mXformsArr[i * 4 + 1] = Math.sin(-Math.PI / 16); // ssin
169cb93a386Sopenharmony_ci            mXformsArr[i * 4 + 2] = currX; // tx
170cb93a386Sopenharmony_ci            mXformsArr[i * 4 + 3] = i*2; // ty
171cb93a386Sopenharmony_ci            currX += widths[i];
172cb93a386Sopenharmony_ci        }
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ci        const bottomBlob = CanvasKit.TextBlob.MakeFromRSXformGlyphs(mIDs, mXforms, font);
175cb93a386Sopenharmony_ci        canvas.drawTextBlob(bottomBlob, 5, 110, bluePaint);
176cb93a386Sopenharmony_ci        canvas.drawTextBlob(bottomBlob, 5, 140, redPaint);
177cb93a386Sopenharmony_ci        bottomBlob.delete();
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ci        CanvasKit.Free(mIDs);
180cb93a386Sopenharmony_ci        CanvasKit.Free(mXforms);
181cb93a386Sopenharmony_ci        bluePaint.delete();
182cb93a386Sopenharmony_ci        redPaint.delete();
183cb93a386Sopenharmony_ci        notoSerif.delete();
184cb93a386Sopenharmony_ci        font.delete();
185cb93a386Sopenharmony_ci    });
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ci    it('can make a font mgr with passed in fonts', () => {
188cb93a386Sopenharmony_ci        // CanvasKit.FontMgr.FromData([bungeeFontBuffer, notoSerifFontBuffer]) also works
189cb93a386Sopenharmony_ci        const fontMgr = CanvasKit.FontMgr.FromData(bungeeFontBuffer, notoSerifFontBuffer);
190cb93a386Sopenharmony_ci        expect(fontMgr).toBeTruthy();
191cb93a386Sopenharmony_ci        expect(fontMgr.countFamilies()).toBe(2);
192cb93a386Sopenharmony_ci        // in debug mode, let's list them.
193cb93a386Sopenharmony_ci        if (fontMgr.dumpFamilies) {
194cb93a386Sopenharmony_ci            fontMgr.dumpFamilies();
195cb93a386Sopenharmony_ci        }
196cb93a386Sopenharmony_ci        fontMgr.delete();
197cb93a386Sopenharmony_ci    });
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_ci    it('can make a font provider with passed in fonts and aliases', () => {
200cb93a386Sopenharmony_ci        const fontProvider = CanvasKit.TypefaceFontProvider.Make();
201cb93a386Sopenharmony_ci        fontProvider.registerFont(bungeeFontBuffer, "My Bungee Alias");
202cb93a386Sopenharmony_ci        fontProvider.registerFont(notoSerifFontBuffer, "My Noto Serif Alias");
203cb93a386Sopenharmony_ci        expect(fontProvider).toBeTruthy();
204cb93a386Sopenharmony_ci        expect(fontProvider.countFamilies()).toBe(2);
205cb93a386Sopenharmony_ci        // in debug mode, let's list them.
206cb93a386Sopenharmony_ci        if (fontProvider.dumpFamilies) {
207cb93a386Sopenharmony_ci            fontProvider.dumpFamilies();
208cb93a386Sopenharmony_ci        }
209cb93a386Sopenharmony_ci        fontProvider.delete();
210cb93a386Sopenharmony_ci    });
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci    gm('various_font_formats', (canvas, fetchedByteBuffers) => {
213cb93a386Sopenharmony_ci        const fontPaint = new CanvasKit.Paint();
214cb93a386Sopenharmony_ci        fontPaint.setAntiAlias(true);
215cb93a386Sopenharmony_ci        fontPaint.setStyle(CanvasKit.PaintStyle.Fill);
216cb93a386Sopenharmony_ci        const inputs = [{
217cb93a386Sopenharmony_ci            type: '.ttf font',
218cb93a386Sopenharmony_ci            buffer: bungeeFontBuffer,
219cb93a386Sopenharmony_ci            y: 60,
220cb93a386Sopenharmony_ci        },{
221cb93a386Sopenharmony_ci            type: '.otf font',
222cb93a386Sopenharmony_ci            buffer: fetchedByteBuffers[0],
223cb93a386Sopenharmony_ci            y: 90,
224cb93a386Sopenharmony_ci        },{
225cb93a386Sopenharmony_ci            type: '.woff font',
226cb93a386Sopenharmony_ci            buffer: fetchedByteBuffers[1],
227cb93a386Sopenharmony_ci            y: 120,
228cb93a386Sopenharmony_ci        },{
229cb93a386Sopenharmony_ci            type: '.woff2 font',
230cb93a386Sopenharmony_ci            buffer: fetchedByteBuffers[2],
231cb93a386Sopenharmony_ci            y: 150,
232cb93a386Sopenharmony_ci        }];
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci        const defaultFont = new CanvasKit.Font(null, 24);
235cb93a386Sopenharmony_ci        canvas.drawText(`The following should be ${inputs.length + 1} lines of text:`, 5, 30, fontPaint, defaultFont);
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci        for (const fontType of inputs) {
238cb93a386Sopenharmony_ci            // smoke test that the font bytes loaded.
239cb93a386Sopenharmony_ci            expect(fontType.buffer).toBeTruthy(fontType.type + ' did not load');
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_ci            const typeface = CanvasKit.Typeface.MakeFreeTypeFaceFromData(fontType.buffer);
242cb93a386Sopenharmony_ci            const font = new CanvasKit.Font(typeface, 24);
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_ci            if (font && typeface) {
245cb93a386Sopenharmony_ci                canvas.drawText(fontType.type + ' loaded', 5, fontType.y, fontPaint, font);
246cb93a386Sopenharmony_ci            } else {
247cb93a386Sopenharmony_ci                canvas.drawText(fontType.type + ' *not* loaded', 5, fontType.y, fontPaint, defaultFont);
248cb93a386Sopenharmony_ci            }
249cb93a386Sopenharmony_ci            font && font.delete();
250cb93a386Sopenharmony_ci            typeface && typeface.delete();
251cb93a386Sopenharmony_ci        }
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ci        // The only ttc font I could find was 14 MB big, so I'm using the smaller test font,
254cb93a386Sopenharmony_ci        // which doesn't have very many glyphs in it, so we just check that we got a non-zero
255cb93a386Sopenharmony_ci        // typeface for it. I was able to load NotoSansCJK-Regular.ttc just fine in a
256cb93a386Sopenharmony_ci        // manual test.
257cb93a386Sopenharmony_ci        const typeface = CanvasKit.Typeface.MakeFreeTypeFaceFromData(fetchedByteBuffers[3]);
258cb93a386Sopenharmony_ci        expect(typeface).toBeTruthy('.ttc font');
259cb93a386Sopenharmony_ci        if (typeface) {
260cb93a386Sopenharmony_ci            canvas.drawText('.ttc loaded', 5, 180, fontPaint, defaultFont);
261cb93a386Sopenharmony_ci            typeface.delete();
262cb93a386Sopenharmony_ci        } else {
263cb93a386Sopenharmony_ci            canvas.drawText('.ttc *not* loaded', 5, 180, fontPaint, defaultFont);
264cb93a386Sopenharmony_ci        }
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci        defaultFont.delete();
267cb93a386Sopenharmony_ci        fontPaint.delete();
268cb93a386Sopenharmony_ci    }, '/assets/Roboto-Regular.otf', '/assets/Roboto-Regular.woff', '/assets/Roboto-Regular.woff2', '/assets/test.ttc');
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci    it('can measure text very precisely with proper settings', () => {
271cb93a386Sopenharmony_ci        const typeface = CanvasKit.Typeface.MakeFreeTypeFaceFromData(notoSerifFontBuffer);
272cb93a386Sopenharmony_ci        const fontSizes = [257, 100, 11];
273cb93a386Sopenharmony_ci        // The point of these values is to let us know 1) we can measure to sub-pixel levels
274cb93a386Sopenharmony_ci        // and 2) that measurements don't drastically change. If these change a little bit,
275cb93a386Sopenharmony_ci        // just update them with the new values. For super-accurate readings, one could
276cb93a386Sopenharmony_ci        // run a C++ snippet of code and compare the values, but that is likely unnecessary
277cb93a386Sopenharmony_ci        // unless we suspect a bug with the bindings.
278cb93a386Sopenharmony_ci        const expectedSizes = [241.06299, 93.79883, 10.31787];
279cb93a386Sopenharmony_ci        for (const idx in fontSizes) {
280cb93a386Sopenharmony_ci            const font = new CanvasKit.Font(typeface, fontSizes[idx]);
281cb93a386Sopenharmony_ci            font.setHinting(CanvasKit.FontHinting.None);
282cb93a386Sopenharmony_ci            font.setLinearMetrics(true);
283cb93a386Sopenharmony_ci            font.setSubpixel(true);
284cb93a386Sopenharmony_ci
285cb93a386Sopenharmony_ci            const ids = font.getGlyphIDs('M');
286cb93a386Sopenharmony_ci            const widths = font.getGlyphWidths(ids);
287cb93a386Sopenharmony_ci            expect(widths[0]).toBeCloseTo(expectedSizes[idx], 5);
288cb93a386Sopenharmony_ci            font.delete();
289cb93a386Sopenharmony_ci        }
290cb93a386Sopenharmony_ci
291cb93a386Sopenharmony_ci        typeface.delete();
292cb93a386Sopenharmony_ci    });
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci    gm('font_edging', (canvas) => {
295cb93a386Sopenharmony_ci        // Draw a small font scaled up to see the aliasing artifacts.
296cb93a386Sopenharmony_ci        canvas.scale(8, 8);
297cb93a386Sopenharmony_ci        canvas.clear(CanvasKit.WHITE);
298cb93a386Sopenharmony_ci        const notoSerif = CanvasKit.Typeface.MakeFreeTypeFaceFromData(notoSerifFontBuffer);
299cb93a386Sopenharmony_ci
300cb93a386Sopenharmony_ci        const textPaint = new CanvasKit.Paint();
301cb93a386Sopenharmony_ci        const annotationFont = new CanvasKit.Font(notoSerif, 6);
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ci        canvas.drawText('Default', 5, 5, textPaint, annotationFont);
304cb93a386Sopenharmony_ci        canvas.drawText('Alias', 5, 25, textPaint, annotationFont);
305cb93a386Sopenharmony_ci        canvas.drawText('AntiAlias', 5, 45, textPaint, annotationFont);
306cb93a386Sopenharmony_ci        canvas.drawText('Subpixel', 5, 65, textPaint, annotationFont);
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci        const testFont = new CanvasKit.Font(notoSerif, 20);
309cb93a386Sopenharmony_ci
310cb93a386Sopenharmony_ci        canvas.drawText('SEA', 35, 15, textPaint, testFont);
311cb93a386Sopenharmony_ci        testFont.setEdging(CanvasKit.FontEdging.Alias);
312cb93a386Sopenharmony_ci        canvas.drawText('SEA', 35, 35, textPaint, testFont);
313cb93a386Sopenharmony_ci        testFont.setEdging(CanvasKit.FontEdging.AntiAlias);
314cb93a386Sopenharmony_ci        canvas.drawText('SEA', 35, 55, textPaint, testFont);
315cb93a386Sopenharmony_ci        testFont.setEdging(CanvasKit.FontEdging.SubpixelAntiAlias);
316cb93a386Sopenharmony_ci        canvas.drawText('SEA', 35, 75, textPaint, testFont);
317cb93a386Sopenharmony_ci
318cb93a386Sopenharmony_ci        textPaint.delete();
319cb93a386Sopenharmony_ci        annotationFont.delete();
320cb93a386Sopenharmony_ci        testFont.delete();
321cb93a386Sopenharmony_ci        notoSerif.delete();
322cb93a386Sopenharmony_ci    });
323cb93a386Sopenharmony_ci
324cb93a386Sopenharmony_ci    it('can get the intercepts of glyphs', () => {
325cb93a386Sopenharmony_ci        const font = new CanvasKit.Font(null, 100);
326cb93a386Sopenharmony_ci        const ids = font.getGlyphIDs('I');
327cb93a386Sopenharmony_ci        expect(ids.length).toEqual(1);
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_ci        // aim for the middle of the I at 100 point, expecting a hit
330cb93a386Sopenharmony_ci        let sects = font.getGlyphIntercepts(ids, [0, 0], -60, -40);
331cb93a386Sopenharmony_ci        expect(sects.length).toEqual(2, "expected one pair of intercepts");
332cb93a386Sopenharmony_ci        expect(sects[0]).toBeCloseTo(25.39063, 5);
333cb93a386Sopenharmony_ci        expect(sects[1]).toBeCloseTo(34.52148, 5);
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci        // aim below the baseline where we expect no intercepts
336cb93a386Sopenharmony_ci        sects = font.getGlyphIntercepts(ids, [0, 0], 20, 30);
337cb93a386Sopenharmony_ci        expect(sects.length).toEqual(0, "expected no intercepts");
338cb93a386Sopenharmony_ci        font.delete();
339cb93a386Sopenharmony_ci    });
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci    it('can use mallocd and normal arrays', () => {
342cb93a386Sopenharmony_ci        const font = new CanvasKit.Font(null, 100);
343cb93a386Sopenharmony_ci        const ids = font.getGlyphIDs('I');
344cb93a386Sopenharmony_ci        expect(ids.length).toEqual(1);
345cb93a386Sopenharmony_ci        const glyphID = ids[0];
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci        // aim for the middle of the I at 100 point, expecting a hit
348cb93a386Sopenharmony_ci        const sects = font.getGlyphIntercepts(Array.of(glyphID), Float32Array.of(0, 0), -60, -40);
349cb93a386Sopenharmony_ci        expect(sects.length).toEqual(2);
350cb93a386Sopenharmony_ci        expect(sects[0]).toBeLessThan(sects[1]);
351cb93a386Sopenharmony_ci        // these values were recorded from the first time it was run
352cb93a386Sopenharmony_ci        expect(sects[0]).toBeCloseTo(25.39063, 5);
353cb93a386Sopenharmony_ci        expect(sects[1]).toBeCloseTo(34.52148, 5);
354cb93a386Sopenharmony_ci
355cb93a386Sopenharmony_ci        const free_list = [];   // will free CanvasKit.Malloc objects at the end
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_ci        // Want to exercise 4 different ways we can receive an array:
358cb93a386Sopenharmony_ci        //  1. normal array
359cb93a386Sopenharmony_ci        //  2. typed-array
360cb93a386Sopenharmony_ci        //  3. CanvasKit.Malloc typeed-array
361cb93a386Sopenharmony_ci        //  4. CavnasKit.Malloc (raw)
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_ci        const id_makers = [
364cb93a386Sopenharmony_ci            (id) => [ id ],
365cb93a386Sopenharmony_ci            (id) => new Uint16Array([ id ]),
366cb93a386Sopenharmony_ci            (id) => {
367cb93a386Sopenharmony_ci                const a = CanvasKit.Malloc(Uint16Array, 1);
368cb93a386Sopenharmony_ci                free_list.push(a);
369cb93a386Sopenharmony_ci                const ta = a.toTypedArray();
370cb93a386Sopenharmony_ci                ta[0] = id;
371cb93a386Sopenharmony_ci                return ta;  // return typed-array
372cb93a386Sopenharmony_ci            },
373cb93a386Sopenharmony_ci            (id) => {
374cb93a386Sopenharmony_ci                const a = CanvasKit.Malloc(Uint16Array, 1);
375cb93a386Sopenharmony_ci                free_list.push(a);
376cb93a386Sopenharmony_ci                a.toTypedArray()[0] = id;
377cb93a386Sopenharmony_ci                return a;   // return raw obj
378cb93a386Sopenharmony_ci            },
379cb93a386Sopenharmony_ci        ];
380cb93a386Sopenharmony_ci        const pos_makers = [
381cb93a386Sopenharmony_ci            (x, y) => [ x, y ],
382cb93a386Sopenharmony_ci            (x, y) => new Float32Array([ x, y ]),
383cb93a386Sopenharmony_ci            (x, y) => {
384cb93a386Sopenharmony_ci                const a = CanvasKit.Malloc(Float32Array, 2);
385cb93a386Sopenharmony_ci                free_list.push(a);
386cb93a386Sopenharmony_ci                const ta = a.toTypedArray();
387cb93a386Sopenharmony_ci                ta[0] = x;
388cb93a386Sopenharmony_ci                ta[1] = y;
389cb93a386Sopenharmony_ci                return ta;  // return typed-array
390cb93a386Sopenharmony_ci            },
391cb93a386Sopenharmony_ci            (x, y) => {
392cb93a386Sopenharmony_ci                const a = CanvasKit.Malloc(Float32Array, 2);
393cb93a386Sopenharmony_ci                free_list.push(a);
394cb93a386Sopenharmony_ci                const ta = a.toTypedArray();
395cb93a386Sopenharmony_ci                ta[0] = x;
396cb93a386Sopenharmony_ci                ta[1] = y;
397cb93a386Sopenharmony_ci                return a;   // return raw obj
398cb93a386Sopenharmony_ci            },
399cb93a386Sopenharmony_ci        ];
400cb93a386Sopenharmony_ci
401cb93a386Sopenharmony_ci        for (const idm of id_makers) {
402cb93a386Sopenharmony_ci            for (const posm of pos_makers) {
403cb93a386Sopenharmony_ci                const s = font.getGlyphIntercepts(idm(glyphID), posm(0, 0), -60, -40);
404cb93a386Sopenharmony_ci                expect(s.length).toEqual(sects.length);
405cb93a386Sopenharmony_ci                for (let i = 0; i < s.length; ++i) {
406cb93a386Sopenharmony_ci                    expect(s[i]).toEqual(sects[i]);
407cb93a386Sopenharmony_ci                }
408cb93a386Sopenharmony_ci            }
409cb93a386Sopenharmony_ci
410cb93a386Sopenharmony_ci        }
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci        free_list.forEach(obj => CanvasKit.Free(obj));
413cb93a386Sopenharmony_ci        font.delete();
414cb93a386Sopenharmony_ci    });
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci});
417