[canvaskit] Remove 2d point arrays from API.

I kept in an array of Color (Float32Array) because it's very convenient
and not worth the hassle of removing.

Change-Id: I34c430c2b5112b6d073b049a81994e946428f21c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/340797
Reviewed-by: Nathaniel Nifong <nifong@google.com>
This commit is contained in:
Kevin Lubick 2020-12-04 09:10:39 -05:00
parent d90e578fb4
commit e7c1a731ff
10 changed files with 100 additions and 106 deletions

View File

@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- `getImageInfo()` and `getColorSpace()` to the `Image` type.
### Breaking
- `Path.addPoly()` no longer accepts a 2d array of points, but a flattened 1d array.
- `MakeVertices()` no longer accepts 2d arrays of points or texture coordinates, but
flattened 1d arrays in both places.
### Changed
- `MakeImage` is now documented in the Typescript types (index.d.ts). The parameters have been
streamlined to align with other, similar APIs.
@ -17,6 +22,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Canvas.drawPoints` correctly takes a flattened Array or TypedArray of points (as the
documentation says), not a 2D array.
### Type Changes (index.d.ts)
- Documented additional type for InputFlexibleColorArray.
## [0.20.0] - 2020-11-12
### Added

View File

@ -387,7 +387,7 @@
ctx.stroke();
// squished vertically
ctx.globalAlpha = 0.7
ctx.globalAlpha = 0.7;
ctx.imageSmoothingQuality = 'medium';
ctx.drawImage(canvas._img, 150, 150, 150, 100);
ctx.rotate(-.2);
@ -594,11 +594,11 @@
ctx.lineWidth = 6;
ctx.ellipse(10, 290, 30, 30, 0, 0, Math.PI * 2);
ctx.scale(2, 1);
ctx.moveTo(10, 290)
ctx.moveTo(10, 290);
ctx.ellipse(10, 290, 30, 60, 0, 0, Math.PI * 2);
ctx.resetTransform();
ctx.scale(3, 1);
ctx.moveTo(10, 290)
ctx.moveTo(10, 290);
ctx.ellipse(10, 290, 30, 90, 0, 0, Math.PI * 2);
ctx.stroke();
}
@ -747,7 +747,7 @@
ctx.fillStyle = pattern;
ctx.fillRect(1500, 0, 3000, 750);
ctx.globalAlpha = 0.7
ctx.globalAlpha = 0.7;
pattern = ctx.createPattern(canvas._img, 'repeat-y');
ctx.fillStyle = pattern;
ctx.fillRect(0, 750, 1500, 1500);
@ -868,7 +868,7 @@
// See https://fiddle.skia.org/c/f48b22eaad1bb7adcc3faaa321754af6
// for original c++ version.
let points = [[ 0, 0 ], [ 250, 0 ], [ 100, 100 ], [ 0, 250 ]];
let points = [0, 0, 250, 0, 100, 100, 0, 250];
let colors = [CanvasKit.RED, CanvasKit.BLUE,
CanvasKit.YELLOW, CanvasKit.CYAN];
let vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TriangleFan,
@ -881,8 +881,8 @@
// See https://fiddle.skia.org/c/e8bdae9bea3227758989028424fcac3d
// for original c++ version.
points = [[ 300, 300 ], [ 50, 300 ], [ 200, 200 ], [ 300, 50 ]];
let texs = [[ 0, 0 ], [ 0, 250 ], [ 250, 250 ], [ 250, 0 ]];
points = [300, 300, 50, 300, 200, 200, 300, 50 ];
let texs = [ 0, 0, 0, 250, 250, 250, 250, 0 ];
vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TriangleFan,
points, texs, colors);
@ -909,13 +909,12 @@
// See https://fiddle.skia.org/c/f48b22eaad1bb7adcc3faaa321754af6
// for original c++ version.
let points = [[ 0, 0 ], [ 250, 0 ], [ 100, 100 ], [ 0, 250 ]];
let colors = [CanvasKit.BLUE, CanvasKit.YELLOW, CanvasKit.RED];
let pos = [0, .7, 1.0];
let transform = [2, 0, 0,
0, 2, 0,
0, 0, 1]
let shader = CanvasKit.Shader.MakeRadialGradient([150,150], 130, colors,
0, 0, 1];
let shader = CanvasKit.Shader.MakeRadialGradient([150, 150], 130, colors,
pos, CanvasKit.TileMode.Mirror, transform);
paint.setShader(shader);
@ -923,7 +922,7 @@
const textBlob = CanvasKit.TextBlob.MakeFromText('Radial', textFont);
canvas.drawTextBlob(textBlob, 10, 200, paint);
paint.delete()
paint.delete();
textFont.delete();
textBlob.delete();
surface.flush();
@ -967,7 +966,7 @@
bounds[0] += textBoxX; // left
bounds[2] += textBoxX; // right
bounds[1] += textBoxY; // top
bounds[3] += textBoxY // bottom
bounds[3] += textBoxY; // bottom
canvas.drawRect(bounds, paint);
const SHAPE_TEST_TEXT = 'VAVAVAVAVAFIfi';

View File

@ -408,7 +408,7 @@ function pathTests(CK: CanvasKit) {
path.addOval(someRect);
path.addOval(someRect, true, 3);
path.addPath(p2);
path.addPoly([[20, 20], [40, 40], [20, 40]], true);
path.addPoly([20, 20, 40, 40, 20, 40], true);
path.addRect(someRect);
path.addRect(someRect, true);
path.addRRect(someRRect);
@ -876,17 +876,17 @@ function vectorTests(CK: CanvasKit) {
function verticesTests(CK: CanvasKit) {
const points = [
[ 70, 170 ], [ 40, 90 ], [ 130, 150 ], [ 100, 50 ],
[ 225, 150 ], [ 225, 60 ], [ 310, 180 ], [ 330, 100 ]
70, 170, 40, 90, 130, 150, 100, 50,
225, 150, 225, 60, 310, 180, 330, 100,
];
const textureCoordinates = [
[ 0, 240 ], [ 0, 0 ], [ 80, 240 ], [ 80, 0 ],
[ 160, 240 ], [ 160, 0 ], [ 240, 240 ], [ 240, 0 ]
0, 240, 0, 0, 80, 240, 80, 0,
160, 240, 160, 0, 240, 240, 240, 0,
];
const vertices = CK.MakeVertices(CK.VertexMode.TrianglesStrip, // $ExpectType Vertices
points, textureCoordinates);
const points2 = [[ 0, 0 ], [ 250, 0 ], [ 100, 100 ], [ 0, 250 ]];
const points2 = new Float32Array(points);
// 1d float color array
const colors = Float32Array.of(
1, 0, 0, 1, // red
@ -894,7 +894,7 @@ function verticesTests(CK: CanvasKit) {
0, 0, 1, 1, // blue
1, 0, 1, 1); // purple
const vertices2 = CK.MakeVertices(CK.VertexMode.TriangleFan,
points, null, colors, null, true);
points2, null, colors, null, true);
const rect = vertices.bounds(); // $ExpectType Float32Array
vertices.bounds(rect);

View File

@ -339,9 +339,10 @@ export interface CanvasKit {
* @param indices
* @param isVolatile
*/
MakeVertices(mode: VertexMode, positions: number[][], textureCoordinates?: number[][] | null,
colors?: Float32Array | ColorIntArray | null, indices?: number[] | null,
isVolatile?: boolean): Vertices;
MakeVertices(mode: VertexMode, positions: InputFlattenedPointArray,
textureCoordinates?: InputFlattenedPointArray | null,
colors?: Float32Array | ColorIntArray | null, indices?: number[] | null,
isVolatile?: boolean): Vertices;
/**
* Returns a Skottie animation built from the provided json string.
@ -1847,11 +1848,10 @@ export interface Path extends EmbindObject<Path> {
* in pts array. If close is true, appends kClose_Verb to Path, connecting
* pts[count - 1] and pts[0].
* Returns the modified path for easier chaining.
* @param points - either an array of 2-arrays representing points or a malloc'd object of
* length n to represent 2*n points. Even indices are x, odd are y.
* @param close - should add a line connecting last point to the first point.
* @param points
* @param close - if true, will add a line connecting last point to the first point.
*/
addPoly(points: MallocObj | number[][], close: boolean): Path;
addPoly(points: InputFlattenedPointArray, close: boolean): Path;
/**
* Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
@ -3427,9 +3427,10 @@ export type InputFlattenedRectangleArray = MallocObj | FlattenedRectangleArray |
/**
* Some APIs accept a flattened array of colors in one of two ways - groups of 4 float values for
* r, g, b, a or just integers that have 8 bits for each these. CanvasKit will detect which one
* it is and act accordingly.
* it is and act accordingly. Additionally, this can be an array of Float32Arrays of length 4
* (e.g. Color). This is convenient for things like gradients when matching up colors to stops.
*/
export type InputFlexibleColorArray = Float32Array | Uint32Array;
export type InputFlexibleColorArray = Float32Array | Uint32Array | Float32Array[];
/**
* CanvasKit APIs accept all of these matrix types. Under the hood, we generally use 4x4 matrices.
*/

View File

@ -39,7 +39,7 @@ fi
if [[ $@ == *debug* ]]; then
echo "Building a Debug build"
EXTRA_CFLAGS="\"-DSK_DEBUG\","
RELEASE_CONF="-O0 --js-opts 0 -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=1 -s GL_ASSERTIONS=1 -g4 \
RELEASE_CONF="-O0 --js-opts 0 -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=1 -s GL_ASSERTIONS=1 -g3 \
--source-map-base /node_modules/canvaskit/bin/ -DSK_DEBUG --pre-js $BASE_DIR/debug.js"
BUILD_DIR=${BUILD_DIR:="out/canvaskit_wasm_debug"}
elif [[ $@ == *profiling* ]]; then

View File

@ -15,7 +15,7 @@ CanvasKit.Color = function(r, g, b, a) {
a = 1;
}
return CanvasKit.Color4f(clamp(r)/255, clamp(g)/255, clamp(b)/255, a);
}
};
// Constructs a Color as a 32 bit unsigned integer, with 8 bits assigned to each channel.
// Channels are expected to be between 0 and 255 and will be clamped as such.
@ -31,7 +31,7 @@ CanvasKit.ColorAsInt = function(r, g, b, a) {
& 0xFFFFFFF) // This truncates the unsigned to 32 bits and signals to JS engines they can
// represent the number with an int instead of a double.
>>> 0); // This makes the value an unsigned int.
}
};
// Construct a 4-float color.
// Opaque if opacity is omitted.
CanvasKit.Color4f = function(r, g, b, a) {
@ -39,7 +39,7 @@ CanvasKit.Color4f = function(r, g, b, a) {
a = 1;
}
return Float32Array.of(r, g, b, a);
}
};
// Color constants use property getters to prevent other code from accidentally
// changing them.
@ -81,7 +81,7 @@ CanvasKit.getColorComponents = function(color) {
Math.floor(color[2]*255),
color[3]
];
}
};
// parseColorString takes in a CSS color value and returns a CanvasKit.Color
// (which is an array of 4 floats in RGBA order). An optional colorMap
@ -140,7 +140,7 @@ CanvasKit.parseColorString = function(colorStr, colorMap) {
}
Debug('unrecognized color ' + colorStr);
return CanvasKit.BLACK;
}
};
function isCanvasKitColor(ob) {
if (!ob) {
@ -195,7 +195,7 @@ CanvasKit.multiplyByAlpha = function(color, alpha) {
var result = color.slice();
result[3] = Math.max(0, Math.min(result[3] * alpha, 1));
return result;
}
};
function radiansToDegrees(rad) {
return (rad / Math.PI) * 180;
@ -249,46 +249,18 @@ function copy1dArray(arr, dest, ptr) {
return ptr;
}
// arr should be a non-jagged 2d JS array (TypedArrays can't be nested
// inside themselves). A common use case is points.
// dest is something like CanvasKit.HEAPF32
// ptr can be optionally provided if the memory was already allocated.
// TODO(kjlubick): Remove 2d arrays - everything should be flat.
function copy2dArray(arr, dest, ptr) {
if (!arr || !arr.length) {
return nullptr;
}
var bytesPerElement = CanvasKit[dest].BYTES_PER_ELEMENT;
if (!ptr) {
ptr = CanvasKit._malloc(arr.length * arr[0].length * bytesPerElement);
}
// Make sure we have a fresh view of the heap after we malloc.
dest = CanvasKit[dest];
var idx = 0;
var adjustedPtr = ptr / bytesPerElement;
for (var r = 0; r < arr.length; r++) {
for (var c = 0; c < arr[0].length; c++) {
dest[adjustedPtr + idx] = arr[r][c];
idx++;
}
}
return ptr;
}
// Copies an array of colors to wasm, returning an object with the pointer
// and info necessary to use the copied colors.
// Accepts either a flat Float32Array, flat Uint32Array or Array of Float32Arrays.
// If color is an object that was allocated with CanvasKit.Malloc, its pointer is
// returned and no extra copy is performed.
// Array of Float32Arrays is deprecated and planned to be removed, prefer flat
// Float32Array
// TODO(nifong): have this accept color builders.
function copyFlexibleColorArray(colors) {
var result = {
colorPtr: nullptr,
count: colors.length,
colorType: CanvasKit.ColorType.RGBA_F32,
}
};
if (colors instanceof Float32Array) {
result.colorPtr = copy1dArray(colors, 'HEAPF32');
result.count = colors.length / 4;
@ -297,14 +269,32 @@ function copyFlexibleColorArray(colors) {
result.colorPtr = copy1dArray(colors, 'HEAPU32');
result.colorType = CanvasKit.ColorType.RGBA_8888;
} else if (colors instanceof Array && colors[0] instanceof Float32Array) {
result.colorPtr = copy2dArray(colors, 'HEAPF32');
} else if (colors instanceof Array) {
result.colorPtr = copyColorArray(colors);
} else {
throw('Invalid argument to copyFlexibleColorArray, Not a color array '+typeof(colors));
}
return result;
}
function copyColorArray(arr) {
if (!arr || !arr.length) {
return nullptr;
}
// 4 floats per color, 4 bytes per float.
var ptr = CanvasKit._malloc(arr.length * 4 * 4);
var idx = 0;
var adjustedPtr = ptr / 4; // cast the byte pointer into a float pointer.
for (var r = 0; r < arr.length; r++) {
for (var c = 0; c < 4; c++) {
CanvasKit.HEAPF32[adjustedPtr + idx] = arr[r][c];
idx++;
}
}
return ptr;
}
var defaultPerspective = Float32Array.of(0, 0, 1);
var _scratch3x3MatrixPtr = nullptr;
@ -575,7 +565,7 @@ CanvasKit.FourFloatArrayHelper = function() {
return this._floats.length / 4;
},
});
}
};
/**
* push the four floats onto the end of the array - if build() has already
@ -587,7 +577,7 @@ CanvasKit.FourFloatArrayHelper.prototype.push = function(f1, f2, f3, f4) {
return;
}
this._floats.push(f1, f2, f3, f4);
}
};
/**
* Set the four floats at a given index - if build() has already
@ -613,7 +603,7 @@ CanvasKit.FourFloatArrayHelper.prototype.set = function(idx, f1, f2, f3, f4) {
this._floats[idx + 1] = f2;
this._floats[idx + 2] = f3;
this._floats[idx + 3] = f4;
}
};
/**
* Copies the float data to the WASM memory and returns a pointer
@ -626,7 +616,7 @@ CanvasKit.FourFloatArrayHelper.prototype.build = function() {
}
this._ptr = copy1dArray(this._floats, 'HEAPF32');
return this._ptr;
}
};
/**
* Frees the wasm memory associated with this array. Of note,
@ -639,7 +629,7 @@ CanvasKit.FourFloatArrayHelper.prototype.delete = function() {
CanvasKit._free(this._ptr);
this._ptr = null;
}
}
};
/**
* Generic helper for dealing with an array of unsigned ints.
@ -654,7 +644,7 @@ CanvasKit.OneUIntArrayHelper = function() {
return this._uints.length;
},
});
}
};
/**
* push the unsigned int onto the end of the array - if build() has already
@ -666,7 +656,7 @@ CanvasKit.OneUIntArrayHelper.prototype.push = function(u) {
return;
}
this._uints.push(u);
}
};
/**
* Set the uint at a given index - if build() has already
@ -686,7 +676,7 @@ CanvasKit.OneUIntArrayHelper.prototype.set = function(idx, u) {
return;
}
this._uints[idx] = u;
}
};
/**
* Copies the uint data to the WASM memory and returns a pointer
@ -699,7 +689,7 @@ CanvasKit.OneUIntArrayHelper.prototype.build = function() {
}
this._ptr = copy1dArray(this._uints, 'HEAPU32');
return this._ptr;
}
};
/**
* Frees the wasm memory associated with this array. Of note,
@ -712,7 +702,7 @@ CanvasKit.OneUIntArrayHelper.prototype.delete = function() {
CanvasKit._free(this._ptr);
this._ptr = null;
}
}
};
/**
* Helper for building an array of Rects (which are just structs

View File

@ -653,23 +653,12 @@ CanvasKit.onRuntimeInitialized = function() {
return this;
};
// points is either an array of [x, y] where x and y are numbers or
// a typed array from Malloc where the even indices will be treated
// as x coordinates and the odd indices will be treated as y coordinates.
// points is a 1d array of length 2n representing n points where the even indices
// will be treated as x coordinates and the odd indices will be treated as y coordinates.
// Like other APIs, this accepts a malloced type array or malloc obj.
CanvasKit.Path.prototype.addPoly = function(points, close) {
var ptr;
var n;
// This was created with CanvasKit.Malloc, so assume the user has
// already been filled with data.
if (points['_ck']) {
ptr = points.byteOffset;
n = points.length/2;
} else {
// TODO(kjlubick) deprecate and remove the 2d array input
ptr = copy2dArray(points, 'HEAPF32');
n = points.length;
}
this._addPoly(ptr, n, close);
var ptr = copy1dArray(points, 'HEAPF32');
this._addPoly(ptr, points.length / 2, close);
freeArraysThatAreNotMallocedByUsers(ptr, points);
return this;
};
@ -1533,12 +1522,12 @@ CanvasKit.MakeImage = function(info, pixels, bytesPerRow) {
// Colors may be a Uint32Array of int colors, a Flat Float32Array of float colors
// or a 2d Array of Float32Array(4) (deprecated)
// the underlying skia function accepts only int colors so it is recommended
// the underlying Skia function accepts only int colors so it is recommended
// to pass an array of int colors to avoid an extra conversion.
// ColorBuilder is not accepted.
CanvasKit.MakeVertices = function(mode, positions, textureCoordinates, colors,
indices, isVolatile) {
// Default isVolitile to true if not set
// Default isVolatile to true if not set
isVolatile = isVolatile === undefined ? true : isVolatile;
var idxCount = (indices && indices.length) || 0;
@ -1554,11 +1543,11 @@ CanvasKit.MakeVertices = function(mode, positions, textureCoordinates, colors,
flags |= (1 << 2);
}
var builder = new CanvasKit._VerticesBuilder(mode, positions.length, idxCount, flags);
var builder = new CanvasKit._VerticesBuilder(mode, positions.length / 2, idxCount, flags);
copy2dArray(positions, 'HEAPF32', builder.positions());
copy1dArray(positions, 'HEAPF32', builder.positions());
if (builder.texCoords()) {
copy2dArray(textureCoordinates, 'HEAPF32', builder.texCoords());
copy1dArray(textureCoordinates, 'HEAPF32', builder.texCoords());
}
if (builder.colors()) {
if (colors.build) {

View File

@ -132,11 +132,18 @@
if (s['shadows']) {
var shadows = s['shadows'];
var shadowColors = shadows.map(function(s) { return s['color'] || CanvasKit.BLACK; });
var shadowOffsets = shadows.map(function(s) { return s['offset'] || [0, 0]; });
var shadowBlurRadii = shadows.map(function(s) { return s['blurRadius'] || 0.0; });
s['_shadowLen'] = shadows.length;
var ptr = CanvasKit._malloc(shadows.length * 2, 'HEAPF32');
var adjustedPtr = ptr / 4; // 4 bytes per float
for (var i = 0; i < shadows.length; i++) {
var offset = shadows[i]['offset'] || [0, 0];
CanvasKit.HEAPF32[adjustedPtr] = offset[0];
CanvasKit.HEAPF32[adjustedPtr + 1] = offset[1];
adjustedPtr += 2;
}
s['_shadowColorsPtr'] = copyFlexibleColorArray(shadowColors).colorPtr;
s['_shadowOffsetsPtr'] = copy2dArray(shadowOffsets, 'HEAPF32');
s['_shadowOffsetsPtr'] = ptr;
s['_shadowBlurRadiiPtr'] = copy1dArray(shadowBlurRadii, 'HEAPF32');
} else {
s['_shadowLen'] = 0;

View File

@ -648,7 +648,7 @@ describe('Canvas Behavior', () => {
const paint = new CanvasKit.Paint();
paint.setAntiAlias(true);
const points = [[ 0, 0 ], [ 250, 0 ], [ 100, 100 ], [ 0, 250 ]];
const points = [0, 0, 250, 0, 100, 100, 0, 250];
// 2d float color array
const colors = [CanvasKit.RED, CanvasKit.BLUE,
CanvasKit.YELLOW, CanvasKit.CYAN];
@ -667,7 +667,7 @@ describe('Canvas Behavior', () => {
const paint = new CanvasKit.Paint();
paint.setAntiAlias(true);
const points = [[ 0, 0 ], [ 250, 0 ], [ 100, 100 ], [ 0, 250 ]];
const points = [0, 0, 250, 0, 100, 100, 0, 250];
// 1d float color array
const colors = Float32Array.of(...CanvasKit.RED, ...CanvasKit.BLUE,
...CanvasKit.YELLOW, ...CanvasKit.CYAN);
@ -689,12 +689,12 @@ describe('Canvas Behavior', () => {
paint.setAntiAlias(true);
const points = [
[ 70, 170 ], [ 40, 90 ], [ 130, 150 ], [ 100, 50 ],
[ 225, 150 ], [ 225, 60 ], [ 310, 180 ], [ 330, 100 ]
70, 170, 40, 90, 130, 150, 100, 50,
225, 150, 225, 60, 310, 180, 330, 100,
];
const textureCoordinates = [
[ 0, 240 ], [ 0, 0 ], [ 80, 240 ], [ 80, 0 ],
[ 160, 240 ], [ 160, 0 ], [ 240, 240 ], [ 240, 0 ]
0, 240, 0, 0, 80, 240, 80, 0,
160, 240, 160, 0, 240, 240, 240, 0,
];
const vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TrianglesStrip,
points, textureCoordinates, null /* colors */, false /*isVolatile*/);

View File

@ -433,7 +433,7 @@ describe('Path Behavior', () => {
paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
paint.setStyle(CanvasKit.PaintStyle.Stroke);
const points = [[5, 5], [30, 20], [55, 5], [55, 50], [30, 30], [5, 50]];
const points = [5, 5, 30, 20, 55, 5, 55, 50, 30, 30, 5, 50];
const pointsObj = CanvasKit.Malloc(Float32Array, 6 * 2);
const mPoints = pointsObj.toTypedArray();