1// Adds compile-time JS functions to augment the CanvasKit interface. 2// Implementations in this file are considerate of GPU builds, i.e. some 3// behavior is predicated on whether or not this is being compiled alongside 4// webgl.js or webgpu.js. 5(function(CanvasKit){ 6 CanvasKit._extraInitializations = CanvasKit._extraInitializations || []; 7 CanvasKit._extraInitializations.push(function() { 8 // Takes in an html id or a canvas element 9 CanvasKit.MakeSWCanvasSurface = function(idOrElement) { 10 var canvas = idOrElement; 11 var isHTMLCanvas = typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement; 12 var isOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas; 13 if (!isHTMLCanvas && !isOffscreenCanvas) { 14 canvas = document.getElementById(idOrElement); 15 if (!canvas) { 16 throw 'Canvas with id ' + idOrElement + ' was not found'; 17 } 18 } 19 // Maybe better to use clientWidth/height. See: 20 // https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html 21 var surface = CanvasKit.MakeSurface(canvas.width, canvas.height); 22 if (surface) { 23 surface._canvas = canvas; 24 } 25 return surface; 26 }; 27 28 // Don't over-write the MakeCanvasSurface set by gpu.js if it exists. 29 if (!CanvasKit.MakeCanvasSurface) { 30 CanvasKit.MakeCanvasSurface = CanvasKit.MakeSWCanvasSurface; 31 } 32 33 // Note that color spaces are currently not supported in CPU surfaces. due to the limitation 34 // canvas.getContext('2d').putImageData imposes a limitation of using an RGBA_8888 color type. 35 // TODO(nifong): support WGC color spaces while still using an RGBA_8888 color type when 36 // on a cpu backend. 37 CanvasKit.MakeSurface = function(width, height) { 38 var imageInfo = { 39 'width': width, 40 'height': height, 41 'colorType': CanvasKit.ColorType.RGBA_8888, 42 // Since we are sending these pixels directly into the HTML canvas, 43 // (and those pixels are un-premultiplied, i.e. straight r,g,b,a) 44 'alphaType': CanvasKit.AlphaType.Unpremul, 45 'colorSpace': CanvasKit.ColorSpace.SRGB, 46 }; 47 var pixelLen = width * height * 4; // it's 8888, so 4 bytes per pixel 48 // Allocate the buffer of pixels to be drawn into. 49 var pixelPtr = CanvasKit._malloc(pixelLen); 50 51 // Experiments with using RasterDirect vs Raster showed a 10% slowdown 52 // over the traditional Surface::MakeRaster approach. This was exacerbated when 53 // the surface was drawing to Premul and we had to convert to Unpremul each frame 54 // (up to a 10x further slowdown). 55 var surface = CanvasKit.Surface._makeRasterDirect(imageInfo, pixelPtr, width*4); 56 if (surface) { 57 surface._canvas = null; 58 surface._width = width; 59 surface._height = height; 60 surface._pixelLen = pixelLen; 61 62 surface._pixelPtr = pixelPtr; 63 // rasterDirectSurface does not initialize the pixels, so we clear them 64 // to transparent black. 65 surface.getCanvas().clear(CanvasKit.TRANSPARENT); 66 } 67 return surface; 68 }; 69 70 CanvasKit.MakeRasterDirectSurface = function(imageInfo, mallocObj, bytesPerRow) { 71 return CanvasKit.Surface._makeRasterDirect(imageInfo, mallocObj['byteOffset'], bytesPerRow); 72 }; 73 74 // For GPU builds, simply proxies to native code flush. For CPU builds, 75 // also updates the underlying HTML canvas, optionally with dirtyRect. 76 CanvasKit.Surface.prototype.flush = function(dirtyRect) { 77 CanvasKit.setCurrentContext(this._context); 78 this._flush(); 79 // Do we have an HTML canvas to write the pixels to? 80 // We will not have a canvas if this a GPU build, for example. 81 if (this._canvas) { 82 var pixels = new Uint8ClampedArray(CanvasKit.HEAPU8.buffer, this._pixelPtr, this._pixelLen); 83 var imageData = new ImageData(pixels, this._width, this._height); 84 85 if (!dirtyRect) { 86 this._canvas.getContext('2d').putImageData(imageData, 0, 0); 87 } else { 88 this._canvas.getContext('2d').putImageData(imageData, 0, 0, 89 dirtyRect[0], dirtyRect[1], 90 dirtyRect[2] - dirtyRect[0], 91 dirtyRect[3] - dirtyRect[1]); 92 } 93 } 94 }; 95 96 // Call dispose() instead of delete to clean up the underlying memory. 97 // TODO(kjlubick) get rid of this and just wrap around delete(). 98 CanvasKit.Surface.prototype.dispose = function() { 99 if (this._pixelPtr) { 100 CanvasKit._free(this._pixelPtr); 101 } 102 this.delete(); 103 }; 104 105 CanvasKit.setCurrentContext = CanvasKit.setCurrentContext || function() { 106 // no op if this is a cpu-only build. 107 }; 108 109 CanvasKit.getCurrentGrDirectContext = CanvasKit.getCurrentGrDirectContext || function() { 110 // No GrDirectContexts without a GPU backend. 111 return null; 112 }; 113 }); 114}(Module)); // When this file is loaded in, the high level object is "Module"; 115