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