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