blob: ec94746c81faba9eaeffc0a25cf42dcc35e2b9fd [file] [log] [blame]
Kevin Lubick369f6a52019-10-03 11:22:08 -04001(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);
Harry Terkelsen223ffcd2020-10-02 15:24:13 -070011 return floatArrayToRects(floatArray);
12 }
Kevin Lubick369f6a52019-10-03 11:22:08 -040013
Harry Terkelsen223ffcd2020-10-02 15:24:13 -070014 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 [];
Kevin Lubick4a5f4f22019-11-20 08:27:10 -050026 }
Harry Terkelsen223ffcd2020-10-02 15:24:13 -070027 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;
Kevin Lubick369f6a52019-10-03 11:22:08 -040039 }
40
Harry Terkelsen10f019c2020-08-04 13:21:09 -070041 // Registers the font (provided as an arrayBuffer) with the alias `family`.
42 CanvasKit.TypefaceFontProvider.prototype.registerFont = function(font, family) {
Kevin Lubick54c1b3d2020-10-07 16:09:22 -040043 var typeface = CanvasKit.FontMgr.RefDefault().MakeTypefaceFromData(font);
Harry Terkelsen10f019c2020-08-04 13:21:09 -070044 if (!typeface) {
Kevin Lubick54c1b3d2020-10-07 16:09:22 -040045 Debug('Could not decode font data');
Harry Terkelsen10f019c2020-08-04 13:21:09 -070046 // 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
Kevin Lubick369f6a52019-10-03 11:22:08 -040054 // These helpers fill out all fields, because emscripten complains if we
55 // have undefined and it expects, for example, a float.
Kevin Lubickc488fd32020-10-06 08:24:00 -040056 // 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.
Kevin Lubick369f6a52019-10-03 11:22:08 -040058 CanvasKit.ParagraphStyle = function(s) {
59 // Use [''] to tell closure not to minify the names
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040060 s['disableHinting'] = s['disableHinting'] || false;
61 if (s['ellipsis']) {
62 var str = s['ellipsis'];
Kevin Lubick0c8884b2020-05-14 08:27:53 -040063 s['_ellipsisPtr'] = cacheOrCopyString(str);
64 s['_ellipsisLen'] = lengthBytesUTF8(str) + 1; // add 1 for the null terminator.
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040065 } else {
66 s['_ellipsisPtr'] = nullptr;
67 s['_ellipsisLen'] = 0;
68 }
69
Kevin Lubick369f6a52019-10-03 11:22:08 -040070 s['heightMultiplier'] = s['heightMultiplier'] || 0;
71 s['maxLines'] = s['maxLines'] || 0;
72 s['textAlign'] = s['textAlign'] || CanvasKit.TextAlign.Start;
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040073 s['textDirection'] = s['textDirection'] || CanvasKit.TextDirection.LTR;
Kevin Lubick369f6a52019-10-03 11:22:08 -040074 s['textStyle'] = CanvasKit.TextStyle(s['textStyle']);
Harry Terkelsen223ffcd2020-10-02 15:24:13 -070075 s['strutStyle'] = strutStyle(s['strutStyle']);
Kevin Lubick369f6a52019-10-03 11:22:08 -040076 return s;
Kevin Lubick0c8884b2020-05-14 08:27:53 -040077 };
Kevin Lubick369f6a52019-10-03 11:22:08 -040078
Kevin Lubickd3b1fe62019-10-21 10:50:26 -040079 function fontStyle(s) {
80 s = s || {};
81 // Can't check for falsey as 0 width means "invisible".
82 if (s['weight'] === undefined) {
83 s['weight'] = CanvasKit.FontWeight.Normal;
84 }
85 s['width'] = s['width'] || CanvasKit.FontWidth.Normal;
86 s['slant'] = s['slant'] || CanvasKit.FontSlant.Upright;
87 return s;
88 }
89
Harry Terkelsen223ffcd2020-10-02 15:24:13 -070090 function strutStyle(s) {
91 s = s || {};
92 s['strutEnabled'] = s['strutEnabled'] || false;
93
94 if (s['strutEnabled'] && Array.isArray(s['fontFamilies']) && s['fontFamilies'].length) {
95 s['_fontFamiliesPtr'] = naiveCopyStrArray(s['fontFamilies']);
96 s['_fontFamiliesLen'] = s['fontFamilies'].length;
97 } else {
98 s['_fontFamiliesPtr'] = nullptr;
99 s['_fontFamiliesLen'] = 0;
100 }
101 s['fontStyle'] = fontStyle(s['fontStyle']);
102 s['fontSize'] = s['fontSize'] || 0;
103 s['heightMultiplier'] = s['heightMultiplier'] || 0;
104 s['leading'] = s['leading'] || 0;
105 s['forceStrutHeight'] = s['forceStrutHeight'] || false;
106 return s;
107 }
108
Kevin Lubick369f6a52019-10-03 11:22:08 -0400109 CanvasKit.TextStyle = function(s) {
110 // Use [''] to tell closure not to minify the names
Kevin Lubick26133322020-06-11 13:48:16 -0400111 if (!s['color']) {
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400112 s['color'] = CanvasKit.BLACK;
113 }
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400114
Kevin Lubick369f6a52019-10-03 11:22:08 -0400115 s['decoration'] = s['decoration'] || 0;
116 s['decorationThickness'] = s['decorationThickness'] || 0;
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700117 s['decorationStyle'] = s['decorationStyle'] || CanvasKit.DecorationStyle.Solid;
118 s['textBaseline'] = s['textBaseline'] || CanvasKit.TextBaseline.Alphabetic;
Kevin Lubick369f6a52019-10-03 11:22:08 -0400119 s['fontSize'] = s['fontSize'] || 0;
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700120 s['letterSpacing'] = s['letterSpacing'] || 0;
121 s['wordSpacing'] = s['wordSpacing'] || 0;
122 s['heightMultiplier'] = s['heightMultiplier'] || 0;
123 if (s['locale']) {
124 var str = s['locale'];
125 s['_localePtr'] = cacheOrCopyString(str);
126 s['_localeLen'] = lengthBytesUTF8(str) + 1; // add 1 for the null terminator.
127 } else {
128 s['_localePtr'] = nullptr;
129 s['_localeLen'] = 0;
130 }
Kevin Lubickd3b1fe62019-10-21 10:50:26 -0400131 s['fontStyle'] = fontStyle(s['fontStyle']);
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700132 if (s['shadows']) {
133 var shadows = s['shadows'];
134 var shadowColors = shadows.map(function(s) { return s['color'] || CanvasKit.BLACK; });
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700135 var shadowBlurRadii = shadows.map(function(s) { return s['blurRadius'] || 0.0; });
136 s['_shadowLen'] = shadows.length;
Kevin Lubicke7c1a732020-12-04 09:10:39 -0500137 var ptr = CanvasKit._malloc(shadows.length * 2, 'HEAPF32');
138 var adjustedPtr = ptr / 4; // 4 bytes per float
139 for (var i = 0; i < shadows.length; i++) {
140 var offset = shadows[i]['offset'] || [0, 0];
141 CanvasKit.HEAPF32[adjustedPtr] = offset[0];
142 CanvasKit.HEAPF32[adjustedPtr + 1] = offset[1];
143 adjustedPtr += 2;
144 }
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700145 s['_shadowColorsPtr'] = copyFlexibleColorArray(shadowColors).colorPtr;
Kevin Lubicke7c1a732020-12-04 09:10:39 -0500146 s['_shadowOffsetsPtr'] = ptr;
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700147 s['_shadowBlurRadiiPtr'] = copy1dArray(shadowBlurRadii, 'HEAPF32');
148 } else {
149 s['_shadowLen'] = 0;
150 s['_shadowColorsPtr'] = nullptr;
151 s['_shadowOffsetsPtr'] = nullptr;
152 s['_shadowBlurRadiiPtr'] = nullptr;
153 }
154 if (s['fontFeatures']) {
155 var fontFeatures = s['fontFeatures'];
156 var fontFeatureNames = fontFeatures.map(function(s) { return s['name']; });
157 var fontFeatureValues = fontFeatures.map(function(s) { return s['value']; });
158 s['_fontFeatureLen'] = fontFeatures.length;
159 s['_fontFeatureNamesPtr'] = naiveCopyStrArray(fontFeatureNames);
160 s['_fontFeatureValuesPtr'] = copy1dArray(fontFeatureValues, 'HEAPU32');
161 } else {
162 s['_fontFeatureLen'] = 0;
163 s['_fontFeatureNamesPtr'] = nullptr;
164 s['_fontFeatureValuesPtr'] = nullptr;
165 }
166
Kevin Lubick369f6a52019-10-03 11:22:08 -0400167 return s;
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400168 };
Kevin Lubick369f6a52019-10-03 11:22:08 -0400169
170 // returns a pointer to a place on the heap that has an array
171 // of char* (effectively a char**). For now, this does the naive thing
172 // and depends on the string being null-terminated. This should be used
173 // for simple, well-formed things (e.g. font-families), not arbitrary
174 // text that should be drawn. If we need this to handle more complex
175 // strings, it should return two pointers, a pointer of the
176 // string array and a pointer to an array of the strings byte lengths.
177 function naiveCopyStrArray(strings) {
178 if (!strings || !strings.length) {
179 return nullptr;
180 }
181 var sPtrs = [];
182 for (var i = 0; i < strings.length; i++) {
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400183 var strPtr = cacheOrCopyString(strings[i]);
Kevin Lubick369f6a52019-10-03 11:22:08 -0400184 sPtrs.push(strPtr);
185 }
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700186 return copy1dArray(sPtrs, 'HEAPU32');
Kevin Lubick369f6a52019-10-03 11:22:08 -0400187 }
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400188
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400189 // maps string -> malloc'd pointer
190 var stringCache = {};
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400191
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400192 // cacheOrCopyString copies a string from JS into WASM on the heap and returns the pointer
193 // to the memory of the string. It is expected that a caller to this helper will *not* free
194 // that memory, so it is cached. Thus, if a future call to this function with the same string
195 // will return the cached pointer, preventing the memory usage from growing unbounded (in
196 // a normal use case).
197 function cacheOrCopyString(str) {
198 if (stringCache[str]) {
199 return stringCache[str];
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400200 }
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400201 // Add 1 for null terminator, which we need when copying/converting
202 var strLen = lengthBytesUTF8(str) + 1;
203 var strPtr = CanvasKit._malloc(strLen);
204 stringToUTF8(str, strPtr, strLen);
205 stringCache[str] = strPtr;
206 return strPtr;
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400207 }
208
Kevin Lubick6aa38692020-06-01 11:25:47 -0400209 // These scratch arrays are allocated once to copy the color data into, which saves us
210 // having to free them after every invocation.
211 var scratchForegroundColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats
212 var scratchBackgroundColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700213 var scratchDecorationColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats
Kevin Lubick6aa38692020-06-01 11:25:47 -0400214
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400215 function copyArrays(textStyle) {
216 // These color fields were arrays, but will set to WASM pointers before we pass this
217 // object over the WASM interface.
Kevin Lubick6aa38692020-06-01 11:25:47 -0400218 textStyle['_colorPtr'] = copyColorToWasm(textStyle['color']);
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400219 textStyle['_foregroundColorPtr'] = nullptr; // nullptr is 0, from helper.js
220 textStyle['_backgroundColorPtr'] = nullptr;
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700221 textStyle['_decorationColorPtr'] = nullptr;
Kevin Lubick6aa38692020-06-01 11:25:47 -0400222 if (textStyle['foregroundColor']) {
223 textStyle['_foregroundColorPtr'] = copyColorToWasm(textStyle['foregroundColor'], scratchForegroundColorPtr);
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400224 }
Kevin Lubick6aa38692020-06-01 11:25:47 -0400225 if (textStyle['backgroundColor']) {
226 textStyle['_backgroundColorPtr'] = copyColorToWasm(textStyle['backgroundColor'], scratchBackgroundColorPtr);
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400227 }
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700228 if (textStyle['decorationColor']) {
229 textStyle['_decorationColorPtr'] = copyColorToWasm(textStyle['decorationColor'], scratchDecorationColorPtr);
230 }
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400231
232 if (Array.isArray(textStyle['fontFamilies']) && textStyle['fontFamilies'].length) {
233 textStyle['_fontFamiliesPtr'] = naiveCopyStrArray(textStyle['fontFamilies']);
234 textStyle['_fontFamiliesLen'] = textStyle['fontFamilies'].length;
235 } else {
236 textStyle['_fontFamiliesPtr'] = nullptr;
237 textStyle['_fontFamiliesLen'] = 0;
Kevin Lubick54c1b3d2020-10-07 16:09:22 -0400238 Debug('no font families provided, text may draw wrong or not at all');
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400239 }
240 }
241
242 function freeArrays(textStyle) {
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400243 // The font family strings will get copied to a vector on the C++ side, which is owned by
244 // the text style.
245 CanvasKit._free(textStyle['_fontFamiliesPtr']);
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400246 }
247
248 CanvasKit.ParagraphBuilder.Make = function(paragraphStyle, fontManager) {
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400249 copyArrays(paragraphStyle['textStyle']);
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400250
251 var result = CanvasKit.ParagraphBuilder._Make(paragraphStyle, fontManager);
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400252 freeArrays(paragraphStyle['textStyle']);
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400253 return result;
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400254 };
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400255
Harry Terkelsen10f019c2020-08-04 13:21:09 -0700256 CanvasKit.ParagraphBuilder.MakeFromFontProvider = function(paragraphStyle, fontProvider) {
257 copyArrays(paragraphStyle['textStyle']);
258
259 var result = CanvasKit.ParagraphBuilder._MakeFromFontProvider(paragraphStyle, fontProvider);
260 freeArrays(paragraphStyle['textStyle']);
261 return result;
262 };
263
Nathaniel Nifong1bedbeb2020-05-04 16:46:17 -0400264 CanvasKit.ParagraphBuilder.prototype.pushStyle = function(textStyle) {
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400265 copyArrays(textStyle);
266 this._pushStyle(textStyle);
267 freeArrays(textStyle);
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700268 };
Nathaniel Nifonge09b3142020-08-04 09:06:54 -0400269
270 CanvasKit.ParagraphBuilder.prototype.pushPaintStyle = function(textStyle, fg, bg) {
271 copyArrays(textStyle);
272 this._pushPaintStyle(textStyle, fg, bg);
273 freeArrays(textStyle);
Harry Terkelsen223ffcd2020-10-02 15:24:13 -0700274 };
275
276 CanvasKit.ParagraphBuilder.prototype.addPlaceholder =
277 function(width, height, alignment, baseline, offset) {
278 width = width || 0;
279 height = height || 0;
280 alignment = alignment || CanvasKit.PlaceholderAlignment.Baseline;
281 baseline = baseline || CanvasKit.TextBaseline.Alphabetic;
282 offset = offset || 0;
283 this._addPlaceholder(width, height, alignment, baseline, offset);
284 };
Kevin Lubick369f6a52019-10-03 11:22:08 -0400285});
Kevin Lubick0c8884b2020-05-14 08:27:53 -0400286}(Module)); // When this file is loaded in, the high level object is "Module";