• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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