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