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 * @type {Float32Array} 8 */ 9 var floatArray = this._getRectsForRange(start, end, hStyle, wStyle); 10 return floatArrayToRects(floatArray); 11 } 12 13 CanvasKit.Paragraph.prototype.getRectsForPlaceholders = function() { 14 /** 15 * @type {Float32Array} 16 */ 17 var floatArray = this._getRectsForPlaceholders(); 18 return floatArrayToRects(floatArray); 19 } 20 21 function floatArrayToRects(floatArray) { 22 if (!floatArray || !floatArray.length) { 23 return []; 24 } 25 var ret = []; 26 for (var i = 0; i < floatArray.length; i+=5) { 27 var rect = CanvasKit.LTRBRect(floatArray[i], floatArray[i+1], floatArray[i+2], floatArray[i+3]); 28 var dir = CanvasKit.TextDirection.LTR; 29 if (floatArray[i+4] === 0) { 30 dir = CanvasKit.TextDirection.RTL; 31 } 32 ret.push({'rect': rect, 'dir': dir}); 33 } 34 CanvasKit._free(floatArray.byteOffset); 35 return ret; 36 } 37 38 // Registers the font (provided as an arrayBuffer) with the alias `family`. 39 CanvasKit.TypefaceFontProvider.prototype.registerFont = function(font, family) { 40 var typeface = CanvasKit.Typeface.MakeFreeTypeFaceFromData(font); 41 if (!typeface) { 42 Debug('Could not decode font data'); 43 // We do not need to free the data since the C++ will do that for us 44 // when the font is deleted (or fails to decode); 45 return null; 46 } 47 var familyPtr = cacheOrCopyString(family); 48 this._registerFont(typeface, familyPtr); 49 } 50 51 // These helpers fill out all fields, because emscripten complains if we 52 // have undefined and it expects, for example, a float. 53 // TODO(kjlubick) For efficiency, we should probably just return opaque WASM objects so we do 54 // not have to keep copying them across the wire. 55 CanvasKit.ParagraphStyle = function(s) { 56 // Use [''] to tell closure not to minify the names 57 s['disableHinting'] = s['disableHinting'] || false; 58 if (s['ellipsis']) { 59 var str = s['ellipsis']; 60 s['_ellipsisPtr'] = cacheOrCopyString(str); 61 s['_ellipsisLen'] = lengthBytesUTF8(str) + 1; // add 1 for the null terminator. 62 } else { 63 s['_ellipsisPtr'] = nullptr; 64 s['_ellipsisLen'] = 0; 65 } 66 67 if (s['heightMultiplier'] == null) { 68 s['heightMultiplier'] = -1 69 } 70 s['maxLines'] = s['maxLines'] || 0; 71 s['replaceTabCharacters'] = s['replaceTabCharacters'] || false; 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 if (s['fontSize'] == null) { 104 s['fontSize'] = -1 105 } 106 if (s['heightMultiplier'] == null) { 107 s['heightMultiplier'] = -1 108 } 109 s['halfLeading'] = s['halfLeading'] || false; 110 s['leading'] = s['leading'] || 0; 111 s['forceStrutHeight'] = s['forceStrutHeight'] || false; 112 return s; 113 } 114 115 CanvasKit.TextStyle = function(s) { 116 // Use [''] to tell closure not to minify the names 117 if (!s['color']) { 118 s['color'] = CanvasKit.BLACK; 119 } 120 121 s['decoration'] = s['decoration'] || 0; 122 s['decorationThickness'] = s['decorationThickness'] || 0; 123 s['decorationStyle'] = s['decorationStyle'] || CanvasKit.DecorationStyle.Solid; 124 s['textBaseline'] = s['textBaseline'] || CanvasKit.TextBaseline.Alphabetic; 125 if (s['fontSize'] == null) { 126 s['fontSize'] = -1 127 } 128 s['letterSpacing'] = s['letterSpacing'] || 0; 129 s['wordSpacing'] = s['wordSpacing'] || 0; 130 if (s['heightMultiplier'] == null) { 131 s['heightMultiplier'] = -1 132 } 133 s['halfLeading'] = s['halfLeading'] || false; 134 s['fontStyle'] = fontStyle(s['fontStyle']); 135 136 // Properties which need to be Malloc'ed are set in `copyArrays`. 137 138 return s; 139 }; 140 141 // returns a pointer to a place on the heap that has an array 142 // of char* (effectively a char**). For now, this does the naive thing 143 // and depends on the string being null-terminated. This should be used 144 // for simple, well-formed things (e.g. font-families), not arbitrary 145 // text that should be drawn. If we need this to handle more complex 146 // strings, it should return two pointers, a pointer of the 147 // string array and a pointer to an array of the strings byte lengths. 148 function naiveCopyStrArray(strings) { 149 if (!strings || !strings.length) { 150 return nullptr; 151 } 152 var sPtrs = []; 153 for (var i = 0; i < strings.length; i++) { 154 var strPtr = cacheOrCopyString(strings[i]); 155 sPtrs.push(strPtr); 156 } 157 return copy1dArray(sPtrs, 'HEAPU32'); 158 } 159 160 // maps string -> malloc'd pointer 161 var stringCache = {}; 162 163 // cacheOrCopyString copies a string from JS into WASM on the heap and returns the pointer 164 // to the memory of the string. It is expected that a caller to this helper will *not* free 165 // that memory, so it is cached. Thus, if a future call to this function with the same string 166 // will return the cached pointer, preventing the memory usage from growing unbounded (in 167 // a normal use case). 168 function cacheOrCopyString(str) { 169 if (stringCache[str]) { 170 return stringCache[str]; 171 } 172 // Add 1 for null terminator, which we need when copying/converting 173 var strLen = lengthBytesUTF8(str) + 1; 174 var strPtr = CanvasKit._malloc(strLen); 175 stringToUTF8(str, strPtr, strLen); 176 stringCache[str] = strPtr; 177 return strPtr; 178 } 179 180 // These scratch arrays are allocated once to copy the color data into, which saves us 181 // having to free them after every invocation. 182 var scratchForegroundColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats 183 var scratchBackgroundColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats 184 var scratchDecorationColorPtr = CanvasKit._malloc(4 * 4); // room for 4 32bit floats 185 186 function copyArrays(textStyle) { 187 // These color fields were arrays, but will set to WASM pointers before we pass this 188 // object over the WASM interface. 189 textStyle['_colorPtr'] = copyColorToWasm(textStyle['color']); 190 textStyle['_foregroundColorPtr'] = nullptr; // nullptr is 0, from helper.js 191 textStyle['_backgroundColorPtr'] = nullptr; 192 textStyle['_decorationColorPtr'] = nullptr; 193 if (textStyle['foregroundColor']) { 194 textStyle['_foregroundColorPtr'] = copyColorToWasm(textStyle['foregroundColor'], scratchForegroundColorPtr); 195 } 196 if (textStyle['backgroundColor']) { 197 textStyle['_backgroundColorPtr'] = copyColorToWasm(textStyle['backgroundColor'], scratchBackgroundColorPtr); 198 } 199 if (textStyle['decorationColor']) { 200 textStyle['_decorationColorPtr'] = copyColorToWasm(textStyle['decorationColor'], scratchDecorationColorPtr); 201 } 202 203 if (Array.isArray(textStyle['fontFamilies']) && textStyle['fontFamilies'].length) { 204 textStyle['_fontFamiliesPtr'] = naiveCopyStrArray(textStyle['fontFamilies']); 205 textStyle['_fontFamiliesLen'] = textStyle['fontFamilies'].length; 206 } else { 207 textStyle['_fontFamiliesPtr'] = nullptr; 208 textStyle['_fontFamiliesLen'] = 0; 209 Debug('no font families provided, text may draw wrong or not at all'); 210 } 211 212 if (textStyle['locale']) { 213 var str = textStyle['locale']; 214 textStyle['_localePtr'] = cacheOrCopyString(str); 215 textStyle['_localeLen'] = lengthBytesUTF8(str) + 1; // add 1 for the null terminator. 216 } else { 217 textStyle['_localePtr'] = nullptr; 218 textStyle['_localeLen'] = 0; 219 } 220 221 if (Array.isArray(textStyle['shadows']) && textStyle['shadows'].length) { 222 var shadows = textStyle['shadows']; 223 var shadowColors = shadows.map(function (s) { return s['color'] || CanvasKit.BLACK; }); 224 var shadowBlurRadii = shadows.map(function (s) { return s['blurRadius'] || 0.0; }); 225 textStyle['_shadowLen'] = shadows.length; 226 // 2 floats per point, 4 bytes per float 227 var ptr = CanvasKit._malloc(shadows.length * 2 * 4); 228 var adjustedPtr = ptr / 4; // 4 bytes per float 229 for (var i = 0; i < shadows.length; i++) { 230 var offset = shadows[i]['offset'] || [0, 0]; 231 CanvasKit.HEAPF32[adjustedPtr] = offset[0]; 232 CanvasKit.HEAPF32[adjustedPtr + 1] = offset[1]; 233 adjustedPtr += 2; 234 } 235 textStyle['_shadowColorsPtr'] = copyFlexibleColorArray(shadowColors).colorPtr; 236 textStyle['_shadowOffsetsPtr'] = ptr; 237 textStyle['_shadowBlurRadiiPtr'] = copy1dArray(shadowBlurRadii, 'HEAPF32'); 238 } else { 239 textStyle['_shadowLen'] = 0; 240 textStyle['_shadowColorsPtr'] = nullptr; 241 textStyle['_shadowOffsetsPtr'] = nullptr; 242 textStyle['_shadowBlurRadiiPtr'] = nullptr; 243 } 244 245 if (Array.isArray(textStyle['fontFeatures']) && textStyle['fontFeatures'].length) { 246 var fontFeatures = textStyle['fontFeatures']; 247 var fontFeatureNames = fontFeatures.map(function (s) { return s['name']; }); 248 var fontFeatureValues = fontFeatures.map(function (s) { return s['value']; }); 249 textStyle['_fontFeatureLen'] = fontFeatures.length; 250 textStyle['_fontFeatureNamesPtr'] = naiveCopyStrArray(fontFeatureNames); 251 textStyle['_fontFeatureValuesPtr'] = copy1dArray(fontFeatureValues, 'HEAPU32'); 252 } else { 253 textStyle['_fontFeatureLen'] = 0; 254 textStyle['_fontFeatureNamesPtr'] = nullptr; 255 textStyle['_fontFeatureValuesPtr'] = nullptr; 256 } 257 258 if (Array.isArray(textStyle['fontVariations']) && textStyle['fontVariations'].length) { 259 var fontVariations = textStyle['fontVariations']; 260 var fontVariationAxes = fontVariations.map(function (s) { return s['axis']; }); 261 var fontVariationValues = fontVariations.map(function (s) { return s['value']; }); 262 textStyle['_fontVariationLen'] = fontVariations.length; 263 textStyle['_fontVariationAxesPtr'] = naiveCopyStrArray(fontVariationAxes); 264 textStyle['_fontVariationValuesPtr'] = copy1dArray(fontVariationValues, 'HEAPF32'); 265 } else { 266 textStyle['_fontVariationLen'] = 0; 267 textStyle['_fontVariationAxesPtr'] = nullptr; 268 textStyle['_fontVariationValuesPtr'] = nullptr; 269 } 270 } 271 272 function freeArrays(textStyle) { 273 // The font family strings will get copied to a vector on the C++ side, which is owned by 274 // the text style. 275 CanvasKit._free(textStyle['_fontFamiliesPtr']); 276 CanvasKit._free(textStyle['_shadowColorsPtr']); 277 CanvasKit._free(textStyle['_shadowOffsetsPtr']); 278 CanvasKit._free(textStyle['_shadowBlurRadiiPtr']); 279 CanvasKit._free(textStyle['_fontFeatureNamesPtr']); 280 CanvasKit._free(textStyle['_fontFeatureValuesPtr']); 281 } 282 283 CanvasKit.ParagraphBuilder.Make = function(paragraphStyle, fontManager) { 284 copyArrays(paragraphStyle['textStyle']); 285 286 var result = CanvasKit.ParagraphBuilder._Make(paragraphStyle, fontManager); 287 freeArrays(paragraphStyle['textStyle']); 288 return result; 289 }; 290 291 CanvasKit.ParagraphBuilder.MakeFromFontProvider = function(paragraphStyle, fontProvider) { 292 copyArrays(paragraphStyle['textStyle']); 293 294 var result = CanvasKit.ParagraphBuilder._MakeFromFontProvider(paragraphStyle, fontProvider); 295 freeArrays(paragraphStyle['textStyle']); 296 return result; 297 }; 298 299 CanvasKit.ParagraphBuilder.ShapeText = function(text, blocks, width) { 300 let length = 0; 301 for (const b of blocks) { 302 length += b.length; 303 } 304 if (length !== text.length) { 305 throw "Accumulated block lengths must equal text.length"; 306 } 307 return CanvasKit.ParagraphBuilder._ShapeText(text, blocks, width); 308 }; 309 310 CanvasKit.ParagraphBuilder.prototype.pushStyle = function(textStyle) { 311 copyArrays(textStyle); 312 this._pushStyle(textStyle); 313 freeArrays(textStyle); 314 }; 315 316 CanvasKit.ParagraphBuilder.prototype.pushPaintStyle = function(textStyle, fg, bg) { 317 copyArrays(textStyle); 318 this._pushPaintStyle(textStyle, fg, bg); 319 freeArrays(textStyle); 320 }; 321 322 CanvasKit.ParagraphBuilder.prototype.addPlaceholder = 323 function(width, height, alignment, baseline, offset) { 324 width = width || 0; 325 height = height || 0; 326 alignment = alignment || CanvasKit.PlaceholderAlignment.Baseline; 327 baseline = baseline || CanvasKit.TextBaseline.Alphabetic; 328 offset = offset || 0; 329 this._addPlaceholder(width, height, alignment, baseline, offset); 330 }; 331 332 CanvasKit.ParagraphBuilder.prototype.setWordsUtf8 = function(words) { 333 var bPtr = copy1dArray(words, 'HEAPU32'); 334 this._setWordsUtf8(bPtr, words && words.length || 0); 335 freeArraysThatAreNotMallocedByUsers(bPtr, words); 336 }; 337 CanvasKit.ParagraphBuilder.prototype.setWordsUtf16 = function(words) { 338 var bPtr = copy1dArray(words, 'HEAPU32'); 339 this._setWordsUtf16(bPtr, words && words.length || 0); 340 freeArraysThatAreNotMallocedByUsers(bPtr, words); 341 }; 342 343 CanvasKit.ParagraphBuilder.prototype.setGraphemeBreaksUtf8 = function(graphemeBreaks) { 344 var bPtr = copy1dArray(graphemeBreaks, 'HEAPU32'); 345 this._setGraphemeBreaksUtf8(bPtr, graphemeBreaks && graphemeBreaks.length || 0); 346 freeArraysThatAreNotMallocedByUsers(bPtr, graphemeBreaks); 347 }; 348 CanvasKit.ParagraphBuilder.prototype.setGraphemeBreaksUtf16 = function(graphemeBreaks) { 349 var bPtr = copy1dArray(graphemeBreaks, 'HEAPU32'); 350 this._setGraphemeBreaksUtf16(bPtr, graphemeBreaks && graphemeBreaks.length || 0); 351 freeArraysThatAreNotMallocedByUsers(bPtr, graphemeBreaks); 352 }; 353 354 CanvasKit.ParagraphBuilder.prototype.setLineBreaksUtf8 = function(lineBreaks) { 355 var bPtr = copy1dArray(lineBreaks, 'HEAPU32'); 356 this._setLineBreaksUtf8(bPtr, lineBreaks && lineBreaks.length || 0); 357 freeArraysThatAreNotMallocedByUsers(bPtr, lineBreaks); 358 }; 359 CanvasKit.ParagraphBuilder.prototype.setLineBreaksUtf16 = function(lineBreaks) { 360 var bPtr = copy1dArray(lineBreaks, 'HEAPU32'); 361 this._setLineBreaksUtf16(bPtr, lineBreaks && lineBreaks.length || 0); 362 freeArraysThatAreNotMallocedByUsers(bPtr, lineBreaks); 363 }; 364}); 365}(Module)); // When this file is loaded in, the high level object is "Module"; 366