xref: /aosp_15_r20/external/skia/modules/canvaskit/font.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
2*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit._extraInitializations.push(function() {
3*c8dee2aaSAndroid Build Coastguard Worker
4*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Canvas.prototype.drawText = function(str, x, y, paint, font) {
5*c8dee2aaSAndroid Build Coastguard Worker    // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
6*c8dee2aaSAndroid Build Coastguard Worker    // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
7*c8dee2aaSAndroid Build Coastguard Worker    var strLen = lengthBytesUTF8(str);
8*c8dee2aaSAndroid Build Coastguard Worker    // Add 1 for null terminator, which we need when copying/converting, but can ignore
9*c8dee2aaSAndroid Build Coastguard Worker    // when we call into Skia.
10*c8dee2aaSAndroid Build Coastguard Worker    var strPtr = CanvasKit._malloc(strLen + 1);
11*c8dee2aaSAndroid Build Coastguard Worker    stringToUTF8(str, strPtr, strLen + 1);
12*c8dee2aaSAndroid Build Coastguard Worker    this._drawSimpleText(strPtr, strLen, x, y, font, paint);
13*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(strPtr);
14*c8dee2aaSAndroid Build Coastguard Worker  };
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Canvas.prototype.drawGlyphs = function(glyphs, positions, x, y, font, paint) {
17*c8dee2aaSAndroid Build Coastguard Worker    if (!(glyphs.length*2 <= positions.length)) {
18*c8dee2aaSAndroid Build Coastguard Worker        throw 'Not enough positions for the array of gyphs';
19*c8dee2aaSAndroid Build Coastguard Worker    }
20*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit.setCurrentContext(this._context);
21*c8dee2aaSAndroid Build Coastguard Worker    const glyphs_ptr    = copy1dArray(glyphs, 'HEAPU16');
22*c8dee2aaSAndroid Build Coastguard Worker    const positions_ptr = copy1dArray(positions, 'HEAPF32');
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker    this._drawGlyphs(glyphs.length, glyphs_ptr, positions_ptr, x, y, font, paint);
25*c8dee2aaSAndroid Build Coastguard Worker
26*c8dee2aaSAndroid Build Coastguard Worker    freeArraysThatAreNotMallocedByUsers(positions_ptr, positions);
27*c8dee2aaSAndroid Build Coastguard Worker    freeArraysThatAreNotMallocedByUsers(glyphs_ptr,    glyphs);
28*c8dee2aaSAndroid Build Coastguard Worker  };
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker  // Glyphs should be a Uint16Array of glyph ids, e.g. provided by Font.getGlyphIDs.
31*c8dee2aaSAndroid Build Coastguard Worker  // If using a Malloc'd array, be sure to use CanvasKit.MallocGlyphIDs() to get the right type.
32*c8dee2aaSAndroid Build Coastguard Worker  // The return value will be a Float32Array that is 4 times as long as the input array. For each
33*c8dee2aaSAndroid Build Coastguard Worker  // glyph, there will be 4 floats for left, top, right, bottom (relative to 0, 0) for that glyph.
34*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Font.prototype.getGlyphBounds = function(glyphs, paint, optionalOutputArray) {
35*c8dee2aaSAndroid Build Coastguard Worker    var glyphPtr = copy1dArray(glyphs, 'HEAPU16');
36*c8dee2aaSAndroid Build Coastguard Worker    var bytesPerRect = 4 * 4;
37*c8dee2aaSAndroid Build Coastguard Worker    var rectPtr = CanvasKit._malloc(glyphs.length * bytesPerRect);
38*c8dee2aaSAndroid Build Coastguard Worker    this._getGlyphWidthBounds(glyphPtr, glyphs.length, nullptr, rectPtr, paint || null);
39*c8dee2aaSAndroid Build Coastguard Worker
40*c8dee2aaSAndroid Build Coastguard Worker    var rects = new Float32Array(CanvasKit.HEAPU8.buffer, rectPtr, glyphs.length * 4);
41*c8dee2aaSAndroid Build Coastguard Worker    freeArraysThatAreNotMallocedByUsers(glyphPtr, glyphs);
42*c8dee2aaSAndroid Build Coastguard Worker    if (optionalOutputArray) {
43*c8dee2aaSAndroid Build Coastguard Worker      optionalOutputArray.set(rects);
44*c8dee2aaSAndroid Build Coastguard Worker      CanvasKit._free(rectPtr);
45*c8dee2aaSAndroid Build Coastguard Worker      return optionalOutputArray;
46*c8dee2aaSAndroid Build Coastguard Worker    }
47*c8dee2aaSAndroid Build Coastguard Worker    var rv = Float32Array.from(rects);
48*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(rectPtr);
49*c8dee2aaSAndroid Build Coastguard Worker    return rv;
50*c8dee2aaSAndroid Build Coastguard Worker  };
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Font.prototype.getGlyphIDs = function(str, numGlyphIDs, optionalOutputArray) {
53*c8dee2aaSAndroid Build Coastguard Worker    if (!numGlyphIDs) {
54*c8dee2aaSAndroid Build Coastguard Worker      numGlyphIDs = str.length;
55*c8dee2aaSAndroid Build Coastguard Worker    }
56*c8dee2aaSAndroid Build Coastguard Worker    // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
57*c8dee2aaSAndroid Build Coastguard Worker    // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
58*c8dee2aaSAndroid Build Coastguard Worker    // Add 1 for null terminator
59*c8dee2aaSAndroid Build Coastguard Worker    var strBytes = lengthBytesUTF8(str) + 1;
60*c8dee2aaSAndroid Build Coastguard Worker    var strPtr = CanvasKit._malloc(strBytes);
61*c8dee2aaSAndroid Build Coastguard Worker    stringToUTF8(str, strPtr, strBytes); // This includes the null terminator
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker    var bytesPerGlyph = 2;
64*c8dee2aaSAndroid Build Coastguard Worker    var glyphPtr = CanvasKit._malloc(numGlyphIDs * bytesPerGlyph);
65*c8dee2aaSAndroid Build Coastguard Worker    // We don't need to compute the id for the null terminator, so subtract 1.
66*c8dee2aaSAndroid Build Coastguard Worker    var actualIDs = this._getGlyphIDs(strPtr, strBytes - 1, numGlyphIDs, glyphPtr);
67*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(strPtr);
68*c8dee2aaSAndroid Build Coastguard Worker    if (actualIDs < 0) {
69*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not get glyphIDs');
70*c8dee2aaSAndroid Build Coastguard Worker      CanvasKit._free(glyphPtr);
71*c8dee2aaSAndroid Build Coastguard Worker      return null;
72*c8dee2aaSAndroid Build Coastguard Worker    }
73*c8dee2aaSAndroid Build Coastguard Worker    var glyphs = new Uint16Array(CanvasKit.HEAPU8.buffer, glyphPtr, actualIDs);
74*c8dee2aaSAndroid Build Coastguard Worker    if (optionalOutputArray) {
75*c8dee2aaSAndroid Build Coastguard Worker      optionalOutputArray.set(glyphs);
76*c8dee2aaSAndroid Build Coastguard Worker      CanvasKit._free(glyphPtr);
77*c8dee2aaSAndroid Build Coastguard Worker      return optionalOutputArray;
78*c8dee2aaSAndroid Build Coastguard Worker    }
79*c8dee2aaSAndroid Build Coastguard Worker    var rv = Uint16Array.from(glyphs);
80*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(glyphPtr);
81*c8dee2aaSAndroid Build Coastguard Worker    return rv;
82*c8dee2aaSAndroid Build Coastguard Worker  };
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Font.prototype.getGlyphIntercepts = function(glyphs, positions, top, bottom) {
85*c8dee2aaSAndroid Build Coastguard Worker    var gPtr = copy1dArray(glyphs, 'HEAPU16');
86*c8dee2aaSAndroid Build Coastguard Worker    var pPtr = copy1dArray(positions, 'HEAPF32');
87*c8dee2aaSAndroid Build Coastguard Worker    return this._getGlyphIntercepts(gPtr, glyphs.length, !wasMalloced(glyphs),
88*c8dee2aaSAndroid Build Coastguard Worker                                    pPtr, positions.length, !wasMalloced(positions),
89*c8dee2aaSAndroid Build Coastguard Worker                                    top, bottom);
90*c8dee2aaSAndroid Build Coastguard Worker  };
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker  // Glyphs should be a Uint16Array of glyph ids, e.g. provided by Font.getGlyphIDs.
93*c8dee2aaSAndroid Build Coastguard Worker  // If using a Malloc'd array, be sure to use CanvasKit.MallocGlyphIDs() to get the right type.
94*c8dee2aaSAndroid Build Coastguard Worker  // The return value will be a Float32Array that has one width per input glyph.
95*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Font.prototype.getGlyphWidths = function(glyphs, paint, optionalOutputArray) {
96*c8dee2aaSAndroid Build Coastguard Worker    var glyphPtr = copy1dArray(glyphs, 'HEAPU16');
97*c8dee2aaSAndroid Build Coastguard Worker    var bytesPerWidth = 4;
98*c8dee2aaSAndroid Build Coastguard Worker    var widthPtr = CanvasKit._malloc(glyphs.length * bytesPerWidth);
99*c8dee2aaSAndroid Build Coastguard Worker    this._getGlyphWidthBounds(glyphPtr, glyphs.length, widthPtr, nullptr, paint || null);
100*c8dee2aaSAndroid Build Coastguard Worker
101*c8dee2aaSAndroid Build Coastguard Worker    var widths = new Float32Array(CanvasKit.HEAPU8.buffer, widthPtr, glyphs.length);
102*c8dee2aaSAndroid Build Coastguard Worker    freeArraysThatAreNotMallocedByUsers(glyphPtr, glyphs);
103*c8dee2aaSAndroid Build Coastguard Worker    if (optionalOutputArray) {
104*c8dee2aaSAndroid Build Coastguard Worker      optionalOutputArray.set(widths);
105*c8dee2aaSAndroid Build Coastguard Worker      CanvasKit._free(widthPtr);
106*c8dee2aaSAndroid Build Coastguard Worker      return optionalOutputArray;
107*c8dee2aaSAndroid Build Coastguard Worker    }
108*c8dee2aaSAndroid Build Coastguard Worker    var rv = Float32Array.from(widths);
109*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(widthPtr);
110*c8dee2aaSAndroid Build Coastguard Worker    return rv;
111*c8dee2aaSAndroid Build Coastguard Worker  };
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker  // arguments should all be arrayBuffers or be an array of arrayBuffers.
114*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.FontMgr.FromData = function() {
115*c8dee2aaSAndroid Build Coastguard Worker    if (!arguments.length) {
116*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not make FontMgr from no font sources');
117*c8dee2aaSAndroid Build Coastguard Worker      return null;
118*c8dee2aaSAndroid Build Coastguard Worker    }
119*c8dee2aaSAndroid Build Coastguard Worker    var fonts = arguments;
120*c8dee2aaSAndroid Build Coastguard Worker    if (fonts.length === 1 && Array.isArray(fonts[0])) {
121*c8dee2aaSAndroid Build Coastguard Worker      fonts = arguments[0];
122*c8dee2aaSAndroid Build Coastguard Worker    }
123*c8dee2aaSAndroid Build Coastguard Worker    if (!fonts.length) {
124*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not make FontMgr from no font sources');
125*c8dee2aaSAndroid Build Coastguard Worker      return null;
126*c8dee2aaSAndroid Build Coastguard Worker    }
127*c8dee2aaSAndroid Build Coastguard Worker    var dPtrs = [];
128*c8dee2aaSAndroid Build Coastguard Worker    var sizes = [];
129*c8dee2aaSAndroid Build Coastguard Worker    for (var i = 0; i < fonts.length; i++) {
130*c8dee2aaSAndroid Build Coastguard Worker      var data = new Uint8Array(fonts[i]);
131*c8dee2aaSAndroid Build Coastguard Worker      var dptr = copy1dArray(data, 'HEAPU8');
132*c8dee2aaSAndroid Build Coastguard Worker      dPtrs.push(dptr);
133*c8dee2aaSAndroid Build Coastguard Worker      sizes.push(data.byteLength);
134*c8dee2aaSAndroid Build Coastguard Worker    }
135*c8dee2aaSAndroid Build Coastguard Worker    // Pointers are 32 bit unsigned ints
136*c8dee2aaSAndroid Build Coastguard Worker    var datasPtr = copy1dArray(dPtrs, 'HEAPU32');
137*c8dee2aaSAndroid Build Coastguard Worker    var sizesPtr = copy1dArray(sizes, 'HEAPU32');
138*c8dee2aaSAndroid Build Coastguard Worker    var fm = CanvasKit.FontMgr._fromData(datasPtr, sizesPtr, fonts.length);
139*c8dee2aaSAndroid Build Coastguard Worker    // The FontMgr has taken ownership of the bytes we allocated in the for loop.
140*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(datasPtr);
141*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(sizesPtr);
142*c8dee2aaSAndroid Build Coastguard Worker    return fm;
143*c8dee2aaSAndroid Build Coastguard Worker  };
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Typeface.MakeTypefaceFromData = function(fontData) {
146*c8dee2aaSAndroid Build Coastguard Worker    var data = new Uint8Array(fontData);
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Worker    var fptr = copy1dArray(data, 'HEAPU8');
149*c8dee2aaSAndroid Build Coastguard Worker    var font = CanvasKit.Typeface._MakeTypefaceFromData(fptr, data.byteLength);
150*c8dee2aaSAndroid Build Coastguard Worker    if (!font) {
151*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not decode font data');
152*c8dee2aaSAndroid Build Coastguard Worker      // We do not need to free the data since the C++ will do that for us
153*c8dee2aaSAndroid Build Coastguard Worker      // when the font is deleted (or fails to decode);
154*c8dee2aaSAndroid Build Coastguard Worker      return null;
155*c8dee2aaSAndroid Build Coastguard Worker    }
156*c8dee2aaSAndroid Build Coastguard Worker    return font;
157*c8dee2aaSAndroid Build Coastguard Worker  };
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker  // TODO(kjlubick) remove this after clients have migrated.
160*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Typeface["MakeFreeTypeFaceFromData"] = CanvasKit.Typeface.MakeTypefaceFromData;
161*c8dee2aaSAndroid Build Coastguard Worker
162*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.Typeface.prototype.getGlyphIDs = function(str, numGlyphIDs, optionalOutputArray) {
163*c8dee2aaSAndroid Build Coastguard Worker    if (!numGlyphIDs) {
164*c8dee2aaSAndroid Build Coastguard Worker      numGlyphIDs = str.length;
165*c8dee2aaSAndroid Build Coastguard Worker    }
166*c8dee2aaSAndroid Build Coastguard Worker    // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
167*c8dee2aaSAndroid Build Coastguard Worker    // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
168*c8dee2aaSAndroid Build Coastguard Worker    // Add 1 for null terminator
169*c8dee2aaSAndroid Build Coastguard Worker    var strBytes = lengthBytesUTF8(str) + 1;
170*c8dee2aaSAndroid Build Coastguard Worker    var strPtr = CanvasKit._malloc(strBytes);
171*c8dee2aaSAndroid Build Coastguard Worker    stringToUTF8(str, strPtr, strBytes); // This includes the null terminator
172*c8dee2aaSAndroid Build Coastguard Worker
173*c8dee2aaSAndroid Build Coastguard Worker    var bytesPerGlyph = 2;
174*c8dee2aaSAndroid Build Coastguard Worker    var glyphPtr = CanvasKit._malloc(numGlyphIDs * bytesPerGlyph);
175*c8dee2aaSAndroid Build Coastguard Worker    // We don't need to compute the id for the null terminator, so subtract 1.
176*c8dee2aaSAndroid Build Coastguard Worker    var actualIDs = this._getGlyphIDs(strPtr, strBytes - 1, numGlyphIDs, glyphPtr);
177*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(strPtr);
178*c8dee2aaSAndroid Build Coastguard Worker    if (actualIDs < 0) {
179*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not get glyphIDs');
180*c8dee2aaSAndroid Build Coastguard Worker      CanvasKit._free(glyphPtr);
181*c8dee2aaSAndroid Build Coastguard Worker      return null;
182*c8dee2aaSAndroid Build Coastguard Worker    }
183*c8dee2aaSAndroid Build Coastguard Worker    var glyphs = new Uint16Array(CanvasKit.HEAPU8.buffer, glyphPtr, actualIDs);
184*c8dee2aaSAndroid Build Coastguard Worker    if (optionalOutputArray) {
185*c8dee2aaSAndroid Build Coastguard Worker      optionalOutputArray.set(glyphs);
186*c8dee2aaSAndroid Build Coastguard Worker      CanvasKit._free(glyphPtr);
187*c8dee2aaSAndroid Build Coastguard Worker      return optionalOutputArray;
188*c8dee2aaSAndroid Build Coastguard Worker    }
189*c8dee2aaSAndroid Build Coastguard Worker    var rv = Uint16Array.from(glyphs);
190*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(glyphPtr);
191*c8dee2aaSAndroid Build Coastguard Worker    return rv;
192*c8dee2aaSAndroid Build Coastguard Worker  };
193*c8dee2aaSAndroid Build Coastguard Worker
194*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.TextBlob.MakeOnPath = function(str, path, font, initialOffset) {
195*c8dee2aaSAndroid Build Coastguard Worker    if (!str || !str.length) {
196*c8dee2aaSAndroid Build Coastguard Worker      Debug('ignoring 0 length string');
197*c8dee2aaSAndroid Build Coastguard Worker      return;
198*c8dee2aaSAndroid Build Coastguard Worker    }
199*c8dee2aaSAndroid Build Coastguard Worker    if (!path || !path.countPoints()) {
200*c8dee2aaSAndroid Build Coastguard Worker      Debug('ignoring empty path');
201*c8dee2aaSAndroid Build Coastguard Worker      return;
202*c8dee2aaSAndroid Build Coastguard Worker    }
203*c8dee2aaSAndroid Build Coastguard Worker    if (path.countPoints() === 1) {
204*c8dee2aaSAndroid Build Coastguard Worker      Debug('path has 1 point, returning normal textblob');
205*c8dee2aaSAndroid Build Coastguard Worker      return this.MakeFromText(str, font);
206*c8dee2aaSAndroid Build Coastguard Worker    }
207*c8dee2aaSAndroid Build Coastguard Worker
208*c8dee2aaSAndroid Build Coastguard Worker    if (!initialOffset) {
209*c8dee2aaSAndroid Build Coastguard Worker      initialOffset = 0;
210*c8dee2aaSAndroid Build Coastguard Worker    }
211*c8dee2aaSAndroid Build Coastguard Worker
212*c8dee2aaSAndroid Build Coastguard Worker    var ids = font.getGlyphIDs(str);
213*c8dee2aaSAndroid Build Coastguard Worker    var widths = font.getGlyphWidths(ids);
214*c8dee2aaSAndroid Build Coastguard Worker
215*c8dee2aaSAndroid Build Coastguard Worker    var rsx = [];
216*c8dee2aaSAndroid Build Coastguard Worker    var meas = new CanvasKit.ContourMeasureIter(path, false, 1);
217*c8dee2aaSAndroid Build Coastguard Worker    var cont = meas.next();
218*c8dee2aaSAndroid Build Coastguard Worker    var dist = initialOffset;
219*c8dee2aaSAndroid Build Coastguard Worker    var xycs = new Float32Array(4);
220*c8dee2aaSAndroid Build Coastguard Worker    for (var i = 0; i < str.length && cont; i++) {
221*c8dee2aaSAndroid Build Coastguard Worker      var width = widths[i];
222*c8dee2aaSAndroid Build Coastguard Worker      dist += width/2;
223*c8dee2aaSAndroid Build Coastguard Worker      if (dist > cont.length()) {
224*c8dee2aaSAndroid Build Coastguard Worker        // jump to next contour
225*c8dee2aaSAndroid Build Coastguard Worker        cont.delete();
226*c8dee2aaSAndroid Build Coastguard Worker        cont = meas.next();
227*c8dee2aaSAndroid Build Coastguard Worker        if (!cont) {
228*c8dee2aaSAndroid Build Coastguard Worker          // We have come to the end of the path - terminate the string
229*c8dee2aaSAndroid Build Coastguard Worker          // right here.
230*c8dee2aaSAndroid Build Coastguard Worker          str = str.substring(0, i);
231*c8dee2aaSAndroid Build Coastguard Worker          break;
232*c8dee2aaSAndroid Build Coastguard Worker        }
233*c8dee2aaSAndroid Build Coastguard Worker        dist = width/2;
234*c8dee2aaSAndroid Build Coastguard Worker      }
235*c8dee2aaSAndroid Build Coastguard Worker
236*c8dee2aaSAndroid Build Coastguard Worker      // Gives us the (x, y) coordinates as well as the cos/sin of the tangent
237*c8dee2aaSAndroid Build Coastguard Worker      // line at that position.
238*c8dee2aaSAndroid Build Coastguard Worker      cont.getPosTan(dist, xycs);
239*c8dee2aaSAndroid Build Coastguard Worker      var cx = xycs[0];
240*c8dee2aaSAndroid Build Coastguard Worker      var cy = xycs[1];
241*c8dee2aaSAndroid Build Coastguard Worker      var cosT = xycs[2];
242*c8dee2aaSAndroid Build Coastguard Worker      var sinT = xycs[3];
243*c8dee2aaSAndroid Build Coastguard Worker
244*c8dee2aaSAndroid Build Coastguard Worker      var adjustedX = cx - (width/2 * cosT);
245*c8dee2aaSAndroid Build Coastguard Worker      var adjustedY = cy - (width/2 * sinT);
246*c8dee2aaSAndroid Build Coastguard Worker
247*c8dee2aaSAndroid Build Coastguard Worker      rsx.push(cosT, sinT, adjustedX, adjustedY);
248*c8dee2aaSAndroid Build Coastguard Worker      dist += width/2;
249*c8dee2aaSAndroid Build Coastguard Worker    }
250*c8dee2aaSAndroid Build Coastguard Worker    var retVal = this.MakeFromRSXform(str, rsx, font);
251*c8dee2aaSAndroid Build Coastguard Worker    cont && cont.delete();
252*c8dee2aaSAndroid Build Coastguard Worker    meas.delete();
253*c8dee2aaSAndroid Build Coastguard Worker    return retVal;
254*c8dee2aaSAndroid Build Coastguard Worker  };
255*c8dee2aaSAndroid Build Coastguard Worker
256*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.TextBlob.MakeFromRSXform = function(str, rsxForms, font) {
257*c8dee2aaSAndroid Build Coastguard Worker    // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
258*c8dee2aaSAndroid Build Coastguard Worker    // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
259*c8dee2aaSAndroid Build Coastguard Worker    // Add 1 for null terminator
260*c8dee2aaSAndroid Build Coastguard Worker    var strLen = lengthBytesUTF8(str) + 1;
261*c8dee2aaSAndroid Build Coastguard Worker    var strPtr = CanvasKit._malloc(strLen);
262*c8dee2aaSAndroid Build Coastguard Worker    // Add 1 for the null terminator.
263*c8dee2aaSAndroid Build Coastguard Worker    stringToUTF8(str, strPtr, strLen);
264*c8dee2aaSAndroid Build Coastguard Worker
265*c8dee2aaSAndroid Build Coastguard Worker    var rPtr = copy1dArray(rsxForms, 'HEAPF32');
266*c8dee2aaSAndroid Build Coastguard Worker
267*c8dee2aaSAndroid Build Coastguard Worker    var blob = CanvasKit.TextBlob._MakeFromRSXform(strPtr, strLen - 1, rPtr, font);
268*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(strPtr);
269*c8dee2aaSAndroid Build Coastguard Worker    if (!blob) {
270*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not make textblob from string "' + str + '"');
271*c8dee2aaSAndroid Build Coastguard Worker      return null;
272*c8dee2aaSAndroid Build Coastguard Worker    }
273*c8dee2aaSAndroid Build Coastguard Worker    return blob;
274*c8dee2aaSAndroid Build Coastguard Worker  };
275*c8dee2aaSAndroid Build Coastguard Worker
276*c8dee2aaSAndroid Build Coastguard Worker  // Glyphs should be a Uint32Array of glyph ids, e.g. provided by Font.getGlyphIDs.
277*c8dee2aaSAndroid Build Coastguard Worker  // If using a Malloc'd array, be sure to use CanvasKit.MallocGlyphIDs() to get the right type.
278*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.TextBlob.MakeFromRSXformGlyphs = function(glyphs, rsxForms, font) {
279*c8dee2aaSAndroid Build Coastguard Worker    // Currently on the C++ side, glyph ids are 16bit, but there is an effort to change that.
280*c8dee2aaSAndroid Build Coastguard Worker    var glyphPtr = copy1dArray(glyphs, 'HEAPU16');
281*c8dee2aaSAndroid Build Coastguard Worker    var bytesPerGlyph = 2;
282*c8dee2aaSAndroid Build Coastguard Worker
283*c8dee2aaSAndroid Build Coastguard Worker    var rPtr = copy1dArray(rsxForms, 'HEAPF32');
284*c8dee2aaSAndroid Build Coastguard Worker
285*c8dee2aaSAndroid Build Coastguard Worker    var blob = CanvasKit.TextBlob._MakeFromRSXformGlyphs(glyphPtr, glyphs.length * bytesPerGlyph, rPtr, font);
286*c8dee2aaSAndroid Build Coastguard Worker    freeArraysThatAreNotMallocedByUsers(glyphPtr, glyphs);
287*c8dee2aaSAndroid Build Coastguard Worker    if (!blob) {
288*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not make textblob from glyphs "' + glyphs + '"');
289*c8dee2aaSAndroid Build Coastguard Worker      return null;
290*c8dee2aaSAndroid Build Coastguard Worker    }
291*c8dee2aaSAndroid Build Coastguard Worker    return blob;
292*c8dee2aaSAndroid Build Coastguard Worker  };
293*c8dee2aaSAndroid Build Coastguard Worker
294*c8dee2aaSAndroid Build Coastguard Worker  // Glyphs should be a Uint32Array of glyph ids, e.g. provided by Font.getGlyphIDs.
295*c8dee2aaSAndroid Build Coastguard Worker  // If using a Malloc'd array, be sure to use CanvasKit.MallocGlyphIDs() to get the right type.
296*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.TextBlob.MakeFromGlyphs = function(glyphs, font) {
297*c8dee2aaSAndroid Build Coastguard Worker    // Currently on the C++ side, glyph ids are 16bit, but there is an effort to change that.
298*c8dee2aaSAndroid Build Coastguard Worker    var glyphPtr = copy1dArray(glyphs, 'HEAPU16');
299*c8dee2aaSAndroid Build Coastguard Worker    var bytesPerGlyph = 2;
300*c8dee2aaSAndroid Build Coastguard Worker    var blob = CanvasKit.TextBlob._MakeFromGlyphs(glyphPtr, glyphs.length * bytesPerGlyph, font);
301*c8dee2aaSAndroid Build Coastguard Worker    freeArraysThatAreNotMallocedByUsers(glyphPtr, glyphs);
302*c8dee2aaSAndroid Build Coastguard Worker    if (!blob) {
303*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not make textblob from glyphs "' + glyphs + '"');
304*c8dee2aaSAndroid Build Coastguard Worker      return null;
305*c8dee2aaSAndroid Build Coastguard Worker    }
306*c8dee2aaSAndroid Build Coastguard Worker    return blob;
307*c8dee2aaSAndroid Build Coastguard Worker  };
308*c8dee2aaSAndroid Build Coastguard Worker
309*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.TextBlob.MakeFromText = function(str, font) {
310*c8dee2aaSAndroid Build Coastguard Worker    // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
311*c8dee2aaSAndroid Build Coastguard Worker    // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
312*c8dee2aaSAndroid Build Coastguard Worker    // Add 1 for null terminator
313*c8dee2aaSAndroid Build Coastguard Worker    var strLen = lengthBytesUTF8(str) + 1;
314*c8dee2aaSAndroid Build Coastguard Worker    var strPtr = CanvasKit._malloc(strLen);
315*c8dee2aaSAndroid Build Coastguard Worker    // Add 1 for the null terminator.
316*c8dee2aaSAndroid Build Coastguard Worker    stringToUTF8(str, strPtr, strLen);
317*c8dee2aaSAndroid Build Coastguard Worker
318*c8dee2aaSAndroid Build Coastguard Worker    var blob = CanvasKit.TextBlob._MakeFromText(strPtr, strLen - 1, font);
319*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(strPtr);
320*c8dee2aaSAndroid Build Coastguard Worker    if (!blob) {
321*c8dee2aaSAndroid Build Coastguard Worker      Debug('Could not make textblob from string "' + str + '"');
322*c8dee2aaSAndroid Build Coastguard Worker      return null;
323*c8dee2aaSAndroid Build Coastguard Worker    }
324*c8dee2aaSAndroid Build Coastguard Worker    return blob;
325*c8dee2aaSAndroid Build Coastguard Worker  };
326*c8dee2aaSAndroid Build Coastguard Worker
327*c8dee2aaSAndroid Build Coastguard Worker  // A helper to return the right type for GlyphIDs stored internally. When that changes, this
328*c8dee2aaSAndroid Build Coastguard Worker  // will also be changed, which will help avoid future breakages.
329*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit.MallocGlyphIDs = function(numGlyphIDs) {
330*c8dee2aaSAndroid Build Coastguard Worker    return CanvasKit.Malloc(Uint16Array, numGlyphIDs);
331*c8dee2aaSAndroid Build Coastguard Worker  }
332*c8dee2aaSAndroid Build Coastguard Worker});
333