xref: /aosp_15_r20/external/skia/modules/canvaskit/memory.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker/*
2*c8dee2aaSAndroid Build Coastguard Worker * This file houses utilities for copying blocks of memory to and from
3*c8dee2aaSAndroid Build Coastguard Worker * the WASM heap.
4*c8dee2aaSAndroid Build Coastguard Worker */
5*c8dee2aaSAndroid Build Coastguard Worker
6*c8dee2aaSAndroid Build Coastguard Worker/**
7*c8dee2aaSAndroid Build Coastguard Worker * Malloc returns a TypedArray backed by the C++ memory of the
8*c8dee2aaSAndroid Build Coastguard Worker * given length. It should only be used by advanced users who
9*c8dee2aaSAndroid Build Coastguard Worker * can manage memory and initialize values properly. When used
10*c8dee2aaSAndroid Build Coastguard Worker * correctly, it can save copying of data between JS and C++.
11*c8dee2aaSAndroid Build Coastguard Worker * When used incorrectly, it can lead to memory leaks.
12*c8dee2aaSAndroid Build Coastguard Worker * Any memory allocated by CanvasKit.Malloc needs to be released with CanvasKit.Free.
13*c8dee2aaSAndroid Build Coastguard Worker *
14*c8dee2aaSAndroid Build Coastguard Worker * const mObj = CanvasKit.Malloc(Float32Array, 20);
15*c8dee2aaSAndroid Build Coastguard Worker * Get a TypedArray view around the malloc'd memory (this does not copy anything).
16*c8dee2aaSAndroid Build Coastguard Worker * const ta = mObj.toTypedArray();
17*c8dee2aaSAndroid Build Coastguard Worker * // store data into ta
18*c8dee2aaSAndroid Build Coastguard Worker * const cf = CanvasKit.ColorFilter.MakeMatrix(ta); // mObj could also be used.
19*c8dee2aaSAndroid Build Coastguard Worker *
20*c8dee2aaSAndroid Build Coastguard Worker * // eventually...
21*c8dee2aaSAndroid Build Coastguard Worker * CanvasKit.Free(mObj);
22*c8dee2aaSAndroid Build Coastguard Worker *
23*c8dee2aaSAndroid Build Coastguard Worker * @param {TypedArray} typedArray - constructor for the typedArray.
24*c8dee2aaSAndroid Build Coastguard Worker * @param {number} len - number of *elements* to store.
25*c8dee2aaSAndroid Build Coastguard Worker */
26*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit.Malloc = function(typedArray, len) {
27*c8dee2aaSAndroid Build Coastguard Worker  var byteLen = len * typedArray.BYTES_PER_ELEMENT;
28*c8dee2aaSAndroid Build Coastguard Worker  var ptr = CanvasKit._malloc(byteLen);
29*c8dee2aaSAndroid Build Coastguard Worker  return {
30*c8dee2aaSAndroid Build Coastguard Worker    '_ck': true,
31*c8dee2aaSAndroid Build Coastguard Worker    'length': len,
32*c8dee2aaSAndroid Build Coastguard Worker    'byteOffset': ptr,
33*c8dee2aaSAndroid Build Coastguard Worker    typedArray: null,
34*c8dee2aaSAndroid Build Coastguard Worker    'subarray': function(start, end) {
35*c8dee2aaSAndroid Build Coastguard Worker      var sa = this['toTypedArray']().subarray(start, end);
36*c8dee2aaSAndroid Build Coastguard Worker      sa['_ck'] = true;
37*c8dee2aaSAndroid Build Coastguard Worker      return sa;
38*c8dee2aaSAndroid Build Coastguard Worker    },
39*c8dee2aaSAndroid Build Coastguard Worker    'toTypedArray': function() {
40*c8dee2aaSAndroid Build Coastguard Worker      // Check if the previously allocated array is still usable.
41*c8dee2aaSAndroid Build Coastguard Worker      // If it's falsy, then we haven't created an array yet.
42*c8dee2aaSAndroid Build Coastguard Worker      // If it's empty, then WASM resized memory and emptied the array.
43*c8dee2aaSAndroid Build Coastguard Worker      if (this.typedArray && this.typedArray.length) {
44*c8dee2aaSAndroid Build Coastguard Worker        return this.typedArray;
45*c8dee2aaSAndroid Build Coastguard Worker      }
46*c8dee2aaSAndroid Build Coastguard Worker      this.typedArray = new typedArray(CanvasKit.HEAPU8.buffer, ptr, len);
47*c8dee2aaSAndroid Build Coastguard Worker      // add a marker that this was allocated in C++ land
48*c8dee2aaSAndroid Build Coastguard Worker      this.typedArray['_ck'] = true;
49*c8dee2aaSAndroid Build Coastguard Worker      return this.typedArray;
50*c8dee2aaSAndroid Build Coastguard Worker    },
51*c8dee2aaSAndroid Build Coastguard Worker  };
52*c8dee2aaSAndroid Build Coastguard Worker};
53*c8dee2aaSAndroid Build Coastguard Worker
54*c8dee2aaSAndroid Build Coastguard Worker/**
55*c8dee2aaSAndroid Build Coastguard Worker * Free frees the memory returned by Malloc.
56*c8dee2aaSAndroid Build Coastguard Worker * Any memory allocated by CanvasKit.Malloc needs to be released with CanvasKit.Free.
57*c8dee2aaSAndroid Build Coastguard Worker */
58*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit.Free = function(mallocObj) {
59*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit._free(mallocObj['byteOffset']);
60*c8dee2aaSAndroid Build Coastguard Worker  mallocObj['byteOffset'] = nullptr;
61*c8dee2aaSAndroid Build Coastguard Worker  // Set these to null to make sure the TypedArrays can be garbage collected.
62*c8dee2aaSAndroid Build Coastguard Worker  mallocObj['toTypedArray'] = null;
63*c8dee2aaSAndroid Build Coastguard Worker  mallocObj.typedArray = null;
64*c8dee2aaSAndroid Build Coastguard Worker};
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker// This helper will free the given pointer unless the provided array is one
67*c8dee2aaSAndroid Build Coastguard Worker// that was returned by CanvasKit.Malloc.
68*c8dee2aaSAndroid Build Coastguard Workerfunction freeArraysThatAreNotMallocedByUsers(ptr, arr) {
69*c8dee2aaSAndroid Build Coastguard Worker  if (!wasMalloced(arr)) {
70*c8dee2aaSAndroid Build Coastguard Worker    CanvasKit._free(ptr);
71*c8dee2aaSAndroid Build Coastguard Worker  }
72*c8dee2aaSAndroid Build Coastguard Worker}
73*c8dee2aaSAndroid Build Coastguard Worker
74*c8dee2aaSAndroid Build Coastguard Worker// wasMalloced returns true if the object was created by a call to Malloc. This is determined
75*c8dee2aaSAndroid Build Coastguard Worker// by looking at a property that was added to our Malloc obj and typed arrays.
76*c8dee2aaSAndroid Build Coastguard Workerfunction wasMalloced(obj) {
77*c8dee2aaSAndroid Build Coastguard Worker  return obj && obj['_ck'];
78*c8dee2aaSAndroid Build Coastguard Worker}
79*c8dee2aaSAndroid Build Coastguard Worker
80*c8dee2aaSAndroid Build Coastguard Worker// We define some "scratch" variables which will house both the pointer to
81*c8dee2aaSAndroid Build Coastguard Worker// memory we allocate at startup as well as a Malloc object, which we can
82*c8dee2aaSAndroid Build Coastguard Worker// use to get a TypedArray view of that memory.
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Workervar _scratch3x3MatrixPtr = nullptr;
85*c8dee2aaSAndroid Build Coastguard Workervar _scratch3x3Matrix;  // the result from CanvasKit.Malloc
86*c8dee2aaSAndroid Build Coastguard Worker
87*c8dee2aaSAndroid Build Coastguard Workervar _scratch4x4MatrixPtr = nullptr;
88*c8dee2aaSAndroid Build Coastguard Workervar _scratch4x4Matrix;
89*c8dee2aaSAndroid Build Coastguard Worker
90*c8dee2aaSAndroid Build Coastguard Workervar _scratchColorPtr = nullptr;
91*c8dee2aaSAndroid Build Coastguard Workervar _scratchColor;
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Workervar _scratchFourFloatsA;
94*c8dee2aaSAndroid Build Coastguard Workervar _scratchFourFloatsAPtr = nullptr;
95*c8dee2aaSAndroid Build Coastguard Worker
96*c8dee2aaSAndroid Build Coastguard Workervar _scratchFourFloatsB;
97*c8dee2aaSAndroid Build Coastguard Workervar _scratchFourFloatsBPtr = nullptr;
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Workervar _scratchThreeFloatsA;
100*c8dee2aaSAndroid Build Coastguard Workervar _scratchThreeFloatsAPtr = nullptr;
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Workervar _scratchThreeFloatsB;
103*c8dee2aaSAndroid Build Coastguard Workervar _scratchThreeFloatsBPtr = nullptr;
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Workervar _scratchIRect;
106*c8dee2aaSAndroid Build Coastguard Workervar _scratchIRectPtr = nullptr;
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Workervar _scratchRRect;
109*c8dee2aaSAndroid Build Coastguard Workervar _scratchRRectPtr = nullptr;
110*c8dee2aaSAndroid Build Coastguard Worker
111*c8dee2aaSAndroid Build Coastguard Workervar _scratchRRect2;
112*c8dee2aaSAndroid Build Coastguard Workervar _scratchRRect2Ptr = nullptr;
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker// arr can be a normal JS array or a TypedArray
115*c8dee2aaSAndroid Build Coastguard Worker// dest is a string like 'HEAPU32' that specifies the type the src array
116*c8dee2aaSAndroid Build Coastguard Worker// should be copied into.
117*c8dee2aaSAndroid Build Coastguard Worker// ptr can be optionally provided if the memory was already allocated.
118*c8dee2aaSAndroid Build Coastguard Worker// Callers should eventually free the data unless the C++ object owns the memory,
119*c8dee2aaSAndroid Build Coastguard Worker// or the provided pointer is a scratch pointer or a user-malloced value.
120*c8dee2aaSAndroid Build Coastguard Worker// see also freeArraysThatAreNotMallocedByUsers().
121*c8dee2aaSAndroid Build Coastguard Workerfunction copy1dArray(arr, dest, ptr) {
122*c8dee2aaSAndroid Build Coastguard Worker  if (!arr || !arr.length) {
123*c8dee2aaSAndroid Build Coastguard Worker    return nullptr;
124*c8dee2aaSAndroid Build Coastguard Worker  }
125*c8dee2aaSAndroid Build Coastguard Worker  // This was created with CanvasKit.Malloc, so it's already been copied.
126*c8dee2aaSAndroid Build Coastguard Worker  if (wasMalloced(arr)) {
127*c8dee2aaSAndroid Build Coastguard Worker    return arr.byteOffset;
128*c8dee2aaSAndroid Build Coastguard Worker  }
129*c8dee2aaSAndroid Build Coastguard Worker  var bytesPerElement = CanvasKit[dest].BYTES_PER_ELEMENT;
130*c8dee2aaSAndroid Build Coastguard Worker  if (!ptr) {
131*c8dee2aaSAndroid Build Coastguard Worker    ptr = CanvasKit._malloc(arr.length * bytesPerElement);
132*c8dee2aaSAndroid Build Coastguard Worker  }
133*c8dee2aaSAndroid Build Coastguard Worker  // In c++ terms, the WASM heap is a uint8_t*, a long buffer/array of single
134*c8dee2aaSAndroid Build Coastguard Worker  // byte elements. When we run _malloc, we always get an offset/pointer into
135*c8dee2aaSAndroid Build Coastguard Worker  // that block of memory.
136*c8dee2aaSAndroid Build Coastguard Worker  // CanvasKit exposes some different views to make it easier to work with
137*c8dee2aaSAndroid Build Coastguard Worker  // different types. HEAPF32 for example, exposes it as a float*
138*c8dee2aaSAndroid Build Coastguard Worker  // However, to make the ptr line up, we have to do some pointer arithmetic.
139*c8dee2aaSAndroid Build Coastguard Worker  // Concretely, we need to convert ptr to go from an index into a 1-byte-wide
140*c8dee2aaSAndroid Build Coastguard Worker  // buffer to an index into a 4-byte-wide buffer (in the case of HEAPF32)
141*c8dee2aaSAndroid Build Coastguard Worker  // and thus we divide ptr by 4.
142*c8dee2aaSAndroid Build Coastguard Worker  // It is important to make sure we are grabbing the freshest view of the
143*c8dee2aaSAndroid Build Coastguard Worker  // memory possible because if we call _malloc and the heap needs to grow,
144*c8dee2aaSAndroid Build Coastguard Worker  // the TypedArrayView will no longer be valid.
145*c8dee2aaSAndroid Build Coastguard Worker  CanvasKit[dest].set(arr, ptr / bytesPerElement);
146*c8dee2aaSAndroid Build Coastguard Worker  return ptr;
147*c8dee2aaSAndroid Build Coastguard Worker}
148*c8dee2aaSAndroid Build Coastguard Worker
149*c8dee2aaSAndroid Build Coastguard Worker// Copies an array of colors to wasm, returning an object with the pointer
150*c8dee2aaSAndroid Build Coastguard Worker// and info necessary to use the copied colors.
151*c8dee2aaSAndroid Build Coastguard Worker// Accepts either a flat Float32Array, flat Uint32Array or Array of Float32Arrays.
152*c8dee2aaSAndroid Build Coastguard Worker// If color is an object that was allocated with CanvasKit.Malloc, its pointer is
153*c8dee2aaSAndroid Build Coastguard Worker// returned and no extra copy is performed.
154*c8dee2aaSAndroid Build Coastguard Worker// TODO(nifong): have this accept color builders.
155*c8dee2aaSAndroid Build Coastguard Workerfunction copyFlexibleColorArray(colors) {
156*c8dee2aaSAndroid Build Coastguard Worker  var result = {
157*c8dee2aaSAndroid Build Coastguard Worker    colorPtr: nullptr,
158*c8dee2aaSAndroid Build Coastguard Worker    count: colors.length,
159*c8dee2aaSAndroid Build Coastguard Worker    colorType: CanvasKit.ColorType.RGBA_F32,
160*c8dee2aaSAndroid Build Coastguard Worker  };
161*c8dee2aaSAndroid Build Coastguard Worker  if (colors instanceof Float32Array) {
162*c8dee2aaSAndroid Build Coastguard Worker    result.colorPtr = copy1dArray(colors, 'HEAPF32');
163*c8dee2aaSAndroid Build Coastguard Worker    result.count = colors.length / 4;
164*c8dee2aaSAndroid Build Coastguard Worker
165*c8dee2aaSAndroid Build Coastguard Worker  } else if (colors instanceof Uint32Array) {
166*c8dee2aaSAndroid Build Coastguard Worker    result.colorPtr = copy1dArray(colors, 'HEAPU32');
167*c8dee2aaSAndroid Build Coastguard Worker    result.colorType = CanvasKit.ColorType.RGBA_8888;
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker  } else if (colors instanceof Array) {
170*c8dee2aaSAndroid Build Coastguard Worker    result.colorPtr = copyColorArray(colors);
171*c8dee2aaSAndroid Build Coastguard Worker  } else {
172*c8dee2aaSAndroid Build Coastguard Worker    throw('Invalid argument to copyFlexibleColorArray, Not a color array '+typeof(colors));
173*c8dee2aaSAndroid Build Coastguard Worker  }
174*c8dee2aaSAndroid Build Coastguard Worker  return result;
175*c8dee2aaSAndroid Build Coastguard Worker}
176*c8dee2aaSAndroid Build Coastguard Worker
177*c8dee2aaSAndroid Build Coastguard Workerfunction copyColorArray(arr) {
178*c8dee2aaSAndroid Build Coastguard Worker  if (!arr || !arr.length) {
179*c8dee2aaSAndroid Build Coastguard Worker    return nullptr;
180*c8dee2aaSAndroid Build Coastguard Worker  }
181*c8dee2aaSAndroid Build Coastguard Worker  // 4 floats per color, 4 bytes per float.
182*c8dee2aaSAndroid Build Coastguard Worker  var ptr = CanvasKit._malloc(arr.length * 4 * 4);
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker  var idx = 0;
185*c8dee2aaSAndroid Build Coastguard Worker  var adjustedPtr = ptr / 4; // cast the byte pointer into a float pointer.
186*c8dee2aaSAndroid Build Coastguard Worker  for (var r = 0; r < arr.length; r++) {
187*c8dee2aaSAndroid Build Coastguard Worker    for (var c = 0; c < 4; c++) {
188*c8dee2aaSAndroid Build Coastguard Worker      CanvasKit.HEAPF32[adjustedPtr + idx] = arr[r][c];
189*c8dee2aaSAndroid Build Coastguard Worker      idx++;
190*c8dee2aaSAndroid Build Coastguard Worker    }
191*c8dee2aaSAndroid Build Coastguard Worker  }
192*c8dee2aaSAndroid Build Coastguard Worker  return ptr;
193*c8dee2aaSAndroid Build Coastguard Worker}
194*c8dee2aaSAndroid Build Coastguard Worker
195*c8dee2aaSAndroid Build Coastguard Workervar defaultPerspective = Float32Array.of(0, 0, 1);
196*c8dee2aaSAndroid Build Coastguard Worker
197*c8dee2aaSAndroid Build Coastguard Worker// Copies the given DOMMatrix/Array/TypedArray to the CanvasKit heap and
198*c8dee2aaSAndroid Build Coastguard Worker// returns a pointer to the memory. This memory is a float* of length 9.
199*c8dee2aaSAndroid Build Coastguard Worker// If the passed in matrix is null/undefined, we return 0 (nullptr). The
200*c8dee2aaSAndroid Build Coastguard Worker// returned pointer should NOT be freed, as it is either null or a scratch
201*c8dee2aaSAndroid Build Coastguard Worker// pointer.
202*c8dee2aaSAndroid Build Coastguard Workerfunction copy3x3MatrixToWasm(matr) {
203*c8dee2aaSAndroid Build Coastguard Worker  if (!matr) {
204*c8dee2aaSAndroid Build Coastguard Worker    return nullptr;
205*c8dee2aaSAndroid Build Coastguard Worker  }
206*c8dee2aaSAndroid Build Coastguard Worker
207*c8dee2aaSAndroid Build Coastguard Worker  var wasm3x3Matrix = _scratch3x3Matrix['toTypedArray']();
208*c8dee2aaSAndroid Build Coastguard Worker  if (matr.length) {
209*c8dee2aaSAndroid Build Coastguard Worker    if (matr.length === 6 || matr.length === 9) {
210*c8dee2aaSAndroid Build Coastguard Worker      // matr should be an array or typed array.
211*c8dee2aaSAndroid Build Coastguard Worker      copy1dArray(matr, 'HEAPF32', _scratch3x3MatrixPtr);
212*c8dee2aaSAndroid Build Coastguard Worker      if (matr.length === 6) {
213*c8dee2aaSAndroid Build Coastguard Worker        // Overwrite the last 3 floats with the default perspective. The divide
214*c8dee2aaSAndroid Build Coastguard Worker        // by 4 casts the pointer into a float pointer.
215*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.HEAPF32.set(defaultPerspective, 6 + _scratch3x3MatrixPtr / 4);
216*c8dee2aaSAndroid Build Coastguard Worker      }
217*c8dee2aaSAndroid Build Coastguard Worker      return _scratch3x3MatrixPtr;
218*c8dee2aaSAndroid Build Coastguard Worker    } else if (matr.length === 16) {
219*c8dee2aaSAndroid Build Coastguard Worker      // Downsample the 4x4 matrix into a 3x3
220*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[0] = matr[0];
221*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[1] = matr[1];
222*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[2] = matr[3];
223*c8dee2aaSAndroid Build Coastguard Worker
224*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[3] = matr[4];
225*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[4] = matr[5];
226*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[5] = matr[7];
227*c8dee2aaSAndroid Build Coastguard Worker
228*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[6] = matr[12];
229*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[7] = matr[13];
230*c8dee2aaSAndroid Build Coastguard Worker      wasm3x3Matrix[8] = matr[15];
231*c8dee2aaSAndroid Build Coastguard Worker      return _scratch3x3MatrixPtr;
232*c8dee2aaSAndroid Build Coastguard Worker    }
233*c8dee2aaSAndroid Build Coastguard Worker    throw 'invalid matrix size';
234*c8dee2aaSAndroid Build Coastguard Worker  } else if (matr['m11'] === undefined) {
235*c8dee2aaSAndroid Build Coastguard Worker    throw 'invalid matrix argument';
236*c8dee2aaSAndroid Build Coastguard Worker  }
237*c8dee2aaSAndroid Build Coastguard Worker  // Reminder that DOMMatrix is column-major.
238*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[0] = matr['m11'];
239*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[1] = matr['m21'];
240*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[2] = matr['m41'];
241*c8dee2aaSAndroid Build Coastguard Worker
242*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[3] = matr['m12'];
243*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[4] = matr['m22'];
244*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[5] = matr['m42'];
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[6] = matr['m14'];
247*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[7] = matr['m24'];
248*c8dee2aaSAndroid Build Coastguard Worker  wasm3x3Matrix[8] = matr['m44'];
249*c8dee2aaSAndroid Build Coastguard Worker  return _scratch3x3MatrixPtr;
250*c8dee2aaSAndroid Build Coastguard Worker}
251*c8dee2aaSAndroid Build Coastguard Worker
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard Worker// Copies the given DOMMatrix/Array/TypedArray to the CanvasKit heap and
254*c8dee2aaSAndroid Build Coastguard Worker// returns a pointer to the memory. This memory is a float* of length 16.
255*c8dee2aaSAndroid Build Coastguard Worker// If the passed in matrix is null/undefined, we return 0 (nullptr). The
256*c8dee2aaSAndroid Build Coastguard Worker// returned pointer should NOT be freed, as it is either null or a scratch
257*c8dee2aaSAndroid Build Coastguard Worker// pointer.
258*c8dee2aaSAndroid Build Coastguard Workerfunction copy4x4MatrixToWasm(matr) {
259*c8dee2aaSAndroid Build Coastguard Worker  if (!matr) {
260*c8dee2aaSAndroid Build Coastguard Worker    return nullptr;
261*c8dee2aaSAndroid Build Coastguard Worker  }
262*c8dee2aaSAndroid Build Coastguard Worker  var wasm4x4Matrix = _scratch4x4Matrix['toTypedArray']();
263*c8dee2aaSAndroid Build Coastguard Worker  if (matr.length) {
264*c8dee2aaSAndroid Build Coastguard Worker    if (matr.length !== 16 && matr.length !== 6 && matr.length !== 9) {
265*c8dee2aaSAndroid Build Coastguard Worker      throw 'invalid matrix size';
266*c8dee2aaSAndroid Build Coastguard Worker    }
267*c8dee2aaSAndroid Build Coastguard Worker    if (matr.length === 16) {
268*c8dee2aaSAndroid Build Coastguard Worker      // matr should be an array or typed array.
269*c8dee2aaSAndroid Build Coastguard Worker      return copy1dArray(matr, 'HEAPF32', _scratch4x4MatrixPtr);
270*c8dee2aaSAndroid Build Coastguard Worker    }
271*c8dee2aaSAndroid Build Coastguard Worker    // Upscale the row-major 3x3 or 3x2 matrix into a 4x4 row-major matrix
272*c8dee2aaSAndroid Build Coastguard Worker    // TODO(skbug.com/10108) This will need to change when we convert our
273*c8dee2aaSAndroid Build Coastguard Worker    //   JS 4x4 to be column-major.
274*c8dee2aaSAndroid Build Coastguard Worker    // When upscaling, we need to overwrite the 3rd column and the 3rd row with
275*c8dee2aaSAndroid Build Coastguard Worker    // 0s. It's easiest to just do that with a fill command.
276*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix.fill(0);
277*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[0] = matr[0];
278*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[1] = matr[1];
279*c8dee2aaSAndroid Build Coastguard Worker    // skip col 2
280*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[3] = matr[2];
281*c8dee2aaSAndroid Build Coastguard Worker
282*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[4] = matr[3];
283*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[5] = matr[4];
284*c8dee2aaSAndroid Build Coastguard Worker    // skip col 2
285*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[7] = matr[5];
286*c8dee2aaSAndroid Build Coastguard Worker
287*c8dee2aaSAndroid Build Coastguard Worker    // row2 == identity
288*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[10] = 1;
289*c8dee2aaSAndroid Build Coastguard Worker
290*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[12] = matr[6];
291*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[13] = matr[7];
292*c8dee2aaSAndroid Build Coastguard Worker    // skip col 2
293*c8dee2aaSAndroid Build Coastguard Worker    wasm4x4Matrix[15] = matr[8];
294*c8dee2aaSAndroid Build Coastguard Worker
295*c8dee2aaSAndroid Build Coastguard Worker    if (matr.length === 6) {
296*c8dee2aaSAndroid Build Coastguard Worker      // fix perspective for the 3x2 case (from above, they will be undefined).
297*c8dee2aaSAndroid Build Coastguard Worker      wasm4x4Matrix[12]=0;
298*c8dee2aaSAndroid Build Coastguard Worker      wasm4x4Matrix[13]=0;
299*c8dee2aaSAndroid Build Coastguard Worker      wasm4x4Matrix[15]=1;
300*c8dee2aaSAndroid Build Coastguard Worker    }
301*c8dee2aaSAndroid Build Coastguard Worker    return _scratch4x4MatrixPtr;
302*c8dee2aaSAndroid Build Coastguard Worker  } else if (matr['m11'] === undefined) {
303*c8dee2aaSAndroid Build Coastguard Worker    throw 'invalid matrix argument';
304*c8dee2aaSAndroid Build Coastguard Worker  }
305*c8dee2aaSAndroid Build Coastguard Worker  // Reminder that DOMMatrix is column-major.
306*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[0] = matr['m11'];
307*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[1] = matr['m21'];
308*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[2] = matr['m31'];
309*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[3] = matr['m41'];
310*c8dee2aaSAndroid Build Coastguard Worker
311*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[4] = matr['m12'];
312*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[5] = matr['m22'];
313*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[6] = matr['m32'];
314*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[7] = matr['m42'];
315*c8dee2aaSAndroid Build Coastguard Worker
316*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[8] = matr['m13'];
317*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[9] = matr['m23'];
318*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[10] = matr['m33'];
319*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[11] = matr['m43'];
320*c8dee2aaSAndroid Build Coastguard Worker
321*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[12] = matr['m14'];
322*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[13] = matr['m24'];
323*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[14] = matr['m34'];
324*c8dee2aaSAndroid Build Coastguard Worker  wasm4x4Matrix[15] = matr['m44'];
325*c8dee2aaSAndroid Build Coastguard Worker  return _scratch4x4MatrixPtr;
326*c8dee2aaSAndroid Build Coastguard Worker}
327*c8dee2aaSAndroid Build Coastguard Worker
328*c8dee2aaSAndroid Build Coastguard Worker// copies a 4x4 matrix at the given pointer into a JS array.
329*c8dee2aaSAndroid Build Coastguard Workerfunction copy4x4MatrixFromWasm(matrPtr) {
330*c8dee2aaSAndroid Build Coastguard Worker  // read them out into an array. TODO(kjlubick): If we change Matrix to be
331*c8dee2aaSAndroid Build Coastguard Worker  // typedArrays, then we should return a typed array here too.
332*c8dee2aaSAndroid Build Coastguard Worker  var rv = new Array(16);
333*c8dee2aaSAndroid Build Coastguard Worker  for (var i = 0; i < 16; i++) {
334*c8dee2aaSAndroid Build Coastguard Worker    rv[i] = CanvasKit.HEAPF32[matrPtr/4 + i]; // divide by 4 to cast to float.
335*c8dee2aaSAndroid Build Coastguard Worker  }
336*c8dee2aaSAndroid Build Coastguard Worker  return rv;
337*c8dee2aaSAndroid Build Coastguard Worker}
338*c8dee2aaSAndroid Build Coastguard Worker
339*c8dee2aaSAndroid Build Coastguard Worker// copies the given floats into the wasm heap as an SkColor4f. Unless a non-scratch pointer is
340*c8dee2aaSAndroid Build Coastguard Worker// passed into ptr, callers do NOT need to free the returned pointer.
341*c8dee2aaSAndroid Build Coastguard Workerfunction copyColorToWasm(color4f, ptr) {
342*c8dee2aaSAndroid Build Coastguard Worker  return copy1dArray(color4f, 'HEAPF32', ptr || _scratchColorPtr);
343*c8dee2aaSAndroid Build Coastguard Worker}
344*c8dee2aaSAndroid Build Coastguard Worker
345*c8dee2aaSAndroid Build Coastguard Worker// copies the given color into the wasm heap. Callers do not need to free the returned pointer.
346*c8dee2aaSAndroid Build Coastguard Workerfunction copyColorComponentsToWasm(r, g, b, a) {
347*c8dee2aaSAndroid Build Coastguard Worker  var colors = _scratchColor['toTypedArray']();
348*c8dee2aaSAndroid Build Coastguard Worker  colors[0] = r;
349*c8dee2aaSAndroid Build Coastguard Worker  colors[1] = g;
350*c8dee2aaSAndroid Build Coastguard Worker  colors[2] = b;
351*c8dee2aaSAndroid Build Coastguard Worker  colors[3] = a;
352*c8dee2aaSAndroid Build Coastguard Worker  return _scratchColorPtr;
353*c8dee2aaSAndroid Build Coastguard Worker}
354*c8dee2aaSAndroid Build Coastguard Worker
355*c8dee2aaSAndroid Build Coastguard Worker// copies the given color into the wasm heap. Callers must free the returned pointer.
356*c8dee2aaSAndroid Build Coastguard Workerfunction copyColorToWasmNoScratch(color4f) {
357*c8dee2aaSAndroid Build Coastguard Worker  // TODO(kjlubick): accept 4 floats or int color
358*c8dee2aaSAndroid Build Coastguard Worker  return copy1dArray(color4f, 'HEAPF32');
359*c8dee2aaSAndroid Build Coastguard Worker}
360*c8dee2aaSAndroid Build Coastguard Worker
361*c8dee2aaSAndroid Build Coastguard Worker// copies the four floats at the given pointer in a js Float32Array
362*c8dee2aaSAndroid Build Coastguard Workerfunction copyColorFromWasm(colorPtr) {
363*c8dee2aaSAndroid Build Coastguard Worker  var rv = new Float32Array(4);
364*c8dee2aaSAndroid Build Coastguard Worker  for (var i = 0; i < 4; i++) {
365*c8dee2aaSAndroid Build Coastguard Worker    rv[i] = CanvasKit.HEAPF32[colorPtr/4 + i]; // divide by 4 to cast to float.
366*c8dee2aaSAndroid Build Coastguard Worker  }
367*c8dee2aaSAndroid Build Coastguard Worker  return rv;
368*c8dee2aaSAndroid Build Coastguard Worker}
369*c8dee2aaSAndroid Build Coastguard Worker
370*c8dee2aaSAndroid Build Coastguard Worker// copies the given floats into the wasm heap as an SkRect. Unless a non-scratch pointer is
371*c8dee2aaSAndroid Build Coastguard Worker// passed into ptr, callers do NOT need to free the returned pointer.
372*c8dee2aaSAndroid Build Coastguard Workerfunction copyRectToWasm(fourFloats, ptr) {
373*c8dee2aaSAndroid Build Coastguard Worker  return copy1dArray(fourFloats, 'HEAPF32', ptr || _scratchFourFloatsAPtr);
374*c8dee2aaSAndroid Build Coastguard Worker}
375*c8dee2aaSAndroid Build Coastguard Worker
376*c8dee2aaSAndroid Build Coastguard Worker// copies the given ints into the wasm heap as an SkIRect. Unless a non-scratch pointer is
377*c8dee2aaSAndroid Build Coastguard Worker// passed into ptr, callers do NOT need to free the returned pointer.
378*c8dee2aaSAndroid Build Coastguard Workerfunction copyIRectToWasm(fourInts, ptr) {
379*c8dee2aaSAndroid Build Coastguard Worker  return copy1dArray(fourInts, 'HEAP32', ptr || _scratchIRectPtr);
380*c8dee2aaSAndroid Build Coastguard Worker}
381*c8dee2aaSAndroid Build Coastguard Worker
382*c8dee2aaSAndroid Build Coastguard Worker// copies the four ints at the given pointer into a JS Int32Array
383*c8dee2aaSAndroid Build Coastguard Workerfunction copyIRectFromWasm(rectMalloc, outputArray) {
384*c8dee2aaSAndroid Build Coastguard Worker  var ta = rectMalloc['toTypedArray']();
385*c8dee2aaSAndroid Build Coastguard Worker  if (outputArray) {
386*c8dee2aaSAndroid Build Coastguard Worker    outputArray.set(ta);
387*c8dee2aaSAndroid Build Coastguard Worker    return outputArray;
388*c8dee2aaSAndroid Build Coastguard Worker  }
389*c8dee2aaSAndroid Build Coastguard Worker  return ta.slice();
390*c8dee2aaSAndroid Build Coastguard Worker}
391*c8dee2aaSAndroid Build Coastguard Worker
392*c8dee2aaSAndroid Build Coastguard Worker// copies the given floats into the wasm heap as an SkRRect. Unless a non-scratch pointer is
393*c8dee2aaSAndroid Build Coastguard Worker// passed into ptr, callers do NOT need to free the returned pointer.
394*c8dee2aaSAndroid Build Coastguard Workerfunction copyRRectToWasm(twelveFloats, ptr) {
395*c8dee2aaSAndroid Build Coastguard Worker  return copy1dArray(twelveFloats, 'HEAPF32', ptr || _scratchRRectPtr);
396*c8dee2aaSAndroid Build Coastguard Worker}
397