• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1(function(CanvasKit){
2  CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
3  CanvasKit._extraInitializations.push(function() {
4
5    CanvasKit.Paragraph.prototype.getRectsForRange = function(start, end, hStyle, wStyle) {
6    /**
7     * This is bytes, but we'll want to think about them as float32s
8     * @type {Float32Array}
9     */
10      var floatArray = this._getRectsForRange(start, end, hStyle, wStyle);
11      return floatArrayToRects(floatArray);
12    }
13
14    CanvasKit.Paragraph.prototype.getRectsForPlaceholders = function() {
15        /**
16        * This is bytes, but we'll want to think about them as float32s
17        * @type {Float32Array}
18        */
19        var floatArray = this._getRectsForPlaceholders();
20        return floatArrayToRects(floatArray);
21    }
22
23    function floatArrayToRects(floatArray) {
24        if (!floatArray || !floatArray.length) {
25            return [];
26        }
27        var ret = [];
28        for (var i = 0; i < floatArray.length; i+=5) {
29            var r = CanvasKit.LTRBRect(floatArray[i], floatArray[i+1], floatArray[i+2], floatArray[i+3]);
30            if (floatArray[i+4] === 0) {
31                r['direction'] = CanvasKit.TextDirection.RTL;
32            } else {
33                r['direction'] = CanvasKit.TextDirection.LTR;
34            }
35            ret.push(r);
36        }
37        CanvasKit._free(floatArray.byteOffset);
38        return ret;
39    }
40
41    // Registers the font (provided as an arrayBuffer) with the alias `family`.
42    CanvasKit.TypefaceFontProvider.prototype.registerFont = function(font, family) {
43      var typeface = CanvasKit.FontMgr.RefDefault().MakeTypefaceFromData(font);
44      if (!typeface) {
45          Debug('Could not decode font data');
46          // We do not need to free the data since the C++ will do that for us
47          // when the font is deleted (or fails to decode);
48          return null;
49      }
50      var familyPtr = cacheOrCopyString(family);
51      this._registerFont(typeface, familyPtr);
52    }
53
54    // These helpers fill out all fields, because emscripten complains if we
55    // have undefined and it expects, for example, a float.
56    // TODO(kjlubick) For efficiency, we should probably just return opaque WASM objects so we do
57    //   not have to keep copying them across the wire.
58    CanvasKit.ParagraphStyle = function(s) {
59      // Use [''] to tell closure not to minify the names
60      s['disableHinting'] = s['disableHinting'] || false;
61      if (s['ellipsis']) {
62        var str = s['ellipsis'];
63        s['_ellipsisPtr'] = cacheOrCopyString(str);
64        s['_ellipsisLen'] = lengthBytesUTF8(str) + 1; // add 1 for the null terminator.
65      } else {
66        s['_ellipsisPtr'] = nullptr;
67        s['_ellipsisLen'] = 0;
68      }
69
70      s['heightMultiplier'] = s['heightMultiplier'] || 0;
71      s['maxLines'] = s['maxLines'] || 0;
72      s['strutStyle'] = strutStyle(s['strutStyle']);
73      s['textAlign'] = s['textAlign'] || CanvasKit.TextAlign.Start;
74      s['textDirection'] = s['textDirection'] || CanvasKit.TextDirection.LTR;
75      s['textHeightBehavior'] = s['textHeightBehavior'] || CanvasKit.TextHeightBehavior.All;
76      s['textStyle'] = CanvasKit.TextStyle(s['textStyle']);
77      return s;
78    };
79
80    function fontStyle(s) {
81      s = s || {};
82      // Can't check for falsey as 0 width means "invisible".
83      if (s['weight'] === undefined) {
84        s['weight'] = CanvasKit.FontWeight.Normal;
85      }
86      s['width'] = s['width'] || CanvasKit.FontWidth.Normal;
87      s['slant'] = s['slant'] || CanvasKit.FontSlant.Upright;
88      return s;
89    }
90
91    function strutStyle(s) {
92        s = s || {};
93        s['strutEnabled'] = s['strutEnabled'] || false;
94
95        if (s['strutEnabled'] && Array.isArray(s['fontFamilies']) && s['fontFamilies'].length) {
96            s['_fontFamiliesPtr'] = naiveCopyStrArray(s['fontFamilies']);
97            s['_fontFamiliesLen'] = s['fontFamilies'].length;
98        } else {
99            s['_fontFamiliesPtr'] = nullptr;
100            s['_fontFamiliesLen'] = 0;
101        }
102        s['fontStyle'] = fontStyle(s['fontStyle']);
103        s['fontSize'] = s['fontSize'] || 0;
104        s['heightMultiplier'] = s['heightMultiplier'] || 0;
105        s['halfLeading'] = s['halfLeading'] || false;
106        s['leading'] = s['leading'] || 0;
107        s['forceStrutHeight'] = s['forceStrutHeight'] || false;
108        return s;
109    }
110
111    CanvasKit.TextStyle = function(s) {
112       // Use [''] to tell closure not to minify the names
113      if (!s['color']) {
114        s['color'] = CanvasKit.BLACK;
115      }
116
117      s['decoration'] = s['decoration'] || 0;
118      s['decorationThickness'] = s['decorationThickness'] || 0;
119      s['decorationStyle'] = s['decorationStyle'] || CanvasKit.DecorationStyle.Solid;
120      s['textBaseline'] = s['textBaseline'] || CanvasKit.TextBaseline.Alphabetic;
121      s['fontSize'] = s['fontSize'] || 0;
122      s['letterSpacing'] = s['letterSpacing'] || 0;
123      s['wordSpacing'] = s['wordSpacing'] || 0;
124      s['heightMultiplier'] = s['heightMultiplier'] || 0;
125      s['halfLeading'] = s['halfLeading'] || false;
126      if (s['locale']) {
127        var str = s['locale'];
128        s['_localePtr'] = cacheOrCopyString(str);
129        s['_localeLen'] = lengthBytesUTF8(str) + 1; // add 1 for the null terminator.
130      } else {
131        s['_localePtr'] = nullptr;
132        s['_localeLen'] = 0;
133      }
134      s['fontStyle'] = fontStyle(s['fontStyle']);
135      if (s['shadows']) {
136        var shadows = s['shadows'];
137        var shadowColors = shadows.map(function(s) { return s['color'] || CanvasKit.BLACK; });
138        var shadowBlurRadii = shadows.map(function(s) { return s['blurRadius'] || 0.0; });
139        s['_shadowLen'] = shadows.length;
140        var ptr = CanvasKit._malloc(shadows.length * 2, 'HEAPF32');
141        var adjustedPtr = ptr / 4;  // 4 bytes per float
142        for (var i = 0; i < shadows.length; i++) {
143          var offset = shadows[i]['offset'] || [0, 0];
144          CanvasKit.HEAPF32[adjustedPtr] = offset[0];
145          CanvasKit.HEAPF32[adjustedPtr + 1] = offset[1];
146          adjustedPtr += 2;
147        }
148        s['_shadowColorsPtr'] = copyFlexibleColorArray(shadowColors).colorPtr;
149        s['_shadowOffsetsPtr'] = ptr;
150        s['_shadowBlurRadiiPtr'] = copy1dArray(shadowBlurRadii, 'HEAPF32');
151      } else {
152        s['_shadowLen'] = 0;
153        s['_shadowColorsPtr'] = nullptr;
154        s['_shadowOffsetsPtr'] = nullptr;
155        s['_shadowBlurRadiiPtr'] = nullptr;
156      }
157      if (s['fontFeatures']) {
158        var fontFeatures = s['fontFeatures'];
159        var fontFeatureNames = fontFeatures.map(function(s) { return s['name']; });
160        var fontFeatureValues = fontFeatures.map(function(s) { return s['value']; });
161        s['_fontFeatureLen'] = fontFeatures.length;
162        s['_fontFeatureNamesPtr'] = naiveCopyStrArray(fontFeatureNames);
163        s['_fontFeatureValuesPtr'] = copy1dArray(fontFeatureValues, 'HEAPU32');
164      } else {
165        s['_fontFeatureLen'] = 0;
166        s['_fontFeatureNamesPtr'] = nullptr;
167        s['_fontFeatureValuesPtr'] = nullptr;
168      }
169
170      return s;
171    };
172
173    // returns a pointer to a place on the heap that has an array
174    // of char* (effectively a char**). For now, this does the naive thing
175    // and depends on the string being null-terminated. This should be used
176    // for simple, well-formed things (e.g. font-families), not arbitrary
177    // text that should be drawn. If we need this to handle more complex
178    // strings, it should return two pointers, a pointer of the
179    // string array and a pointer to an array of the strings byte lengths.
180    function naiveCopyStrArray(strings) {
181      if (!strings || !strings.length) {
182        return nullptr;
183      }
184      var sPtrs = [];
185      for (var i = 0; i < strings.length; i++) {
186        var strPtr = cacheOrCopyString(strings[i]);
187        sPtrs.push(strPtr);
188      }
189      return copy1dArray(sPtrs, 'HEAPU32');
190    }
191
192    // maps string -> malloc'd pointer
193    var stringCache = {};
194
195    // cacheOrCopyString copies a string from JS into WASM on the heap and returns the pointer
196    // to the memory of the string. It is expected that a caller to this helper will *not* free
197    // that memory, so it is cached. Thus, if a future call to this function with the same string
198    // will return the cached pointer, preventing the memory usage from growing unbounded (in
199    // a normal use case).
200    function cacheOrCopyString(str) {
201      if (stringCache[str]) {
202        return stringCache[str];
203      }
204      // Add 1 for null terminator, which we need when copying/converting
205      var strLen = lengthBytesUTF8(str) + 1;
206      var strPtr = CanvasKit._malloc(strLen);
207      stringToUTF8(str, strPtr, strLen);
208      stringCache[str] = strPtr;
209      return strPtr;
210    }
211
212    // These scratch arrays are allocated once to copy the color data into, which saves us
213    // having to free them after every invocation.
214    var scratchForegroundColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats
215    var scratchBackgroundColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats
216    var scratchDecorationColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats
217
218    function copyArrays(textStyle) {
219      // These color fields were arrays, but will set to WASM pointers before we pass this
220      // object over the WASM interface.
221      textStyle['_colorPtr'] = copyColorToWasm(textStyle['color']);
222      textStyle['_foregroundColorPtr'] = nullptr; // nullptr is 0, from helper.js
223      textStyle['_backgroundColorPtr'] = nullptr;
224      textStyle['_decorationColorPtr'] = nullptr;
225      if (textStyle['foregroundColor']) {
226        textStyle['_foregroundColorPtr'] = copyColorToWasm(textStyle['foregroundColor'], scratchForegroundColorPtr);
227      }
228      if (textStyle['backgroundColor']) {
229        textStyle['_backgroundColorPtr'] = copyColorToWasm(textStyle['backgroundColor'], scratchBackgroundColorPtr);
230      }
231      if (textStyle['decorationColor']) {
232        textStyle['_decorationColorPtr'] = copyColorToWasm(textStyle['decorationColor'], scratchDecorationColorPtr);
233      }
234
235      if (Array.isArray(textStyle['fontFamilies']) && textStyle['fontFamilies'].length) {
236        textStyle['_fontFamiliesPtr'] = naiveCopyStrArray(textStyle['fontFamilies']);
237        textStyle['_fontFamiliesLen'] = textStyle['fontFamilies'].length;
238      } else {
239        textStyle['_fontFamiliesPtr'] = nullptr;
240        textStyle['_fontFamiliesLen'] = 0;
241        Debug('no font families provided, text may draw wrong or not at all');
242      }
243    }
244
245    function freeArrays(textStyle) {
246      // The font family strings will get copied to a vector on the C++ side, which is owned by
247      // the text style.
248      CanvasKit._free(textStyle['_fontFamiliesPtr']);
249    }
250
251    CanvasKit.ParagraphBuilder.Make = function(paragraphStyle, fontManager) {
252      copyArrays(paragraphStyle['textStyle']);
253
254      var result =  CanvasKit.ParagraphBuilder._Make(paragraphStyle, fontManager);
255      freeArrays(paragraphStyle['textStyle']);
256      return result;
257    };
258
259    CanvasKit.ParagraphBuilder.MakeFromFontProvider = function(paragraphStyle, fontProvider) {
260        copyArrays(paragraphStyle['textStyle']);
261
262        var result =  CanvasKit.ParagraphBuilder._MakeFromFontProvider(paragraphStyle, fontProvider);
263        freeArrays(paragraphStyle['textStyle']);
264        return result;
265    };
266
267    CanvasKit.ParagraphBuilder.ShapeText = function(text, blocks, width) {
268        let length = 0;
269        for (const b of blocks) {
270            length += b.length;
271        }
272        if (length !== text.length) {
273            throw "Accumulated block lengths must equal text.length";
274        }
275        return CanvasKit.ParagraphBuilder._ShapeText(text, blocks, width);
276    };
277
278    CanvasKit.ParagraphBuilder.prototype.pushStyle = function(textStyle) {
279      copyArrays(textStyle);
280      this._pushStyle(textStyle);
281      freeArrays(textStyle);
282    };
283
284    CanvasKit.ParagraphBuilder.prototype.pushPaintStyle = function(textStyle, fg, bg) {
285      copyArrays(textStyle);
286      this._pushPaintStyle(textStyle, fg, bg);
287      freeArrays(textStyle);
288    };
289
290    CanvasKit.ParagraphBuilder.prototype.addPlaceholder =
291          function(width, height, alignment, baseline, offset) {
292      width = width || 0;
293      height = height || 0;
294      alignment = alignment || CanvasKit.PlaceholderAlignment.Baseline;
295      baseline = baseline || CanvasKit.TextBaseline.Alphabetic;
296      offset = offset || 0;
297      this._addPlaceholder(width, height, alignment, baseline, offset);
298    };
299});
300}(Module)); // When this file is loaded in, the high level object is "Module";
301