• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
2CanvasKit._extraInitializations.push(function() {
3
4  // str can be either a text string or a ShapedText object
5  CanvasKit.SkCanvas.prototype.drawText = function(str, x, y, paint, font) {
6    if (typeof str === 'string') {
7      // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
8      // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
9      var strLen = lengthBytesUTF8(str);
10      // Add 1 for null terminator, which we need when copying/converting, but can ignore
11      // when we call into Skia.
12      var strPtr = CanvasKit._malloc(strLen + 1);
13      stringToUTF8(str, strPtr, strLen + 1);
14      this._drawSimpleText(strPtr, strLen, x, y, font, paint);
15    } else {
16      this._drawShapedText(str, x, y, paint);
17    }
18  }
19
20  // Returns an array of the widths of the glyphs in this string.
21  CanvasKit.SkFont.prototype.getWidths = function(str) {
22    // add 1 for null terminator
23    var codePoints = str.length + 1;
24    // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
25    // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
26    // Add 1 for null terminator
27    var strBytes = lengthBytesUTF8(str) + 1;
28    var strPtr = CanvasKit._malloc(strBytes);
29    stringToUTF8(str, strPtr, strBytes);
30
31    var bytesPerFloat = 4;
32    // allocate widths == numCodePoints
33    var widthPtr = CanvasKit._malloc(codePoints * bytesPerFloat);
34    if (!this._getWidths(strPtr, strBytes, codePoints, widthPtr)) {
35      SkDebug('Could not compute widths');
36      CanvasKit._free(strPtr);
37      CanvasKit._free(widthPtr);
38      return null;
39    }
40    // reminder, this shouldn't copy the data, just is a nice way to
41    // wrap 4 bytes together into a float.
42    var widths = new Float32Array(CanvasKit.HEAPU8.buffer, widthPtr, codePoints);
43    // This copies the data so we can free the CanvasKit memory
44    var retVal = Array.from(widths);
45    CanvasKit._free(strPtr);
46    CanvasKit._free(widthPtr);
47    return retVal;
48  }
49
50  // arguments should all be arrayBuffers or be an array of arrayBuffers.
51  CanvasKit.SkFontMgr.FromData = function() {
52    if (!arguments.length) {
53      SkDebug('Could not make SkFontMgr from no font sources');
54      return null;
55    }
56    var fonts = arguments;
57    if (fonts.length === 1 && Array.isArray(fonts[0])) {
58      fonts = arguments[0];
59    }
60    if (!fonts.length) {
61      SkDebug('Could not make SkFontMgr from no font sources');
62      return null;
63    }
64    var dPtrs = [];
65    var sizes = [];
66    for (var i = 0; i < fonts.length; i++) {
67      var data = new Uint8Array(fonts[i]);
68      var dptr = copy1dArray(data, CanvasKit.HEAPU8);
69      dPtrs.push(dptr);
70      sizes.push(data.byteLength);
71    }
72    // Pointers are 32 bit unsigned ints
73    var datasPtr = copy1dArray(dPtrs, CanvasKit.HEAPU32);
74    var sizesPtr = copy1dArray(sizes, CanvasKit.HEAPU32);
75    var fm = CanvasKit.SkFontMgr._fromData(datasPtr, sizesPtr, fonts.length);
76    // The SkFontMgr has taken ownership of the bytes we allocated in the for loop.
77    CanvasKit._free(datasPtr);
78    CanvasKit._free(sizesPtr);
79    return fm;
80  }
81
82  // fontData should be an arrayBuffer
83  CanvasKit.SkFontMgr.prototype.MakeTypefaceFromData = function(fontData) {
84    var data = new Uint8Array(fontData);
85
86    var fptr = copy1dArray(data, CanvasKit.HEAPU8);
87    var font = this._makeTypefaceFromData(fptr, data.byteLength);
88    if (!font) {
89      SkDebug('Could not decode font data');
90      // We do not need to free the data since the C++ will do that for us
91      // when the font is deleted (or fails to decode);
92      return null;
93    }
94    return font;
95  }
96
97  CanvasKit.SkTextBlob.MakeOnPath = function(str, path, font, initialOffset) {
98    if (!str || !str.length) {
99      SkDebug('ignoring 0 length string');
100      return;
101    }
102    if (!path || !path.countPoints()) {
103      SkDebug('ignoring empty path');
104      return;
105    }
106    if (path.countPoints() === 1) {
107      SkDebug('path has 1 point, returning normal textblob');
108      return this.MakeFromText(str, font);
109    }
110
111    if (!initialOffset) {
112      initialOffset = 0;
113    }
114
115    var widths = font.getWidths(str);
116
117    var rsx = new CanvasKit.RSXFormBuilder();
118    var meas = new CanvasKit.SkPathMeasure(path, false, 1);
119    var dist = initialOffset;
120    for (var i = 0; i < str.length; i++) {
121      var width = widths[i];
122      dist += width/2;
123      if (dist > meas.getLength()) {
124        // jump to next contour
125        if (!meas.nextContour()) {
126          // We have come to the end of the path - terminate the string
127          // right here.
128          str = str.substring(0, i);
129          break;
130        }
131        dist = width/2;
132      }
133
134      // Gives us the (x, y) coordinates as well as the cos/sin of the tangent
135      // line at that position.
136      var xycs = meas.getPosTan(dist);
137      var cx = xycs[0];
138      var cy = xycs[1];
139      var cosT = xycs[2];
140      var sinT = xycs[3];
141
142      var adjustedX = cx - (width/2 * cosT);
143      var adjustedY = cy - (width/2 * sinT);
144
145      rsx.push(cosT, sinT, adjustedX, adjustedY);
146      dist += width/2;
147    }
148    var retVal = this.MakeFromRSXform(str, rsx, font);
149    rsx.delete();
150    meas.delete();
151    return retVal;
152  }
153
154  CanvasKit.SkTextBlob.MakeFromRSXform = function(str, rsxBuilder, font) {
155    // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
156    // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
157    // Add 1 for null terminator
158    var strLen = lengthBytesUTF8(str) + 1;
159    var strPtr = CanvasKit._malloc(strLen);
160    // Add 1 for the null terminator.
161    stringToUTF8(str, strPtr, strLen);
162    var rptr = rsxBuilder.build();
163
164    var blob = CanvasKit.SkTextBlob._MakeFromRSXform(strPtr, strLen - 1,
165                          rptr, font, CanvasKit.TextEncoding.UTF8);
166    if (!blob) {
167      SkDebug('Could not make textblob from string "' + str + '"');
168      return null;
169    }
170
171    var origDelete = blob.delete.bind(blob);
172    blob.delete = function() {
173      CanvasKit._free(strPtr);
174      origDelete();
175    }
176    return blob;
177  }
178
179  CanvasKit.SkTextBlob.MakeFromText = function(str, font) {
180    // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
181    // JS.  See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
182    // Add 1 for null terminator
183    var strLen = lengthBytesUTF8(str) + 1;
184    var strPtr = CanvasKit._malloc(strLen);
185    // Add 1 for the null terminator.
186    stringToUTF8(str, strPtr, strLen);
187
188    var blob = CanvasKit.SkTextBlob._MakeFromText(strPtr, strLen - 1, font, CanvasKit.TextEncoding.UTF8);
189    if (!blob) {
190      SkDebug('Could not make textblob from string "' + str + '"');
191      return null;
192    }
193
194    var origDelete = blob.delete.bind(blob);
195    blob.delete = function() {
196      CanvasKit._free(strPtr);
197      origDelete();
198    }
199    return blob;
200  }
201});
202