1*c8dee2aaSAndroid Build Coastguard Workerdescribe('Paragraph Behavior', function() { 2*c8dee2aaSAndroid Build Coastguard Worker let container; 3*c8dee2aaSAndroid Build Coastguard Worker 4*c8dee2aaSAndroid Build Coastguard Worker const assetLoadingPromises = []; 5*c8dee2aaSAndroid Build Coastguard Worker let notoSerifFontBuffer = null; 6*c8dee2aaSAndroid Build Coastguard Worker // This font is known to support kerning 7*c8dee2aaSAndroid Build Coastguard Worker assetLoadingPromises.push(fetch('/assets/NotoSerif-Regular.ttf').then( 8*c8dee2aaSAndroid Build Coastguard Worker (response) => response.arrayBuffer()).then( 9*c8dee2aaSAndroid Build Coastguard Worker (buffer) => { 10*c8dee2aaSAndroid Build Coastguard Worker notoSerifFontBuffer = buffer; 11*c8dee2aaSAndroid Build Coastguard Worker })); 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Worker let notoSerifBoldItalicFontBuffer = null; 14*c8dee2aaSAndroid Build Coastguard Worker assetLoadingPromises.push(fetch('/assets/NotoSerif-BoldItalic.ttf').then( 15*c8dee2aaSAndroid Build Coastguard Worker (response) => response.arrayBuffer()).then( 16*c8dee2aaSAndroid Build Coastguard Worker (buffer) => { 17*c8dee2aaSAndroid Build Coastguard Worker notoSerifBoldItalicFontBuffer = buffer; 18*c8dee2aaSAndroid Build Coastguard Worker })); 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard Worker let emojiFontBuffer = null; 21*c8dee2aaSAndroid Build Coastguard Worker assetLoadingPromises.push(fetch('/assets/NotoColorEmoji.ttf').then( 22*c8dee2aaSAndroid Build Coastguard Worker (response) => response.arrayBuffer()).then( 23*c8dee2aaSAndroid Build Coastguard Worker (buffer) => { 24*c8dee2aaSAndroid Build Coastguard Worker emojiFontBuffer = buffer; 25*c8dee2aaSAndroid Build Coastguard Worker })); 26*c8dee2aaSAndroid Build Coastguard Worker 27*c8dee2aaSAndroid Build Coastguard Worker let robotoFontBuffer = null; 28*c8dee2aaSAndroid Build Coastguard Worker assetLoadingPromises.push(fetch('/assets/Roboto-Regular.otf').then( 29*c8dee2aaSAndroid Build Coastguard Worker (response) => response.arrayBuffer()).then( 30*c8dee2aaSAndroid Build Coastguard Worker (buffer) => { 31*c8dee2aaSAndroid Build Coastguard Worker robotoFontBuffer = buffer; 32*c8dee2aaSAndroid Build Coastguard Worker })); 33*c8dee2aaSAndroid Build Coastguard Worker 34*c8dee2aaSAndroid Build Coastguard Worker let robotoVariableFontBuffer = null; 35*c8dee2aaSAndroid Build Coastguard Worker assetLoadingPromises.push(fetch('/assets/RobotoSlab-VariableFont_wght.ttf').then( 36*c8dee2aaSAndroid Build Coastguard Worker (response) => response.arrayBuffer()).then( 37*c8dee2aaSAndroid Build Coastguard Worker (buffer) => { 38*c8dee2aaSAndroid Build Coastguard Worker robotoVariableFontBuffer = buffer; 39*c8dee2aaSAndroid Build Coastguard Worker })); 40*c8dee2aaSAndroid Build Coastguard Worker 41*c8dee2aaSAndroid Build Coastguard Worker beforeEach(async () => { 42*c8dee2aaSAndroid Build Coastguard Worker await EverythingLoaded; 43*c8dee2aaSAndroid Build Coastguard Worker await Promise.all(assetLoadingPromises); 44*c8dee2aaSAndroid Build Coastguard Worker container = document.createElement('div'); 45*c8dee2aaSAndroid Build Coastguard Worker container.innerHTML = ` 46*c8dee2aaSAndroid Build Coastguard Worker <canvas width=600 height=600 id=test></canvas> 47*c8dee2aaSAndroid Build Coastguard Worker <canvas width=600 height=600 id=report></canvas>`; 48*c8dee2aaSAndroid Build Coastguard Worker document.body.appendChild(container); 49*c8dee2aaSAndroid Build Coastguard Worker }); 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker afterEach(() => { 52*c8dee2aaSAndroid Build Coastguard Worker document.body.removeChild(container); 53*c8dee2aaSAndroid Build Coastguard Worker }); 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_basic', (canvas) => { 56*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 57*c8dee2aaSAndroid Build Coastguard Worker 58*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 59*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 60*c8dee2aaSAndroid Build Coastguard Worker 61*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 62*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 63*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 64*c8dee2aaSAndroid Build Coastguard Worker 65*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 200; 66*c8dee2aaSAndroid Build Coastguard Worker 67*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 68*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 69*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 70*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 71*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 72*c8dee2aaSAndroid Build Coastguard Worker }, 73*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Center, 74*c8dee2aaSAndroid Build Coastguard Worker maxLines: 8, 75*c8dee2aaSAndroid Build Coastguard Worker ellipsis: '.._.', 76*c8dee2aaSAndroid Build Coastguard Worker }); 77*c8dee2aaSAndroid Build Coastguard Worker 78*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 79*c8dee2aaSAndroid Build Coastguard Worker builder.addText('VAVAVAVAVAVAVA\nVAVA\n'); 80*c8dee2aaSAndroid Build Coastguard Worker 81*c8dee2aaSAndroid Build Coastguard Worker const blueText = new CanvasKit.TextStyle({ 82*c8dee2aaSAndroid Build Coastguard Worker backgroundColor: CanvasKit.Color(234, 208, 232), // light pink 83*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(48, 37, 199), 84*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 85*c8dee2aaSAndroid Build Coastguard Worker decoration: CanvasKit.LineThroughDecoration, 86*c8dee2aaSAndroid Build Coastguard Worker decorationThickness: 1.5, // multiplier based on font size 87*c8dee2aaSAndroid Build Coastguard Worker fontSize: 24, 88*c8dee2aaSAndroid Build Coastguard Worker }); 89*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(blueText); 90*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Gosh I hope this wraps at some point, it is such a long line.`) 91*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 92*c8dee2aaSAndroid Build Coastguard Worker builder.addText(` I'm done with the blue now. `) 93*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Now I hope we should stop before we get 8 lines tall. `); 94*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 95*c8dee2aaSAndroid Build Coastguard Worker 96*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 97*c8dee2aaSAndroid Build Coastguard Worker 98*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.didExceedMaxLines()).toBeTruthy(); 99*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getAlphabeticBaseline()).toBeCloseTo(21.377, 3); 100*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getHeight()).toEqual(240); 101*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getIdeographicBaseline()).toBeCloseTo(27.236, 3); 102*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getLongestLine()).toBeCloseTo(193.820, 3); 103*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getMaxIntrinsicWidth()).toBeCloseTo(1444.250, 3); 104*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getMaxWidth()).toEqual(200); 105*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getMinIntrinsicWidth()).toBeCloseTo(172.360, 3); 106*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getWordBoundary(8)).toEqual({ 107*c8dee2aaSAndroid Build Coastguard Worker start: 0, 108*c8dee2aaSAndroid Build Coastguard Worker end: 14, 109*c8dee2aaSAndroid Build Coastguard Worker }); 110*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getWordBoundary(25)).toEqual({ 111*c8dee2aaSAndroid Build Coastguard Worker start: 25, 112*c8dee2aaSAndroid Build Coastguard Worker end: 26, 113*c8dee2aaSAndroid Build Coastguard Worker }); 114*c8dee2aaSAndroid Build Coastguard Worker 115*c8dee2aaSAndroid Build Coastguard Worker 116*c8dee2aaSAndroid Build Coastguard Worker const lineMetrics = paragraph.getLineMetrics(); 117*c8dee2aaSAndroid Build Coastguard Worker expect(lineMetrics.length).toEqual(8); // 8 lines worth of metrics 118*c8dee2aaSAndroid Build Coastguard Worker const flm = lineMetrics[0]; // First Line Metric 119*c8dee2aaSAndroid Build Coastguard Worker expect(flm.startIndex).toEqual(0); 120*c8dee2aaSAndroid Build Coastguard Worker expect(flm.endExcludingWhitespaces).toEqual(14) 121*c8dee2aaSAndroid Build Coastguard Worker expect(flm.endIndex).toEqual(14); // Including whitespaces but excluding newlines 122*c8dee2aaSAndroid Build Coastguard Worker expect(flm.endIncludingNewline).toEqual(15); 123*c8dee2aaSAndroid Build Coastguard Worker expect(flm.lineNumber).toEqual(0); 124*c8dee2aaSAndroid Build Coastguard Worker expect(flm.isHardBreak).toEqual(true); 125*c8dee2aaSAndroid Build Coastguard Worker expect(flm.ascent).toBeCloseTo(21.377, 3); 126*c8dee2aaSAndroid Build Coastguard Worker expect(flm.descent).toBeCloseTo(5.859, 3); 127*c8dee2aaSAndroid Build Coastguard Worker expect(flm.height).toBeCloseTo(27.000, 3); 128*c8dee2aaSAndroid Build Coastguard Worker expect(flm.width).toBeCloseTo(172.360, 3); 129*c8dee2aaSAndroid Build Coastguard Worker expect(flm.left).toBeCloseTo(13.818, 3); 130*c8dee2aaSAndroid Build Coastguard Worker expect(flm.baseline).toBeCloseTo(21.141, 3); 131*c8dee2aaSAndroid Build Coastguard Worker 132*c8dee2aaSAndroid Build Coastguard Worker const singleLineMetrics = paragraph.getLineMetricsAt(0); 133*c8dee2aaSAndroid Build Coastguard Worker expect(singleLineMetrics.startIndex).toEqual(flm.startIndex); 134*c8dee2aaSAndroid Build Coastguard Worker expect(singleLineMetrics.lineNumber).toEqual(flm.lineNumber); 135*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getLineMetricsAt(9)).toBeFalsy(); 136*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getNumberOfLines()).toEqual(8); 137*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getLineNumberAt(9999)).toEqual(-1); 138*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getLineNumberAt(0)).toEqual(0); 139*c8dee2aaSAndroid Build Coastguard Worker 140*c8dee2aaSAndroid Build Coastguard Worker const glyphInfo = paragraph.getGlyphInfoAt(13); 141*c8dee2aaSAndroid Build Coastguard Worker expect(glyphInfo.graphemeClusterTextRange.start).toEqual(13); 142*c8dee2aaSAndroid Build Coastguard Worker expect(glyphInfo.graphemeClusterTextRange.end).toEqual(14); 143*c8dee2aaSAndroid Build Coastguard Worker expect(glyphInfo.dir).toEqual(CanvasKit.TextDirection.LTR); 144*c8dee2aaSAndroid Build Coastguard Worker expect(glyphInfo.isEllipsis).toEqual(false); 145*c8dee2aaSAndroid Build Coastguard Worker expect(glyphInfo.graphemeLayoutBounds[0]).toBeCloseTo(172.08, 3); 146*c8dee2aaSAndroid Build Coastguard Worker expect(glyphInfo.graphemeLayoutBounds[1]).toBeCloseTo(-0.24, 3); 147*c8dee2aaSAndroid Build Coastguard Worker expect(glyphInfo.graphemeLayoutBounds[2]).toBeCloseTo(186.18, 3); 148*c8dee2aaSAndroid Build Coastguard Worker expect(glyphInfo.graphemeLayoutBounds[3]).toBeCloseTo(27, 3); 149*c8dee2aaSAndroid Build Coastguard Worker 150*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getGlyphInfoAt(9999)).toBeFalsy(); 151*c8dee2aaSAndroid Build Coastguard Worker 152*c8dee2aaSAndroid Build Coastguard Worker // This should hit the last character on the first line. 153*c8dee2aaSAndroid Build Coastguard Worker const lastGlyphOnFirstLine = paragraph.getClosestGlyphInfoAtCoordinate(180, 21); 154*c8dee2aaSAndroid Build Coastguard Worker expect(lastGlyphOnFirstLine.graphemeClusterTextRange.start).toEqual(13); 155*c8dee2aaSAndroid Build Coastguard Worker expect(lastGlyphOnFirstLine.graphemeClusterTextRange.end).toEqual(14); 156*c8dee2aaSAndroid Build Coastguard Worker expect(lastGlyphOnFirstLine.dir).toEqual(CanvasKit.TextDirection.LTR); 157*c8dee2aaSAndroid Build Coastguard Worker expect(lastGlyphOnFirstLine.isEllipsis).toEqual(false); 158*c8dee2aaSAndroid Build Coastguard Worker expect(lastGlyphOnFirstLine.graphemeLayoutBounds[0]).toBeCloseTo(172.08, 3); 159*c8dee2aaSAndroid Build Coastguard Worker expect(lastGlyphOnFirstLine.graphemeLayoutBounds[1]).toBeCloseTo(-0.24, 3); 160*c8dee2aaSAndroid Build Coastguard Worker expect(lastGlyphOnFirstLine.graphemeLayoutBounds[2]).toBeCloseTo(186.18, 3); 161*c8dee2aaSAndroid Build Coastguard Worker expect(lastGlyphOnFirstLine.graphemeLayoutBounds[3]).toBeCloseTo(27, 3); 162*c8dee2aaSAndroid Build Coastguard Worker 163*c8dee2aaSAndroid Build Coastguard Worker const unresolvedGlyphs = paragraph.unresolvedCodepoints(); 164*c8dee2aaSAndroid Build Coastguard Worker expect(unresolvedGlyphs.length).toEqual(0, unresolvedGlyphs); 165*c8dee2aaSAndroid Build Coastguard Worker 166*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(10, 10, wrapTo+10, 230), paint); 167*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 168*c8dee2aaSAndroid Build Coastguard Worker 169*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 170*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 171*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 172*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 173*c8dee2aaSAndroid Build Coastguard Worker }); 174*c8dee2aaSAndroid Build Coastguard Worker 175*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_foreground_and_background_color', (canvas) => { 176*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 177*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 178*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 179*c8dee2aaSAndroid Build Coastguard Worker 180*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 200; 181*c8dee2aaSAndroid Build Coastguard Worker 182*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 183*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 184*c8dee2aaSAndroid Build Coastguard Worker foregroundColor: CanvasKit.Color4f(1.0, 0, 0, 0.8), 185*c8dee2aaSAndroid Build Coastguard Worker backgroundColor: CanvasKit.Color4f(0, 0, 1.0, 0.8), 186*c8dee2aaSAndroid Build Coastguard Worker // color should default to black 187*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 188*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 189*c8dee2aaSAndroid Build Coastguard Worker }, 190*c8dee2aaSAndroid Build Coastguard Worker 191*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Center, 192*c8dee2aaSAndroid Build Coastguard Worker }); 193*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 194*c8dee2aaSAndroid Build Coastguard Worker builder.addText( 195*c8dee2aaSAndroid Build Coastguard Worker 'This text has a red foregroundColor and a blue backgroundColor.'); 196*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 197*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(300); 198*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 199*c8dee2aaSAndroid Build Coastguard Worker 200*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 201*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 202*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 203*c8dee2aaSAndroid Build Coastguard Worker }); 204*c8dee2aaSAndroid Build Coastguard Worker 205*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_foreground_stroke_paint', (canvas) => { 206*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 207*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 208*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 209*c8dee2aaSAndroid Build Coastguard Worker 210*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 200; 211*c8dee2aaSAndroid Build Coastguard Worker 212*c8dee2aaSAndroid Build Coastguard Worker const textStyle = { 213*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 214*c8dee2aaSAndroid Build Coastguard Worker fontSize: 40, 215*c8dee2aaSAndroid Build Coastguard Worker }; 216*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 217*c8dee2aaSAndroid Build Coastguard Worker textStyle: textStyle, 218*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Center, 219*c8dee2aaSAndroid Build Coastguard Worker }); 220*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 221*c8dee2aaSAndroid Build Coastguard Worker 222*c8dee2aaSAndroid Build Coastguard Worker const fg = new CanvasKit.Paint(); 223*c8dee2aaSAndroid Build Coastguard Worker fg.setColor(CanvasKit.BLACK); 224*c8dee2aaSAndroid Build Coastguard Worker fg.setStyle(CanvasKit.PaintStyle.Stroke); 225*c8dee2aaSAndroid Build Coastguard Worker 226*c8dee2aaSAndroid Build Coastguard Worker const bg = new CanvasKit.Paint(); 227*c8dee2aaSAndroid Build Coastguard Worker bg.setColor(CanvasKit.TRANSPARENT); 228*c8dee2aaSAndroid Build Coastguard Worker 229*c8dee2aaSAndroid Build Coastguard Worker builder.pushPaintStyle(textStyle, fg, bg); 230*c8dee2aaSAndroid Build Coastguard Worker builder.addText( 231*c8dee2aaSAndroid Build Coastguard Worker 'This text is stroked in black and has no fill'); 232*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 233*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(300); 234*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 235*c8dee2aaSAndroid Build Coastguard Worker // Again 5px to the right so you can tell the fill is transparent 236*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 15, 10); 237*c8dee2aaSAndroid Build Coastguard Worker 238*c8dee2aaSAndroid Build Coastguard Worker fg.delete(); 239*c8dee2aaSAndroid Build Coastguard Worker bg.delete(); 240*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 241*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 242*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 243*c8dee2aaSAndroid Build Coastguard Worker }); 244*c8dee2aaSAndroid Build Coastguard Worker 245*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_letter_word_spacing', (canvas) => { 246*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 247*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 248*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 249*c8dee2aaSAndroid Build Coastguard Worker 250*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 200; 251*c8dee2aaSAndroid Build Coastguard Worker 252*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 253*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 254*c8dee2aaSAndroid Build Coastguard Worker // color should default to black 255*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 256*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 257*c8dee2aaSAndroid Build Coastguard Worker letterSpacing: 5, 258*c8dee2aaSAndroid Build Coastguard Worker wordSpacing: 10, 259*c8dee2aaSAndroid Build Coastguard Worker }, 260*c8dee2aaSAndroid Build Coastguard Worker 261*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Center, 262*c8dee2aaSAndroid Build Coastguard Worker }); 263*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 264*c8dee2aaSAndroid Build Coastguard Worker builder.addText( 265*c8dee2aaSAndroid Build Coastguard Worker 'This text should have a lot of space between the letters and words.'); 266*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 267*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(300); 268*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 269*c8dee2aaSAndroid Build Coastguard Worker 270*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 271*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 272*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 273*c8dee2aaSAndroid Build Coastguard Worker }); 274*c8dee2aaSAndroid Build Coastguard Worker 275*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_shadows', (canvas) => { 276*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 277*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 278*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 279*c8dee2aaSAndroid Build Coastguard Worker 280*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 200; 281*c8dee2aaSAndroid Build Coastguard Worker 282*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 283*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 284*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.WHITE, 285*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 286*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 287*c8dee2aaSAndroid Build Coastguard Worker shadows: [{color: CanvasKit.BLACK, blurRadius: 15}, 288*c8dee2aaSAndroid Build Coastguard Worker {color: CanvasKit.RED, blurRadius: 5, offset: [10, 10]}], 289*c8dee2aaSAndroid Build Coastguard Worker }, 290*c8dee2aaSAndroid Build Coastguard Worker 291*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Center, 292*c8dee2aaSAndroid Build Coastguard Worker }); 293*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 294*c8dee2aaSAndroid Build Coastguard Worker builder.addText('This text should have a shadow behind it.'); 295*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 296*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(300); 297*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 298*c8dee2aaSAndroid Build Coastguard Worker 299*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 300*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 301*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 302*c8dee2aaSAndroid Build Coastguard Worker }); 303*c8dee2aaSAndroid Build Coastguard Worker 304*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_strut_style', (canvas) => { 305*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(robotoFontBuffer); 306*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 307*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Roboto'); 308*c8dee2aaSAndroid Build Coastguard Worker 309*c8dee2aaSAndroid Build Coastguard Worker // The lines in this paragraph should have the same height despite the third 310*c8dee2aaSAndroid Build Coastguard Worker // line having a larger font size. 311*c8dee2aaSAndroid Build Coastguard Worker const paraStrutStyle = new CanvasKit.ParagraphStyle({ 312*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 313*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 314*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 315*c8dee2aaSAndroid Build Coastguard Worker }, 316*c8dee2aaSAndroid Build Coastguard Worker strutStyle: { 317*c8dee2aaSAndroid Build Coastguard Worker strutEnabled: true, 318*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 319*c8dee2aaSAndroid Build Coastguard Worker fontSize: 28, 320*c8dee2aaSAndroid Build Coastguard Worker heightMultiplier: 1.5, 321*c8dee2aaSAndroid Build Coastguard Worker forceStrutHeight: true, 322*c8dee2aaSAndroid Build Coastguard Worker }, 323*c8dee2aaSAndroid Build Coastguard Worker }); 324*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 325*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 326*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 327*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 328*c8dee2aaSAndroid Build Coastguard Worker }, 329*c8dee2aaSAndroid Build Coastguard Worker }); 330*c8dee2aaSAndroid Build Coastguard Worker const roboto28Style = new CanvasKit.TextStyle({ 331*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 332*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 333*c8dee2aaSAndroid Build Coastguard Worker fontSize: 28, 334*c8dee2aaSAndroid Build Coastguard Worker }); 335*c8dee2aaSAndroid Build Coastguard Worker const roboto32Style = new CanvasKit.TextStyle({ 336*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 337*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 338*c8dee2aaSAndroid Build Coastguard Worker fontSize: 32, 339*c8dee2aaSAndroid Build Coastguard Worker }); 340*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStrutStyle, fontMgr); 341*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(roboto28Style); 342*c8dee2aaSAndroid Build Coastguard Worker builder.addText('This paragraph\n'); 343*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(roboto32Style); 344*c8dee2aaSAndroid Build Coastguard Worker builder.addText('is using\n'); 345*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 346*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(roboto28Style); 347*c8dee2aaSAndroid Build Coastguard Worker builder.addText('a strut style!\n'); 348*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 349*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 350*c8dee2aaSAndroid Build Coastguard Worker 351*c8dee2aaSAndroid Build Coastguard Worker const builder2 = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 352*c8dee2aaSAndroid Build Coastguard Worker builder2.pushStyle(roboto28Style); 353*c8dee2aaSAndroid Build Coastguard Worker builder2.addText('This paragraph\n'); 354*c8dee2aaSAndroid Build Coastguard Worker builder2.pushStyle(roboto32Style); 355*c8dee2aaSAndroid Build Coastguard Worker builder2.addText('is not using\n'); 356*c8dee2aaSAndroid Build Coastguard Worker builder2.pop(); 357*c8dee2aaSAndroid Build Coastguard Worker builder2.pushStyle(roboto28Style); 358*c8dee2aaSAndroid Build Coastguard Worker builder2.addText('a strut style!\n'); 359*c8dee2aaSAndroid Build Coastguard Worker builder2.pop(); 360*c8dee2aaSAndroid Build Coastguard Worker builder2.pop(); 361*c8dee2aaSAndroid Build Coastguard Worker 362*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 363*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(300); 364*c8dee2aaSAndroid Build Coastguard Worker 365*c8dee2aaSAndroid Build Coastguard Worker const paragraph2 = builder2.build(); 366*c8dee2aaSAndroid Build Coastguard Worker paragraph2.layout(300); 367*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 368*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph2, 220, 10); 369*c8dee2aaSAndroid Build Coastguard Worker 370*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 371*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 372*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 373*c8dee2aaSAndroid Build Coastguard Worker }); 374*c8dee2aaSAndroid Build Coastguard Worker 375*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_font_features', (canvas) => { 376*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(robotoFontBuffer); 377*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 378*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Roboto'); 379*c8dee2aaSAndroid Build Coastguard Worker 380*c8dee2aaSAndroid Build Coastguard Worker 381*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 382*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 383*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 384*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 385*c8dee2aaSAndroid Build Coastguard Worker fontSize: 30, 386*c8dee2aaSAndroid Build Coastguard Worker fontFeatures: [{name: 'smcp', value: 1}] 387*c8dee2aaSAndroid Build Coastguard Worker }, 388*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Center, 389*c8dee2aaSAndroid Build Coastguard Worker }); 390*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 391*c8dee2aaSAndroid Build Coastguard Worker builder.addText('This Text Should Be In Small Caps'); 392*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 393*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(300); 394*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 395*c8dee2aaSAndroid Build Coastguard Worker 396*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 397*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 398*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 399*c8dee2aaSAndroid Build Coastguard Worker }); 400*c8dee2aaSAndroid Build Coastguard Worker 401*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_font_variations', (canvas) => { 402*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(robotoVariableFontBuffer); 403*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 404*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Roboto Slab'); 405*c8dee2aaSAndroid Build Coastguard Worker 406*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 407*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 408*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 409*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto Slab'], 410*c8dee2aaSAndroid Build Coastguard Worker fontSize: 30, 411*c8dee2aaSAndroid Build Coastguard Worker }, 412*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Center, 413*c8dee2aaSAndroid Build Coastguard Worker }); 414*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 415*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Normal\n'); 416*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(new CanvasKit.TextStyle({ 417*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto Slab'], 418*c8dee2aaSAndroid Build Coastguard Worker fontSize: 30, 419*c8dee2aaSAndroid Build Coastguard Worker fontVariations: [{axis: 'wght', value: 900}] 420*c8dee2aaSAndroid Build Coastguard Worker })); 421*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Heavy Weight\n'); 422*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(new CanvasKit.TextStyle({ 423*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto Slab'], 424*c8dee2aaSAndroid Build Coastguard Worker fontSize: 30, 425*c8dee2aaSAndroid Build Coastguard Worker fontVariations: [{axis: 'wght', value: 100}] 426*c8dee2aaSAndroid Build Coastguard Worker })); 427*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Light Weight\n'); 428*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 429*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 430*c8dee2aaSAndroid Build Coastguard Worker 431*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 432*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(300); 433*c8dee2aaSAndroid Build Coastguard Worker 434*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 435*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 436*c8dee2aaSAndroid Build Coastguard Worker 437*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 438*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 439*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 440*c8dee2aaSAndroid Build Coastguard Worker }); 441*c8dee2aaSAndroid Build Coastguard Worker 442*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_placeholders', (canvas) => { 443*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(robotoFontBuffer); 444*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 445*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Roboto'); 446*c8dee2aaSAndroid Build Coastguard Worker 447*c8dee2aaSAndroid Build Coastguard Worker 448*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 449*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 450*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 451*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 452*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 453*c8dee2aaSAndroid Build Coastguard Worker }, 454*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Center, 455*c8dee2aaSAndroid Build Coastguard Worker }); 456*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 457*c8dee2aaSAndroid Build Coastguard Worker builder.addText('There should be '); 458*c8dee2aaSAndroid Build Coastguard Worker builder.addPlaceholder(10, 10, CanvasKit.PlaceholderAlignment.AboveBaseline, 459*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.TextBaseline.Ideographic); 460*c8dee2aaSAndroid Build Coastguard Worker builder.addText('a space in this sentence.\n'); 461*c8dee2aaSAndroid Build Coastguard Worker 462*c8dee2aaSAndroid Build Coastguard Worker builder.addText('There should be '); 463*c8dee2aaSAndroid Build Coastguard Worker builder.addPlaceholder(10, 10, CanvasKit.PlaceholderAlignment.BelowBaseline, 464*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.TextBaseline.Ideographic); 465*c8dee2aaSAndroid Build Coastguard Worker builder.addText('a dropped space in this sentence.\n'); 466*c8dee2aaSAndroid Build Coastguard Worker 467*c8dee2aaSAndroid Build Coastguard Worker builder.addText('There should be '); 468*c8dee2aaSAndroid Build Coastguard Worker builder.addPlaceholder(10, 10, null, null, 20); 469*c8dee2aaSAndroid Build Coastguard Worker builder.addText('an offset space in this sentence.\n'); 470*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 471*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(300); 472*c8dee2aaSAndroid Build Coastguard Worker 473*c8dee2aaSAndroid Build Coastguard Worker let rects = paragraph.getRectsForPlaceholders(); 474*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 475*c8dee2aaSAndroid Build Coastguard Worker 476*c8dee2aaSAndroid Build Coastguard Worker for (const r of rects) { 477*c8dee2aaSAndroid Build Coastguard Worker const p = new CanvasKit.Paint(); 478*c8dee2aaSAndroid Build Coastguard Worker p.setColor(CanvasKit.Color(0, 0, 255)); 479*c8dee2aaSAndroid Build Coastguard Worker p.setStyle(CanvasKit.PaintStyle.Stroke); 480*c8dee2aaSAndroid Build Coastguard Worker // Account for the (10, 10) offset when we painted the paragraph. 481*c8dee2aaSAndroid Build Coastguard Worker const rect = r.rect; 482*c8dee2aaSAndroid Build Coastguard Worker expect(r.dir).toEqual(CanvasKit.TextDirection.LTR); 483*c8dee2aaSAndroid Build Coastguard Worker const placeholder = 484*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.LTRBRect(rect[0]+10,rect[1]+10,rect[2]+10,rect[3]+10); 485*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(placeholder, p); 486*c8dee2aaSAndroid Build Coastguard Worker p.delete(); 487*c8dee2aaSAndroid Build Coastguard Worker } 488*c8dee2aaSAndroid Build Coastguard Worker 489*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 490*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 491*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 492*c8dee2aaSAndroid Build Coastguard Worker }); 493*c8dee2aaSAndroid Build Coastguard Worker 494*c8dee2aaSAndroid Build Coastguard Worker // loosely based on SkParagraph_GetRectsForRangeParagraph test in c++ code. 495*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_rects', (canvas) => { 496*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 497*c8dee2aaSAndroid Build Coastguard Worker 498*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 550; 499*c8dee2aaSAndroid Build Coastguard Worker const hStyle = CanvasKit.RectHeightStyle.Max; 500*c8dee2aaSAndroid Build Coastguard Worker const wStyle = CanvasKit.RectWidthStyle.Tight; 501*c8dee2aaSAndroid Build Coastguard Worker 502*c8dee2aaSAndroid Build Coastguard Worker const mallocedColor = CanvasKit.Malloc(Float32Array, 4); 503*c8dee2aaSAndroid Build Coastguard Worker mallocedColor.toTypedArray().set([0.9, 0.1, 0.1, 1.0]); 504*c8dee2aaSAndroid Build Coastguard Worker 505*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 506*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 507*c8dee2aaSAndroid Build Coastguard Worker color: mallocedColor, 508*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 509*c8dee2aaSAndroid Build Coastguard Worker fontSize: 50, 510*c8dee2aaSAndroid Build Coastguard Worker }, 511*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 512*c8dee2aaSAndroid Build Coastguard Worker maxLines: 10, 513*c8dee2aaSAndroid Build Coastguard Worker }); 514*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 515*c8dee2aaSAndroid Build Coastguard Worker builder.addText('12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345'); 516*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 517*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.Free(mallocedColor); 518*c8dee2aaSAndroid Build Coastguard Worker 519*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 520*c8dee2aaSAndroid Build Coastguard Worker 521*c8dee2aaSAndroid Build Coastguard Worker const ranges = [ 522*c8dee2aaSAndroid Build Coastguard Worker { 523*c8dee2aaSAndroid Build Coastguard Worker start: 0, 524*c8dee2aaSAndroid Build Coastguard Worker end: 0, 525*c8dee2aaSAndroid Build Coastguard Worker expectedNum: 0, 526*c8dee2aaSAndroid Build Coastguard Worker }, 527*c8dee2aaSAndroid Build Coastguard Worker { 528*c8dee2aaSAndroid Build Coastguard Worker start: 0, 529*c8dee2aaSAndroid Build Coastguard Worker end: 1, 530*c8dee2aaSAndroid Build Coastguard Worker expectedNum: 1, 531*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(200, 0, 200), 532*c8dee2aaSAndroid Build Coastguard Worker }, 533*c8dee2aaSAndroid Build Coastguard Worker { 534*c8dee2aaSAndroid Build Coastguard Worker start: 2, 535*c8dee2aaSAndroid Build Coastguard Worker end: 8, 536*c8dee2aaSAndroid Build Coastguard Worker expectedNum: 1, 537*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(255, 0, 0), 538*c8dee2aaSAndroid Build Coastguard Worker }, 539*c8dee2aaSAndroid Build Coastguard Worker { 540*c8dee2aaSAndroid Build Coastguard Worker start: 8, 541*c8dee2aaSAndroid Build Coastguard Worker end: 21, 542*c8dee2aaSAndroid Build Coastguard Worker expectedNum: 1, 543*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(0, 255, 0), 544*c8dee2aaSAndroid Build Coastguard Worker }, 545*c8dee2aaSAndroid Build Coastguard Worker { 546*c8dee2aaSAndroid Build Coastguard Worker start: 30, 547*c8dee2aaSAndroid Build Coastguard Worker end: 100, 548*c8dee2aaSAndroid Build Coastguard Worker expectedNum: 4, 549*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(0, 0, 255), 550*c8dee2aaSAndroid Build Coastguard Worker }, 551*c8dee2aaSAndroid Build Coastguard Worker { 552*c8dee2aaSAndroid Build Coastguard Worker start: 19, 553*c8dee2aaSAndroid Build Coastguard Worker end: 22, 554*c8dee2aaSAndroid Build Coastguard Worker expectedNum: 1, 555*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(0, 200, 200), 556*c8dee2aaSAndroid Build Coastguard Worker } 557*c8dee2aaSAndroid Build Coastguard Worker ]; 558*c8dee2aaSAndroid Build Coastguard Worker // Move it down a bit so we can see the rects that go above 0,0 559*c8dee2aaSAndroid Build Coastguard Worker canvas.translate(10, 10); 560*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 0, 0); 561*c8dee2aaSAndroid Build Coastguard Worker 562*c8dee2aaSAndroid Build Coastguard Worker for (const test of ranges) { 563*c8dee2aaSAndroid Build Coastguard Worker let rects = paragraph.getRectsForRange(test.start, test.end, hStyle, wStyle); 564*c8dee2aaSAndroid Build Coastguard Worker expect(Array.isArray(rects)).toEqual(true); 565*c8dee2aaSAndroid Build Coastguard Worker expect(rects.length).toEqual(test.expectedNum); 566*c8dee2aaSAndroid Build Coastguard Worker 567*c8dee2aaSAndroid Build Coastguard Worker for (const r of rects) { 568*c8dee2aaSAndroid Build Coastguard Worker expect(r.dir).toEqual(CanvasKit.TextDirection.LTR); 569*c8dee2aaSAndroid Build Coastguard Worker const p = new CanvasKit.Paint(); 570*c8dee2aaSAndroid Build Coastguard Worker p.setColor(test.color); 571*c8dee2aaSAndroid Build Coastguard Worker p.setStyle(CanvasKit.PaintStyle.Stroke); 572*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(r.rect, p); 573*c8dee2aaSAndroid Build Coastguard Worker p.delete(); 574*c8dee2aaSAndroid Build Coastguard Worker } 575*c8dee2aaSAndroid Build Coastguard Worker } 576*c8dee2aaSAndroid Build Coastguard Worker expect(CanvasKit.RectHeightStyle.Strut).toBeTruthy(); 577*c8dee2aaSAndroid Build Coastguard Worker 578*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 579*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 580*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 581*c8dee2aaSAndroid Build Coastguard Worker }); 582*c8dee2aaSAndroid Build Coastguard Worker 583*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_emoji', (canvas) => { 584*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData([notoSerifFontBuffer, emojiFontBuffer]); 585*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(2); 586*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 587*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(1)).toEqual('Noto Color Emoji'); 588*c8dee2aaSAndroid Build Coastguard Worker 589*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 450; 590*c8dee2aaSAndroid Build Coastguard Worker 591*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 592*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 593*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 594*c8dee2aaSAndroid Build Coastguard Worker // Put text first, otherwise the "emoji space" is used and that looks bad. 595*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif', 'Noto Color Emoji'], 596*c8dee2aaSAndroid Build Coastguard Worker fontSize: 30, 597*c8dee2aaSAndroid Build Coastguard Worker }, 598*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 599*c8dee2aaSAndroid Build Coastguard Worker maxLines: 10, 600*c8dee2aaSAndroid Build Coastguard Worker }); 601*c8dee2aaSAndroid Build Coastguard Worker 602*c8dee2aaSAndroid Build Coastguard Worker const textStyle = new CanvasKit.TextStyle({ 603*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 604*c8dee2aaSAndroid Build Coastguard Worker // The number 4 matches an emoji and looks strange w/o this additional style. 605*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 606*c8dee2aaSAndroid Build Coastguard Worker fontSize: 30, 607*c8dee2aaSAndroid Build Coastguard Worker }); 608*c8dee2aaSAndroid Build Coastguard Worker 609*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 610*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(textStyle); 611*c8dee2aaSAndroid Build Coastguard Worker builder.addText('4 flags on following line:\n'); 612*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 613*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`️ \n`); 614*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Rainbow Italy Liberia USA\n\n'); 615*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Emoji below should wrap:\n'); 616*c8dee2aaSAndroid Build Coastguard Worker builder.addText(``); 617*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 618*c8dee2aaSAndroid Build Coastguard Worker 619*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 620*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 621*c8dee2aaSAndroid Build Coastguard Worker 622*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 623*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 624*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 625*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(10, 10, wrapTo+10, wrapTo+10), paint); 626*c8dee2aaSAndroid Build Coastguard Worker 627*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 628*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 629*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 630*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 631*c8dee2aaSAndroid Build Coastguard Worker }); 632*c8dee2aaSAndroid Build Coastguard Worker 633*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_hits', (canvas) => { 634*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData([notoSerifFontBuffer]); 635*c8dee2aaSAndroid Build Coastguard Worker 636*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 300; 637*c8dee2aaSAndroid Build Coastguard Worker 638*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 639*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 640*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 641*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 642*c8dee2aaSAndroid Build Coastguard Worker fontSize: 50, 643*c8dee2aaSAndroid Build Coastguard Worker }, 644*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 645*c8dee2aaSAndroid Build Coastguard Worker maxLines: 10, 646*c8dee2aaSAndroid Build Coastguard Worker }); 647*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 648*c8dee2aaSAndroid Build Coastguard Worker builder.addText('UNCOPYRIGHTABLE'); 649*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 650*c8dee2aaSAndroid Build Coastguard Worker 651*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 652*c8dee2aaSAndroid Build Coastguard Worker canvas.translate(10, 10); 653*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 0, 0); 654*c8dee2aaSAndroid Build Coastguard Worker 655*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 656*c8dee2aaSAndroid Build Coastguard Worker 657*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.Color(255, 0, 0)); 658*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Fill); 659*c8dee2aaSAndroid Build Coastguard Worker canvas.drawCircle(20, 30, 3, paint); 660*c8dee2aaSAndroid Build Coastguard Worker 661*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.Color(0, 0, 255)); 662*c8dee2aaSAndroid Build Coastguard Worker canvas.drawCircle(80, 90, 3, paint); 663*c8dee2aaSAndroid Build Coastguard Worker 664*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.Color(0, 255, 0)); 665*c8dee2aaSAndroid Build Coastguard Worker canvas.drawCircle(280, 2, 3, paint); 666*c8dee2aaSAndroid Build Coastguard Worker 667*c8dee2aaSAndroid Build Coastguard Worker let posU = paragraph.getGlyphPositionAtCoordinate(20, 30); 668*c8dee2aaSAndroid Build Coastguard Worker expect(posU).toEqual({ 669*c8dee2aaSAndroid Build Coastguard Worker pos: 1, 670*c8dee2aaSAndroid Build Coastguard Worker affinity: CanvasKit.Affinity.Upstream 671*c8dee2aaSAndroid Build Coastguard Worker }); 672*c8dee2aaSAndroid Build Coastguard Worker let posA = paragraph.getGlyphPositionAtCoordinate(80, 90); 673*c8dee2aaSAndroid Build Coastguard Worker expect(posA).toEqual({ 674*c8dee2aaSAndroid Build Coastguard Worker pos: 11, 675*c8dee2aaSAndroid Build Coastguard Worker affinity: CanvasKit.Affinity.Downstream 676*c8dee2aaSAndroid Build Coastguard Worker }); 677*c8dee2aaSAndroid Build Coastguard Worker let posG = paragraph.getGlyphPositionAtCoordinate(280, 2); 678*c8dee2aaSAndroid Build Coastguard Worker expect(posG).toEqual({ 679*c8dee2aaSAndroid Build Coastguard Worker pos: 9, 680*c8dee2aaSAndroid Build Coastguard Worker affinity: CanvasKit.Affinity.Upstream 681*c8dee2aaSAndroid Build Coastguard Worker }); 682*c8dee2aaSAndroid Build Coastguard Worker 683*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 684*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 685*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 686*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 687*c8dee2aaSAndroid Build Coastguard Worker }); 688*c8dee2aaSAndroid Build Coastguard Worker 689*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_styles', (canvas) => { 690*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 691*c8dee2aaSAndroid Build Coastguard Worker 692*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 693*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 694*c8dee2aaSAndroid Build Coastguard Worker 695*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer, notoSerifBoldItalicFontBuffer); 696*c8dee2aaSAndroid Build Coastguard Worker 697*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 698*c8dee2aaSAndroid Build Coastguard Worker 699*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 700*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 701*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 702*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 703*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 704*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Light, 705*c8dee2aaSAndroid Build Coastguard Worker } 706*c8dee2aaSAndroid Build Coastguard Worker }, 707*c8dee2aaSAndroid Build Coastguard Worker textDirection: CanvasKit.TextDirection.RTL, 708*c8dee2aaSAndroid Build Coastguard Worker disableHinting: true, 709*c8dee2aaSAndroid Build Coastguard Worker }); 710*c8dee2aaSAndroid Build Coastguard Worker 711*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 712*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Default text\n'); 713*c8dee2aaSAndroid Build Coastguard Worker 714*c8dee2aaSAndroid Build Coastguard Worker const boldItalic = new CanvasKit.TextStyle({ 715*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.RED, 716*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 717*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 718*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 719*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Bold, 720*c8dee2aaSAndroid Build Coastguard Worker width: CanvasKit.FontWidth.Expanded, 721*c8dee2aaSAndroid Build Coastguard Worker slant: CanvasKit.FontSlant.Italic, 722*c8dee2aaSAndroid Build Coastguard Worker } 723*c8dee2aaSAndroid Build Coastguard Worker }); 724*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(boldItalic); 725*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Bold, Expanded, Italic\n`); 726*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 727*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`back to normal`); 728*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 729*c8dee2aaSAndroid Build Coastguard Worker 730*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 731*c8dee2aaSAndroid Build Coastguard Worker 732*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(10, 10, wrapTo+10, wrapTo+10), paint); 733*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 734*c8dee2aaSAndroid Build Coastguard Worker 735*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 736*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 737*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 738*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 739*c8dee2aaSAndroid Build Coastguard Worker }); 740*c8dee2aaSAndroid Build Coastguard Worker 741*c8dee2aaSAndroid Build Coastguard Worker it('paragraph_rounding_hack', () => { 742*c8dee2aaSAndroid Build Coastguard Worker const paraStyleDefault = new CanvasKit.ParagraphStyle({ 743*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 744*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 745*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 746*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 747*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Light, 748*c8dee2aaSAndroid Build Coastguard Worker } 749*c8dee2aaSAndroid Build Coastguard Worker }, 750*c8dee2aaSAndroid Build Coastguard Worker textDirection: CanvasKit.TextDirection.RTL, 751*c8dee2aaSAndroid Build Coastguard Worker disableHinting: true, 752*c8dee2aaSAndroid Build Coastguard Worker }); 753*c8dee2aaSAndroid Build Coastguard Worker expect(paraStyleDefault.applyRoundingHack).toEqual(true); 754*c8dee2aaSAndroid Build Coastguard Worker 755*c8dee2aaSAndroid Build Coastguard Worker const paraStyleOverride = new CanvasKit.ParagraphStyle({ 756*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 757*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 758*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 759*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 760*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Light, 761*c8dee2aaSAndroid Build Coastguard Worker } 762*c8dee2aaSAndroid Build Coastguard Worker }, 763*c8dee2aaSAndroid Build Coastguard Worker textDirection: CanvasKit.TextDirection.RTL, 764*c8dee2aaSAndroid Build Coastguard Worker disableHinting: true, 765*c8dee2aaSAndroid Build Coastguard Worker applyRoundingHack: false, 766*c8dee2aaSAndroid Build Coastguard Worker }); 767*c8dee2aaSAndroid Build Coastguard Worker expect(paraStyleOverride.applyRoundingHack).toEqual(false); 768*c8dee2aaSAndroid Build Coastguard Worker }); 769*c8dee2aaSAndroid Build Coastguard Worker 770*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_font_provider', (canvas) => { 771*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 772*c8dee2aaSAndroid Build Coastguard Worker 773*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 774*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 775*c8dee2aaSAndroid Build Coastguard Worker 776*c8dee2aaSAndroid Build Coastguard Worker // Register Noto Serif as 'sans-serif'. 777*c8dee2aaSAndroid Build Coastguard Worker const fontSrc = CanvasKit.TypefaceFontProvider.Make(); 778*c8dee2aaSAndroid Build Coastguard Worker fontSrc.registerFont(notoSerifFontBuffer, 'sans-serif'); 779*c8dee2aaSAndroid Build Coastguard Worker fontSrc.registerFont(notoSerifBoldItalicFontBuffer, 'sans-serif'); 780*c8dee2aaSAndroid Build Coastguard Worker 781*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 782*c8dee2aaSAndroid Build Coastguard Worker 783*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 784*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 785*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['sans-serif'], 786*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 787*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 788*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Light, 789*c8dee2aaSAndroid Build Coastguard Worker } 790*c8dee2aaSAndroid Build Coastguard Worker }, 791*c8dee2aaSAndroid Build Coastguard Worker textDirection: CanvasKit.TextDirection.RTL, 792*c8dee2aaSAndroid Build Coastguard Worker disableHinting: true, 793*c8dee2aaSAndroid Build Coastguard Worker }); 794*c8dee2aaSAndroid Build Coastguard Worker 795*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.MakeFromFontProvider(paraStyle, fontSrc); 796*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Default text\n'); 797*c8dee2aaSAndroid Build Coastguard Worker 798*c8dee2aaSAndroid Build Coastguard Worker const boldItalic = new CanvasKit.TextStyle({ 799*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.RED, 800*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['sans-serif'], 801*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 802*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 803*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Bold, 804*c8dee2aaSAndroid Build Coastguard Worker width: CanvasKit.FontWidth.Expanded, 805*c8dee2aaSAndroid Build Coastguard Worker slant: CanvasKit.FontSlant.Italic, 806*c8dee2aaSAndroid Build Coastguard Worker } 807*c8dee2aaSAndroid Build Coastguard Worker }); 808*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(boldItalic); 809*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Bold, Expanded, Italic\n`); 810*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 811*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`back to normal`); 812*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 813*c8dee2aaSAndroid Build Coastguard Worker 814*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 815*c8dee2aaSAndroid Build Coastguard Worker 816*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(10, 10, wrapTo+10, wrapTo+10), paint); 817*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 818*c8dee2aaSAndroid Build Coastguard Worker 819*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 820*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 821*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 822*c8dee2aaSAndroid Build Coastguard Worker fontSrc.delete(); 823*c8dee2aaSAndroid Build Coastguard Worker }); 824*c8dee2aaSAndroid Build Coastguard Worker 825*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_font_collection', (canvas) => { 826*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 827*c8dee2aaSAndroid Build Coastguard Worker 828*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 829*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 830*c8dee2aaSAndroid Build Coastguard Worker 831*c8dee2aaSAndroid Build Coastguard Worker // Register Noto Serif as 'sans-serif'. 832*c8dee2aaSAndroid Build Coastguard Worker const fontSrc = CanvasKit.TypefaceFontProvider.Make(); 833*c8dee2aaSAndroid Build Coastguard Worker fontSrc.registerFont(notoSerifFontBuffer, 'sans-serif'); 834*c8dee2aaSAndroid Build Coastguard Worker const fontCollection = CanvasKit.FontCollection.Make(); 835*c8dee2aaSAndroid Build Coastguard Worker fontCollection.setDefaultFontManager(fontSrc); 836*c8dee2aaSAndroid Build Coastguard Worker 837*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 838*c8dee2aaSAndroid Build Coastguard Worker 839*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 840*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 841*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['sans-serif'], 842*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 843*c8dee2aaSAndroid Build Coastguard Worker }, 844*c8dee2aaSAndroid Build Coastguard Worker disableHinting: true, 845*c8dee2aaSAndroid Build Coastguard Worker }); 846*c8dee2aaSAndroid Build Coastguard Worker 847*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.MakeFromFontCollection( 848*c8dee2aaSAndroid Build Coastguard Worker paraStyle, fontCollection); 849*c8dee2aaSAndroid Build Coastguard Worker builder.addText('ABC DEF GHI'); 850*c8dee2aaSAndroid Build Coastguard Worker 851*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 852*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 853*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 854*c8dee2aaSAndroid Build Coastguard Worker 855*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 856*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 857*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 858*c8dee2aaSAndroid Build Coastguard Worker fontSrc.delete(); 859*c8dee2aaSAndroid Build Coastguard Worker }); 860*c8dee2aaSAndroid Build Coastguard Worker 861*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_text_styles', (canvas) => { 862*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 863*c8dee2aaSAndroid Build Coastguard Worker 864*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.GREEN); 865*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 866*c8dee2aaSAndroid Build Coastguard Worker 867*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 868*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 869*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 870*c8dee2aaSAndroid Build Coastguard Worker 871*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 200; 872*c8dee2aaSAndroid Build Coastguard Worker 873*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 874*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 875*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 876*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 877*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 878*c8dee2aaSAndroid Build Coastguard Worker decoration: CanvasKit.UnderlineDecoration, 879*c8dee2aaSAndroid Build Coastguard Worker decorationThickness: 1.5, // multiplier based on font size 880*c8dee2aaSAndroid Build Coastguard Worker decorationStyle: CanvasKit.DecorationStyle.Wavy, 881*c8dee2aaSAndroid Build Coastguard Worker }, 882*c8dee2aaSAndroid Build Coastguard Worker }); 883*c8dee2aaSAndroid Build Coastguard Worker 884*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 885*c8dee2aaSAndroid Build Coastguard Worker builder.addText('VAVAVAVAVAVAVA\nVAVA\n'); 886*c8dee2aaSAndroid Build Coastguard Worker 887*c8dee2aaSAndroid Build Coastguard Worker const blueText = new CanvasKit.TextStyle({ 888*c8dee2aaSAndroid Build Coastguard Worker backgroundColor: CanvasKit.Color(234, 208, 232), // light pink 889*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(48, 37, 199), 890*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 891*c8dee2aaSAndroid Build Coastguard Worker textBaseline: CanvasKit.TextBaseline.Ideographic, 892*c8dee2aaSAndroid Build Coastguard Worker decoration: CanvasKit.LineThroughDecoration, 893*c8dee2aaSAndroid Build Coastguard Worker decorationThickness: 1.5, // multiplier based on font size 894*c8dee2aaSAndroid Build Coastguard Worker }); 895*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(blueText); 896*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Gosh I hope this wraps at some point, it is such a long line.`); 897*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 898*c8dee2aaSAndroid Build Coastguard Worker builder.addText(` I'm done with the blue now. `); 899*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Now I hope we should stop before we get 8 lines tall. `); 900*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 901*c8dee2aaSAndroid Build Coastguard Worker 902*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 903*c8dee2aaSAndroid Build Coastguard Worker 904*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getAlphabeticBaseline()).toBeCloseTo(21.377, 3); 905*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getHeight()).toEqual(227); 906*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getIdeographicBaseline()).toBeCloseTo(27.236, 3); 907*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getLongestLine()).toBeCloseTo(195.664, 3); 908*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getMaxIntrinsicWidth()).toBeCloseTo(1167.140, 3); 909*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getMaxWidth()).toEqual(200); 910*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getMinIntrinsicWidth()).toBeCloseTo(172.360, 3); 911*c8dee2aaSAndroid Build Coastguard Worker // Check "VAVAVAVAVAVAVA" 912*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getWordBoundary(8)).toEqual({ 913*c8dee2aaSAndroid Build Coastguard Worker start: 0, 914*c8dee2aaSAndroid Build Coastguard Worker end: 14, 915*c8dee2aaSAndroid Build Coastguard Worker }); 916*c8dee2aaSAndroid Build Coastguard Worker // Check "I" 917*c8dee2aaSAndroid Build Coastguard Worker expect(paragraph.getWordBoundary(25)).toEqual({ 918*c8dee2aaSAndroid Build Coastguard Worker start: 25, 919*c8dee2aaSAndroid Build Coastguard Worker end: 26, 920*c8dee2aaSAndroid Build Coastguard Worker }); 921*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(10, 10, wrapTo+10, 230), paint); 922*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 923*c8dee2aaSAndroid Build Coastguard Worker 924*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 925*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 926*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 927*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 928*c8dee2aaSAndroid Build Coastguard Worker }); 929*c8dee2aaSAndroid Build Coastguard Worker 930*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_text_styles_mixed_leading_distribution', (canvas) => { 931*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 932*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 933*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 934*c8dee2aaSAndroid Build Coastguard Worker 935*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 200; 936*c8dee2aaSAndroid Build Coastguard Worker 937*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 938*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 939*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 940*c8dee2aaSAndroid Build Coastguard Worker backgroundColor: CanvasKit.Color(234, 208, 232), // light pink 941*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 942*c8dee2aaSAndroid Build Coastguard Worker fontSize: 10, 943*c8dee2aaSAndroid Build Coastguard Worker heightMultiplier: 10, 944*c8dee2aaSAndroid Build Coastguard Worker }, 945*c8dee2aaSAndroid Build Coastguard Worker }); 946*c8dee2aaSAndroid Build Coastguard Worker 947*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 948*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Not half leading'); 949*c8dee2aaSAndroid Build Coastguard Worker 950*c8dee2aaSAndroid Build Coastguard Worker const halfLeadingText = new CanvasKit.TextStyle({ 951*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(48, 37, 199), 952*c8dee2aaSAndroid Build Coastguard Worker backgroundColor: CanvasKit.Color(234, 208, 232), // light pink 953*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 954*c8dee2aaSAndroid Build Coastguard Worker fontSize: 10, 955*c8dee2aaSAndroid Build Coastguard Worker heightMultiplier: 10, 956*c8dee2aaSAndroid Build Coastguard Worker halfLeading: true, 957*c8dee2aaSAndroid Build Coastguard Worker }); 958*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(halfLeadingText); 959*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Half Leading Text'); 960*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 961*c8dee2aaSAndroid Build Coastguard Worker 962*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 963*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 0, 0); 964*c8dee2aaSAndroid Build Coastguard Worker 965*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 966*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 967*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 968*c8dee2aaSAndroid Build Coastguard Worker }); 969*c8dee2aaSAndroid Build Coastguard Worker 970*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_mixed_text_height_behavior', (canvas) => { 971*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer); 972*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.countFamilies()).toEqual(1); 973*c8dee2aaSAndroid Build Coastguard Worker expect(fontMgr.getFamilyName(0)).toEqual('Noto Serif'); 974*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 975*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 976*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 977*c8dee2aaSAndroid Build Coastguard Worker 978*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 220; 979*c8dee2aaSAndroid Build Coastguard Worker const behaviors = ["All", "DisableFirstAscent", "DisableLastDescent", "DisableAll"]; 980*c8dee2aaSAndroid Build Coastguard Worker 981*c8dee2aaSAndroid Build Coastguard Worker for (let i = 0; i < behaviors.length; i++) { 982*c8dee2aaSAndroid Build Coastguard Worker const style = new CanvasKit.ParagraphStyle({ 983*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 984*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 985*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 986*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 987*c8dee2aaSAndroid Build Coastguard Worker heightMultiplier: 3, // make the difference more obvious 988*c8dee2aaSAndroid Build Coastguard Worker }, 989*c8dee2aaSAndroid Build Coastguard Worker textHeightBehavior: CanvasKit.TextHeightBehavior[behaviors[i]], 990*c8dee2aaSAndroid Build Coastguard Worker }); 991*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(style, fontMgr); 992*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Text height behavior\nof '+behaviors[i]); 993*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 994*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 995*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 0, 150 * i); 996*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(0, 150 * i, wrapTo, 150 * i + 120), paint); 997*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 998*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 999*c8dee2aaSAndroid Build Coastguard Worker } 1000*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 1001*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 1002*c8dee2aaSAndroid Build Coastguard Worker }); 1003*c8dee2aaSAndroid Build Coastguard Worker 1004*c8dee2aaSAndroid Build Coastguard Worker it('should not crash if we omit font family on pushed textStyle', () => { 1005*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('test'); 1006*c8dee2aaSAndroid Build Coastguard Worker expect(surface).toBeTruthy('Could not make surface'); 1007*c8dee2aaSAndroid Build Coastguard Worker 1008*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 1009*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 1010*c8dee2aaSAndroid Build Coastguard Worker 1011*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 1012*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 1013*c8dee2aaSAndroid Build Coastguard Worker 1014*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer, notoSerifBoldItalicFontBuffer); 1015*c8dee2aaSAndroid Build Coastguard Worker 1016*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 1017*c8dee2aaSAndroid Build Coastguard Worker 1018*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 1019*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 1020*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 1021*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 1022*c8dee2aaSAndroid Build Coastguard Worker }, 1023*c8dee2aaSAndroid Build Coastguard Worker textDirection: CanvasKit.TextDirection.RTL, 1024*c8dee2aaSAndroid Build Coastguard Worker disableHinting: true, 1025*c8dee2aaSAndroid Build Coastguard Worker }); 1026*c8dee2aaSAndroid Build Coastguard Worker 1027*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 1028*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Default text\n'); 1029*c8dee2aaSAndroid Build Coastguard Worker 1030*c8dee2aaSAndroid Build Coastguard Worker const boldItalic = new CanvasKit.TextStyle({ 1031*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 1032*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Bold, 1033*c8dee2aaSAndroid Build Coastguard Worker slant: CanvasKit.FontSlant.Italic, 1034*c8dee2aaSAndroid Build Coastguard Worker } 1035*c8dee2aaSAndroid Build Coastguard Worker }); 1036*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(boldItalic); 1037*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Bold, Italic\n`); // doesn't show up, but we don't crash 1038*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 1039*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`back to normal`); 1040*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 1041*c8dee2aaSAndroid Build Coastguard Worker 1042*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 1043*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(10, 10, wrapTo+10, wrapTo+10), paint); 1044*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 1045*c8dee2aaSAndroid Build Coastguard Worker 1046*c8dee2aaSAndroid Build Coastguard Worker surface.flush(); 1047*c8dee2aaSAndroid Build Coastguard Worker 1048*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 1049*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 1050*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 1051*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 1052*c8dee2aaSAndroid Build Coastguard Worker }); 1053*c8dee2aaSAndroid Build Coastguard Worker 1054*c8dee2aaSAndroid Build Coastguard Worker it('should not crash if we omit font family on paragraph style', () => { 1055*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('test'); 1056*c8dee2aaSAndroid Build Coastguard Worker expect(surface).toBeTruthy('Could not make surface'); 1057*c8dee2aaSAndroid Build Coastguard Worker 1058*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 1059*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 1060*c8dee2aaSAndroid Build Coastguard Worker 1061*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 1062*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 1063*c8dee2aaSAndroid Build Coastguard Worker 1064*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer, notoSerifBoldItalicFontBuffer); 1065*c8dee2aaSAndroid Build Coastguard Worker 1066*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 1067*c8dee2aaSAndroid Build Coastguard Worker 1068*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 1069*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 1070*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 1071*c8dee2aaSAndroid Build Coastguard Worker }, 1072*c8dee2aaSAndroid Build Coastguard Worker textDirection: CanvasKit.TextDirection.RTL, 1073*c8dee2aaSAndroid Build Coastguard Worker disableHinting: true, 1074*c8dee2aaSAndroid Build Coastguard Worker }); 1075*c8dee2aaSAndroid Build Coastguard Worker 1076*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 1077*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Default text\n'); 1078*c8dee2aaSAndroid Build Coastguard Worker 1079*c8dee2aaSAndroid Build Coastguard Worker const boldItalic = new CanvasKit.TextStyle({ 1080*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 1081*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Bold, 1082*c8dee2aaSAndroid Build Coastguard Worker slant: CanvasKit.FontSlant.Italic, 1083*c8dee2aaSAndroid Build Coastguard Worker } 1084*c8dee2aaSAndroid Build Coastguard Worker }); 1085*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(boldItalic); 1086*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Bold, Italic\n`); 1087*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 1088*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`back to normal`); 1089*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 1090*c8dee2aaSAndroid Build Coastguard Worker 1091*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 1092*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(10, 10, wrapTo+10, wrapTo+10), paint); 1093*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 1094*c8dee2aaSAndroid Build Coastguard Worker 1095*c8dee2aaSAndroid Build Coastguard Worker surface.flush(); 1096*c8dee2aaSAndroid Build Coastguard Worker 1097*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 1098*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 1099*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 1100*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 1101*c8dee2aaSAndroid Build Coastguard Worker }); 1102*c8dee2aaSAndroid Build Coastguard Worker 1103*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_builder_with_reset', (canvas) => { 1104*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer, notoSerifBoldItalicFontBuffer); 1105*c8dee2aaSAndroid Build Coastguard Worker 1106*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 1107*c8dee2aaSAndroid Build Coastguard Worker 1108*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 1109*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 1110*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 1111*c8dee2aaSAndroid Build Coastguard Worker }, 1112*c8dee2aaSAndroid Build Coastguard Worker }); 1113*c8dee2aaSAndroid Build Coastguard Worker 1114*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 1115*c8dee2aaSAndroid Build Coastguard Worker builder.addText('Default text\n'); 1116*c8dee2aaSAndroid Build Coastguard Worker 1117*c8dee2aaSAndroid Build Coastguard Worker const boldItalic = new CanvasKit.TextStyle({ 1118*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 1119*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Bold, 1120*c8dee2aaSAndroid Build Coastguard Worker slant: CanvasKit.FontSlant.Italic, 1121*c8dee2aaSAndroid Build Coastguard Worker } 1122*c8dee2aaSAndroid Build Coastguard Worker }); 1123*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(boldItalic); 1124*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Bold, Italic\n`); 1125*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 1126*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 1127*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 1128*c8dee2aaSAndroid Build Coastguard Worker 1129*c8dee2aaSAndroid Build Coastguard Worker builder.reset(); 1130*c8dee2aaSAndroid Build Coastguard Worker builder.addText('This builder has been reused\n'); 1131*c8dee2aaSAndroid Build Coastguard Worker 1132*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(boldItalic); 1133*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`2 Bold, Italic\n`); 1134*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 1135*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`2 back to normal`); 1136*c8dee2aaSAndroid Build Coastguard Worker const paragraph2 = builder.build(); 1137*c8dee2aaSAndroid Build Coastguard Worker paragraph2.layout(wrapTo); 1138*c8dee2aaSAndroid Build Coastguard Worker 1139*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 1140*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph2, 10, 100); 1141*c8dee2aaSAndroid Build Coastguard Worker 1142*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 1143*c8dee2aaSAndroid Build Coastguard Worker paragraph2.delete(); 1144*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 1145*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 1146*c8dee2aaSAndroid Build Coastguard Worker }); 1147*c8dee2aaSAndroid Build Coastguard Worker 1148*c8dee2aaSAndroid Build Coastguard Worker // This helped find and resolve skbug.com/13247 1149*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_saved_to_skpicture', (canvas) => { 1150*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer, notoSerifBoldItalicFontBuffer); 1151*c8dee2aaSAndroid Build Coastguard Worker 1152*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 1153*c8dee2aaSAndroid Build Coastguard Worker 1154*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 1155*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 1156*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 1157*c8dee2aaSAndroid Build Coastguard Worker }, 1158*c8dee2aaSAndroid Build Coastguard Worker }); 1159*c8dee2aaSAndroid Build Coastguard Worker 1160*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 1161*c8dee2aaSAndroid Build Coastguard Worker builder.addText('This was saved to an SkPicture\n'); 1162*c8dee2aaSAndroid Build Coastguard Worker 1163*c8dee2aaSAndroid Build Coastguard Worker const boldItalic = new CanvasKit.TextStyle({ 1164*c8dee2aaSAndroid Build Coastguard Worker fontStyle: { 1165*c8dee2aaSAndroid Build Coastguard Worker weight: CanvasKit.FontWeight.Bold, 1166*c8dee2aaSAndroid Build Coastguard Worker slant: CanvasKit.FontSlant.Italic, 1167*c8dee2aaSAndroid Build Coastguard Worker } 1168*c8dee2aaSAndroid Build Coastguard Worker }); 1169*c8dee2aaSAndroid Build Coastguard Worker builder.pushStyle(boldItalic); 1170*c8dee2aaSAndroid Build Coastguard Worker builder.addText(`Bold, Italic\n`); 1171*c8dee2aaSAndroid Build Coastguard Worker builder.pop(); 1172*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 1173*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 1174*c8dee2aaSAndroid Build Coastguard Worker 1175*c8dee2aaSAndroid Build Coastguard Worker const recorder = new CanvasKit.PictureRecorder(); 1176*c8dee2aaSAndroid Build Coastguard Worker const skpCanvas = recorder.beginRecording(CanvasKit.LTRBRect(0, 0, 200, 200)); 1177*c8dee2aaSAndroid Build Coastguard Worker skpCanvas.drawParagraph(paragraph, 10, 10); 1178*c8dee2aaSAndroid Build Coastguard Worker const picture = recorder.finishRecordingAsPicture(); 1179*c8dee2aaSAndroid Build Coastguard Worker 1180*c8dee2aaSAndroid Build Coastguard Worker canvas.drawPicture(CanvasKit.MakePicture(picture.serialize())); 1181*c8dee2aaSAndroid Build Coastguard Worker 1182*c8dee2aaSAndroid Build Coastguard Worker picture.delete(); 1183*c8dee2aaSAndroid Build Coastguard Worker recorder.delete(); 1184*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 1185*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 1186*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 1187*c8dee2aaSAndroid Build Coastguard Worker }); 1188*c8dee2aaSAndroid Build Coastguard Worker 1189*c8dee2aaSAndroid Build Coastguard Worker it('should replace tab characters', () => { 1190*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(notoSerifFontBuffer, notoSerifBoldItalicFontBuffer); 1191*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 1192*c8dee2aaSAndroid Build Coastguard Worker 1193*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 1194*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 1195*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 1196*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Noto Serif'], 1197*c8dee2aaSAndroid Build Coastguard Worker fontSize: 20, 1198*c8dee2aaSAndroid Build Coastguard Worker }, 1199*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 1200*c8dee2aaSAndroid Build Coastguard Worker replaceTabCharacters: true, 1201*c8dee2aaSAndroid Build Coastguard Worker }); 1202*c8dee2aaSAndroid Build Coastguard Worker 1203*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 1204*c8dee2aaSAndroid Build Coastguard Worker builder.addText('1\t2'); 1205*c8dee2aaSAndroid Build Coastguard Worker 1206*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 1207*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 1208*c8dee2aaSAndroid Build Coastguard Worker 1209*c8dee2aaSAndroid Build Coastguard Worker const lines = paragraph.getShapedLines(); 1210*c8dee2aaSAndroid Build Coastguard Worker 1211*c8dee2aaSAndroid Build Coastguard Worker expect(lines.length).toEqual(1); 1212*c8dee2aaSAndroid Build Coastguard Worker expect(lines[0].runs.length).toEqual(1); 1213*c8dee2aaSAndroid Build Coastguard Worker expect(lines[0].runs[0].glyphs.length).toEqual(3); 1214*c8dee2aaSAndroid Build Coastguard Worker 1215*c8dee2aaSAndroid Build Coastguard Worker // The tab should not be a missing glyph. 1216*c8dee2aaSAndroid Build Coastguard Worker expect(lines[0].runs[0].glyphs[1]).not.toEqual(0); 1217*c8dee2aaSAndroid Build Coastguard Worker 1218*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 1219*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 1220*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 1221*c8dee2aaSAndroid Build Coastguard Worker }); 1222*c8dee2aaSAndroid Build Coastguard Worker 1223*c8dee2aaSAndroid Build Coastguard Worker gm('paragraph_fontSize_and_heightMultiplier_0', (canvas) => { 1224*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData(robotoFontBuffer); 1225*c8dee2aaSAndroid Build Coastguard Worker const wrapTo = 250; 1226*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 1227*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 1228*c8dee2aaSAndroid Build Coastguard Worker fontSize: 0, 1229*c8dee2aaSAndroid Build Coastguard Worker heightMultiplier: 0, 1230*c8dee2aaSAndroid Build Coastguard Worker }, 1231*c8dee2aaSAndroid Build Coastguard Worker }); 1232*c8dee2aaSAndroid Build Coastguard Worker 1233*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 1234*c8dee2aaSAndroid Build Coastguard Worker builder.addText('This should not be visible'); 1235*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 1236*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 1237*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 1238*c8dee2aaSAndroid Build Coastguard Worker 1239*c8dee2aaSAndroid Build Coastguard Worker let rects = paragraph.getRectsForRange(0, 1, CanvasKit.RectHeightStyle.Tight, CanvasKit.RectWidthStyle.Tight); 1240*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 1241*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.Color(255, 0, 0)); 1242*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(rects[0].rect, paint); 1243*c8dee2aaSAndroid Build Coastguard Worker expect(rects[0].dir).toEqual(CanvasKit.TextDirection.LTR); 1244*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 1245*c8dee2aaSAndroid Build Coastguard Worker 1246*c8dee2aaSAndroid Build Coastguard Worker paragraph.delete(); 1247*c8dee2aaSAndroid Build Coastguard Worker fontMgr.delete(); 1248*c8dee2aaSAndroid Build Coastguard Worker builder.delete(); 1249*c8dee2aaSAndroid Build Coastguard Worker }); 1250*c8dee2aaSAndroid Build Coastguard Worker 1251*c8dee2aaSAndroid Build Coastguard Worker}); 1252