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