ed827bcf91
Change-Id: Iea50f4fb6cdd611ceeb77e5ab1dfe6e703ca201d Reviewed-on: https://skia-review.googlesource.com/c/skia/+/293681 Reviewed-by: Kevin Lubick <kjlubick@google.com> Commit-Queue: Nathaniel Nifong <nifong@google.com>
794 lines
31 KiB
JavaScript
794 lines
31 KiB
JavaScript
describe('Core canvas behavior', () => {
|
|
let container;
|
|
|
|
beforeEach(async () => {
|
|
await LoadCanvasKit;
|
|
container = document.createElement('div');
|
|
container.innerHTML = `
|
|
<canvas width=600 height=600 id=test></canvas>
|
|
<canvas width=600 height=600 id=report></canvas>`;
|
|
document.body.appendChild(container);
|
|
});
|
|
|
|
afterEach(() => {
|
|
document.body.removeChild(container);
|
|
});
|
|
|
|
gm('picture_test', (canvas) => {
|
|
const spr = new CanvasKit.SkPictureRecorder();
|
|
const rcanvas = spr.beginRecording(
|
|
CanvasKit.LTRBRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT));
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setStrokeWidth(2.0);
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
|
|
paint.setStyle(CanvasKit.PaintStyle.Stroke);
|
|
|
|
rcanvas.drawRoundRect(CanvasKit.LTRBRect(5, 35, 45, 80), 15, 10, paint);
|
|
|
|
const font = new CanvasKit.SkFont(null, 20);
|
|
rcanvas.drawText('this picture has a round rect', 5, 100, paint, font);
|
|
const pic = spr.finishRecordingAsPicture();
|
|
spr.delete();
|
|
paint.delete();
|
|
|
|
canvas.drawPicture(pic);
|
|
|
|
// test that file saving functionality throws no errors
|
|
// Unfortunately jasmine spy objects can't fake their type so we can't verify it downloads
|
|
// a nonzero sized file.
|
|
pic.saveAsFile('foo.skp');
|
|
|
|
pic.delete();
|
|
});
|
|
|
|
const uIntColorToCanvasKitColor = (c) => {
|
|
return CanvasKit.Color(
|
|
(c >> 16) & 0xFF,
|
|
(c >> 8) & 0xFF,
|
|
(c >> 0) & 0xFF,
|
|
((c >> 24) & 0xFF) / 255
|
|
);
|
|
}
|
|
|
|
it('can compute tonal colors', () => {
|
|
const input = {
|
|
ambient: CanvasKit.BLUE,
|
|
spot: CanvasKit.RED,
|
|
};
|
|
const out = CanvasKit.computeTonalColors(input);
|
|
expect(new Float32Array(out.ambient)).toEqual(CanvasKit.BLACK);
|
|
const expectedSpot = [0.173, 0, 0, 0.969];
|
|
expect(out.spot.length).toEqual(4);
|
|
expect(out.spot[0]).toBeCloseTo(expectedSpot[0], 3);
|
|
expect(out.spot[1]).toBeCloseTo(expectedSpot[1], 3);
|
|
expect(out.spot[2]).toBeCloseTo(expectedSpot[2], 3);
|
|
expect(out.spot[3]).toBeCloseTo(expectedSpot[3], 3);
|
|
});
|
|
|
|
// This helper is used for all the MakeImageFromEncoded tests.
|
|
// TODO(kjlubick): rewrite this and callers to use gm
|
|
function decodeAndDrawSingleFrameImage(imgName, goldName, done) {
|
|
const imgPromise = fetch(imgName)
|
|
.then((response) => response.arrayBuffer());
|
|
Promise.all([imgPromise, LoadCanvasKit]).then((values) => {
|
|
const imgData = values[0];
|
|
expect(imgData).toBeTruthy();
|
|
catchException(done, () => {
|
|
let img = CanvasKit.MakeImageFromEncoded(imgData);
|
|
expect(img).toBeTruthy();
|
|
const surface = CanvasKit.MakeCanvasSurface('test');
|
|
expect(surface).toBeTruthy('Could not make surface');
|
|
if (!surface) {
|
|
done();
|
|
return;
|
|
}
|
|
const canvas = surface.getCanvas();
|
|
let paint = new CanvasKit.SkPaint();
|
|
canvas.drawImage(img, 0, 0, paint);
|
|
|
|
paint.delete();
|
|
img.delete();
|
|
|
|
reportSurface(surface, goldName, done);
|
|
})();
|
|
});
|
|
}
|
|
|
|
it('can decode and draw a png', (done) => {
|
|
decodeAndDrawSingleFrameImage('/assets/mandrill_512.png', 'drawImage_png', done);
|
|
});
|
|
|
|
it('can decode and draw a jpg', (done) => {
|
|
decodeAndDrawSingleFrameImage('/assets/mandrill_h1v1.jpg', 'drawImage_jpg', done);
|
|
});
|
|
|
|
it('can decode and draw a (still) gif', (done) => {
|
|
decodeAndDrawSingleFrameImage('/assets/flightAnim.gif', 'drawImage_gif', done);
|
|
});
|
|
|
|
it('can decode and draw a still webp', (done) => {
|
|
decodeAndDrawSingleFrameImage('/assets/color_wheel.webp', 'drawImage_webp', done);
|
|
});
|
|
|
|
it('can readPixels from an SkImage', (done) => {
|
|
const imgPromise = fetch('/assets/mandrill_512.png')
|
|
.then((response) => response.arrayBuffer());
|
|
Promise.all([imgPromise, LoadCanvasKit]).then((values) => {
|
|
const imgData = values[0];
|
|
expect(imgData).toBeTruthy();
|
|
catchException(done, () => {
|
|
let img = CanvasKit.MakeImageFromEncoded(imgData);
|
|
expect(img).toBeTruthy();
|
|
const imageInfo = {
|
|
alphaType: CanvasKit.AlphaType.Unpremul,
|
|
colorType: CanvasKit.ColorType.RGBA_8888,
|
|
colorSpace: CanvasKit.SkColorSpace.SRGB,
|
|
width: img.width(),
|
|
height: img.height(),
|
|
};
|
|
|
|
const pixels = img.readPixels(imageInfo, 0, 0);
|
|
// We know the image is 512 by 512 pixels in size, each pixel
|
|
// requires 4 bytes (R, G, B, A).
|
|
expect(pixels.length).toEqual(512 * 512 * 4);
|
|
|
|
img.delete();
|
|
done();
|
|
})();
|
|
});
|
|
});
|
|
|
|
gm('drawDrawable_animated_gif', (canvas, fetchedByteBuffers) => {
|
|
let aImg = CanvasKit.MakeAnimatedImageFromEncoded(fetchedByteBuffers[0]);
|
|
expect(aImg).toBeTruthy();
|
|
expect(aImg.getRepetitionCount()).toEqual(-1); // infinite loop
|
|
expect(aImg.width()).toEqual(320);
|
|
expect(aImg.height()).toEqual(240);
|
|
expect(aImg.getFrameCount()).toEqual(60);
|
|
// TODO(kjlubick): deprecate drawAnimatedImage and have it just snap off
|
|
// an SkImage at the desired frame.
|
|
|
|
canvas.drawAnimatedImage(aImg, 0, 0);
|
|
|
|
let c = aImg.decodeNextFrame();
|
|
expect(c).not.toEqual(-1);
|
|
canvas.drawAnimatedImage(aImg, 300, 0);
|
|
for(let i = 0; i < 10; i++) {
|
|
c = aImg.decodeNextFrame();
|
|
expect(c).not.toEqual(-1);
|
|
}
|
|
canvas.drawAnimatedImage(aImg, 0, 300);
|
|
for(let i = 0; i < 10; i++) {
|
|
c = aImg.decodeNextFrame();
|
|
expect(c).not.toEqual(-1);
|
|
}
|
|
canvas.drawAnimatedImage(aImg, 300, 300);
|
|
|
|
aImg.delete();
|
|
}, '/assets/flightAnim.gif');
|
|
|
|
gm('1x4_from_scratch', (canvas) => {
|
|
canvas.clear(CanvasKit.WHITE);
|
|
const paint = new CanvasKit.SkPaint();
|
|
|
|
// This creates and draws an SkImage that is 1 pixel wide, 4 pixels tall with
|
|
// the colors listed below.
|
|
const pixels = Uint8Array.from([
|
|
255, 0, 0, 255, // opaque red
|
|
0, 255, 0, 255, // opaque green
|
|
0, 0, 255, 255, // opaque blue
|
|
255, 0, 255, 100, // transparent purple
|
|
]);
|
|
const img = CanvasKit.MakeImage(pixels, 1, 4, CanvasKit.AlphaType.Unpremul, CanvasKit.ColorType.RGBA_8888,
|
|
CanvasKit.SkColorSpace.SRGB);
|
|
canvas.drawImage(img, 1, 1, paint);
|
|
img.delete();
|
|
});
|
|
|
|
gm('sweep_gradient', (canvas) => {
|
|
const paint = new CanvasKit.SkPaint();
|
|
const shader = CanvasKit.SkShader.MakeSweepGradient(
|
|
100, 100, // X, Y coordinates
|
|
[CanvasKit.GREEN, CanvasKit.BLUE],
|
|
[0.0, 1.0],
|
|
CanvasKit.TileMode.Clamp,
|
|
);
|
|
expect(shader).toBeTruthy('Could not make shader');
|
|
|
|
paint.setShader(shader);
|
|
canvas.drawPaint(paint);
|
|
|
|
paint.delete();
|
|
shader.delete();
|
|
});
|
|
|
|
// TODO(kjlubick): There's a lot of shared code between the gradient gms
|
|
// It would be best to deduplicate that in a nice DAMP way.
|
|
// Inspired by https://fiddle.skia.org/c/b29ce50a341510784ac7d5281586d076
|
|
gm('linear_gradients', (canvas) => {
|
|
canvas.clear(CanvasKit.WHITE);
|
|
canvas.scale(2, 2);
|
|
const strokePaint = new CanvasKit.SkPaint();
|
|
strokePaint.setStyle(CanvasKit.PaintStyle.Stroke);
|
|
strokePaint.setColor(CanvasKit.BLACK);
|
|
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setStyle(CanvasKit.PaintStyle.Fill);
|
|
const transparentGreen = CanvasKit.Color(0, 255, 255, 0);
|
|
|
|
const lgs = CanvasKit.SkShader.MakeLinearGradient(
|
|
[0, 0], [50, 100], // start and stop points
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror
|
|
);
|
|
paint.setShader(lgs);
|
|
let r = CanvasKit.LTRBRect(0, 0, 100, 100);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const lgsPremul = CanvasKit.SkShader.MakeLinearGradient(
|
|
[100, 0], [150, 100], // start and stop points
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
null, // no local matrix
|
|
1 // interpolate colors in premul
|
|
);
|
|
paint.setShader(lgsPremul);
|
|
r = CanvasKit.LTRBRect(100, 0, 200, 100);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const lgs45 = CanvasKit.SkShader.MakeLinearGradient(
|
|
[0, 100], [50, 200], // start and stop points
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
CanvasKit.SkMatrix.rotated(Math.PI/4, 0, 100),
|
|
);
|
|
paint.setShader(lgs45);
|
|
r = CanvasKit.LTRBRect(0, 100, 100, 200);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const lgs45Premul = CanvasKit.SkShader.MakeLinearGradient(
|
|
[100, 100], [150, 200], // start and stop points
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
CanvasKit.SkMatrix.rotated(Math.PI/4, 100, 100),
|
|
1 // interpolate colors in premul
|
|
);
|
|
paint.setShader(lgs45Premul);
|
|
r = CanvasKit.LTRBRect(100, 100, 200, 200);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
lgs.delete();
|
|
lgs45.delete();
|
|
lgsPremul.delete();
|
|
lgs45Premul.delete();
|
|
strokePaint.delete();
|
|
paint.delete();
|
|
});
|
|
|
|
gm('radial_gradients', (canvas) => {
|
|
canvas.clear(CanvasKit.WHITE);
|
|
canvas.scale(2, 2);
|
|
const strokePaint = new CanvasKit.SkPaint();
|
|
strokePaint.setStyle(CanvasKit.PaintStyle.Stroke);
|
|
strokePaint.setColor(CanvasKit.BLACK);
|
|
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setStyle(CanvasKit.PaintStyle.Fill);
|
|
const transparentGreen = CanvasKit.Color(0, 255, 255, 0);
|
|
|
|
const rgs = CanvasKit.SkShader.MakeRadialGradient(
|
|
[50, 50], 50, // center, radius
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror
|
|
);
|
|
paint.setShader(rgs);
|
|
let r = CanvasKit.LTRBRect(0, 0, 100, 100);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const rgsPremul = CanvasKit.SkShader.MakeRadialGradient(
|
|
[150, 50], 50, // center, radius
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
null, // no local matrix
|
|
1 // interpolate colors in premul
|
|
);
|
|
paint.setShader(rgsPremul);
|
|
r = CanvasKit.LTRBRect(100, 0, 200, 100);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const rgsSkew = CanvasKit.SkShader.MakeRadialGradient(
|
|
[50, 150], 50, // center, radius
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
CanvasKit.SkMatrix.skewed(0.5, 0, 100, 100),
|
|
null, // color space
|
|
);
|
|
paint.setShader(rgsSkew);
|
|
r = CanvasKit.LTRBRect(0, 100, 100, 200);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const rgsSkewPremul = CanvasKit.SkShader.MakeRadialGradient(
|
|
[150, 150], 50, // center, radius
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
CanvasKit.SkMatrix.skewed(0.5, 0, 100, 100),
|
|
1, // interpolate colors in premul
|
|
null, // color space
|
|
);
|
|
paint.setShader(rgsSkewPremul);
|
|
r = CanvasKit.LTRBRect(100, 100, 200, 200);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
rgs.delete();
|
|
rgsPremul.delete();
|
|
rgsSkew.delete();
|
|
rgsSkewPremul.delete();
|
|
strokePaint.delete();
|
|
paint.delete();
|
|
});
|
|
|
|
gm('conical_gradients', (canvas) => {
|
|
canvas.clear(CanvasKit.WHITE);
|
|
canvas.scale(2, 2);
|
|
const strokePaint = new CanvasKit.SkPaint();
|
|
strokePaint.setStyle(CanvasKit.PaintStyle.Stroke);
|
|
strokePaint.setColor(CanvasKit.BLACK);
|
|
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setStyle(CanvasKit.PaintStyle.Fill);
|
|
paint.setAntiAlias(true);
|
|
const transparentGreen = CanvasKit.Color(0, 255, 255, 0);
|
|
|
|
const cgs = CanvasKit.SkShader.MakeTwoPointConicalGradient(
|
|
[80, 10], 15, // start, radius
|
|
[10, 110], 60, // end, radius
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
null, // color space
|
|
);
|
|
paint.setShader(cgs);
|
|
let r = CanvasKit.LTRBRect(0, 0, 100, 100);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const cgsPremul = CanvasKit.SkShader.MakeTwoPointConicalGradient(
|
|
[180, 10], 15, // start, radius
|
|
[110, 110], 60, // end, radius
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
null, // no local matrix
|
|
1, // interpolate colors in premul
|
|
null, // color space
|
|
);
|
|
paint.setShader(cgsPremul);
|
|
r = CanvasKit.LTRBRect(100, 0, 200, 100);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const cgs45 = CanvasKit.SkShader.MakeTwoPointConicalGradient(
|
|
[80, 110], 15, // start, radius
|
|
[10, 210], 60, // end, radius
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
CanvasKit.SkMatrix.rotated(Math.PI/4, 0, 100),
|
|
null, // color space
|
|
);
|
|
paint.setShader(cgs45);
|
|
r = CanvasKit.LTRBRect(0, 100, 100, 200);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
const cgs45Premul = CanvasKit.SkShader.MakeTwoPointConicalGradient(
|
|
[180, 110], 15, // start, radius
|
|
[110, 210], 60, // end, radius
|
|
[transparentGreen, CanvasKit.BLUE, CanvasKit.RED],
|
|
[0, 0.65, 1.0],
|
|
CanvasKit.TileMode.Mirror,
|
|
CanvasKit.SkMatrix.rotated(Math.PI/4, 100, 100),
|
|
1, // interpolate colors in premul
|
|
null, // color space
|
|
);
|
|
paint.setShader(cgs45Premul);
|
|
r = CanvasKit.LTRBRect(100, 100, 200, 200);
|
|
canvas.drawRect(r, paint);
|
|
canvas.drawRect(r, strokePaint);
|
|
|
|
cgs.delete();
|
|
cgsPremul.delete();
|
|
cgs45.delete();
|
|
strokePaint.delete();
|
|
paint.delete();
|
|
});
|
|
|
|
gm('blur_filters', (canvas) => {
|
|
const pathUL = starPath(CanvasKit, 100, 100, 80);
|
|
const pathBR = starPath(CanvasKit, 400, 300, 80);
|
|
const paint = new CanvasKit.SkPaint();
|
|
const textFont = new CanvasKit.SkFont(null, 24);
|
|
|
|
canvas.drawText('Above: MaskFilter', 20, 220, paint, textFont);
|
|
canvas.drawText('Right: ImageFilter', 20, 260, paint, textFont);
|
|
|
|
paint.setColor(CanvasKit.BLUE);
|
|
|
|
const blurMask = CanvasKit.SkMaskFilter.MakeBlur(CanvasKit.BlurStyle.Normal, 5, true);
|
|
paint.setMaskFilter(blurMask);
|
|
canvas.drawPath(pathUL, paint);
|
|
|
|
const blurIF = CanvasKit.SkImageFilter.MakeBlur(8, 1, CanvasKit.TileMode.Decal, null);
|
|
paint.setImageFilter(blurIF);
|
|
canvas.drawPath(pathBR, paint);
|
|
|
|
pathUL.delete();
|
|
pathBR.delete();
|
|
paint.delete();
|
|
blurMask.delete();
|
|
blurIF.delete();
|
|
textFont.delete();
|
|
});
|
|
|
|
gm('combined_filters', (canvas, fetchedByteBuffers) => {
|
|
const img = CanvasKit.MakeImageFromEncoded(fetchedByteBuffers[0]);
|
|
expect(img).toBeTruthy();
|
|
|
|
canvas.clear(CanvasKit.WHITE);
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(CanvasKit.Color(0, 255, 0, 1.0));
|
|
const redCF = CanvasKit.SkColorFilter.MakeBlend(
|
|
CanvasKit.Color(255, 0, 0, 0.1), CanvasKit.BlendMode.SrcOver);
|
|
const redIF = CanvasKit.SkImageFilter.MakeColorFilter(redCF, null);
|
|
const blurIF = CanvasKit.SkImageFilter.MakeBlur(8, 0.2, CanvasKit.TileMode.Decal, null);
|
|
const combined = CanvasKit.SkImageFilter.MakeCompose(redIF, blurIF);
|
|
|
|
// rotate 10 degrees centered on 200, 200
|
|
const m = CanvasKit.SkMatrix.rotated(Math.PI/18, 200, 200);
|
|
const rotated = CanvasKit.SkImageFilter.MakeMatrixTransform(m, CanvasKit.FilterQuality.Medium, combined);
|
|
paint.setImageFilter(rotated);
|
|
|
|
//canvas.rotate(10, 200, 200);
|
|
canvas.drawImage(img, 0, 0, paint);
|
|
canvas.drawRect(CanvasKit.LTRBRect(5, 35, 45, 80), paint);
|
|
|
|
paint.delete();
|
|
redIF.delete();
|
|
redCF.delete();
|
|
blurIF.delete();
|
|
combined.delete();
|
|
rotated.delete();
|
|
img.delete();
|
|
}, '/assets/mandrill_512.png');
|
|
|
|
gm('animated_filters', (canvas, fetchedByteBuffers) => {
|
|
const img = CanvasKit.MakeAnimatedImageFromEncoded(fetchedByteBuffers[0]);
|
|
expect(img).toBeTruthy();
|
|
img.decodeNextFrame();
|
|
img.decodeNextFrame();
|
|
canvas.clear(CanvasKit.WHITE);
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(CanvasKit.Color(0, 255, 0, 1.0));
|
|
const redCF = CanvasKit.SkColorFilter.MakeBlend(
|
|
CanvasKit.Color(255, 0, 0, 0.1), CanvasKit.BlendMode.SrcOver);
|
|
const redIF = CanvasKit.SkImageFilter.MakeColorFilter(redCF, null);
|
|
const blurIF = CanvasKit.SkImageFilter.MakeBlur(8, 0.2, CanvasKit.TileMode.Decal, null);
|
|
const combined = CanvasKit.SkImageFilter.MakeCompose(redIF, blurIF);
|
|
paint.setImageFilter(combined);
|
|
|
|
const frame = img.getCurrentFrame();
|
|
canvas.drawImage(frame, 100, 50, paint);
|
|
|
|
paint.delete();
|
|
redIF.delete();
|
|
redCF.delete();
|
|
blurIF.delete();
|
|
combined.delete();
|
|
frame.delete();
|
|
img.delete();
|
|
}, '/assets/flightAnim.gif');
|
|
|
|
gm('drawImage_skp', (canvas, fetchedByteBuffers) => {
|
|
const pic = CanvasKit.MakeSkPicture(fetchedByteBuffers[0]);
|
|
expect(pic).toBeTruthy();
|
|
|
|
canvas.clear(CanvasKit.TRANSPARENT);
|
|
canvas.drawPicture(pic);
|
|
}, '/assets/red_line.skp');
|
|
|
|
it('can draw once using drawOnce utility method', (done) => {
|
|
const surface = CanvasKit.MakeCanvasSurface('test');
|
|
expect(surface).toBeTruthy('Could not make surface');
|
|
if (!surface) {
|
|
done();
|
|
return;
|
|
}
|
|
|
|
const drawFrame = (canvas) => {
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setStrokeWidth(1.0);
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
|
|
paint.setStyle(CanvasKit.PaintStyle.Stroke);
|
|
const path = new CanvasKit.SkPath();
|
|
path.moveTo(20, 5);
|
|
path.lineTo(30, 20);
|
|
path.lineTo(40, 10);
|
|
canvas.drawPath(path, paint);
|
|
path.delete();
|
|
paint.delete();
|
|
// surface hasn't been flushed yet (nor should we call flush
|
|
// ourselves), so reportSurface would likely be blank if we
|
|
// were to call it.
|
|
done();
|
|
}
|
|
surface.drawOnce(drawFrame);
|
|
// Reminder: drawOnce is async. In this test, we are just making
|
|
// sure the drawOnce function is there and doesn't crash, so we can
|
|
// just call done() when the frame is rendered.
|
|
});
|
|
|
|
it('can draw client-supplied dirty rects', (done) => {
|
|
// dirty rects are only honored by software (CPU) canvases today.
|
|
const surface = CanvasKit.MakeSWCanvasSurface('test');
|
|
expect(surface).toBeTruthy('Could not make surface');
|
|
if (!surface) {
|
|
done();
|
|
return;
|
|
}
|
|
|
|
const drawFrame = (canvas) => {
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setStrokeWidth(1.0);
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
|
|
paint.setStyle(CanvasKit.PaintStyle.Stroke);
|
|
const path = new CanvasKit.SkPath();
|
|
path.moveTo(20, 5);
|
|
path.lineTo(30, 20);
|
|
path.lineTo(40, 10);
|
|
canvas.drawPath(path, paint);
|
|
path.delete();
|
|
paint.delete();
|
|
done();
|
|
}
|
|
const dirtyRect = CanvasKit.XYWHRect(10, 10, 15, 15);
|
|
surface.drawOnce(drawFrame, dirtyRect);
|
|
// We simply ensure that passing a dirty rect doesn't crash.
|
|
});
|
|
|
|
it('can use DecodeCache APIs', () => {
|
|
const initialLimit = CanvasKit.getDecodeCacheLimitBytes();
|
|
expect(initialLimit).toBeGreaterThan(1024 * 1024);
|
|
|
|
const newLimit = 42 * 1024 * 1024;
|
|
CanvasKit.setDecodeCacheLimitBytes(newLimit);
|
|
expect(CanvasKit.getDecodeCacheLimitBytes()).toEqual(newLimit);
|
|
|
|
// We cannot make any assumptions about this value,
|
|
// so we just make sure it doesn't crash.
|
|
CanvasKit.getDecodeCacheUsedBytes();
|
|
});
|
|
|
|
gm('combined_shaders', (canvas) => {
|
|
const rShader = CanvasKit.SkShader.Color(CanvasKit.Color(255, 0, 0, 1.0));
|
|
const gShader = CanvasKit.SkShader.Color(CanvasKit.Color(0, 255, 0, 0.6));
|
|
const bShader = CanvasKit.SkShader.Color(CanvasKit.Color(0, 0, 255, 1.0));
|
|
|
|
const rgShader = CanvasKit.SkShader.Blend(CanvasKit.BlendMode.SrcOver, rShader, gShader);
|
|
|
|
const p = new CanvasKit.SkPaint();
|
|
p.setShader(rgShader);
|
|
canvas.drawPaint(p);
|
|
|
|
const gbShader = CanvasKit.SkShader.Lerp(0.5, gShader, bShader);
|
|
|
|
p.setShader(gbShader);
|
|
canvas.drawRect(CanvasKit.LTRBRect(5, 100, 300, 400), p);
|
|
rShader.delete();
|
|
gShader.delete();
|
|
bShader.delete();
|
|
rgShader.delete();
|
|
gbShader.delete();
|
|
p.delete();
|
|
});
|
|
|
|
it('exports consts correctly', () => {
|
|
expect(CanvasKit.TRANSPARENT).toEqual(Float32Array.of(0, 0, 0, 0));
|
|
expect(CanvasKit.RED).toEqual(Float32Array.of(1, 0, 0, 1));
|
|
|
|
expect(CanvasKit.QUAD_VERB).toEqual(2);
|
|
expect(CanvasKit.CONIC_VERB).toEqual(3);
|
|
|
|
expect(CanvasKit.SaveLayerInitWithPrevious).toEqual(4);
|
|
expect(CanvasKit.SaveLayerF16ColorType).toEqual(16);
|
|
});
|
|
|
|
it('can set color on a paint and get it as four floats', () => {
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setColor(CanvasKit.Color4f(3.3, 2.2, 1.1, 0.5));
|
|
expect(paint.getColor()).toEqual(Float32Array.of(3.3, 2.2, 1.1, 0.5));
|
|
|
|
paint.setColorComponents(0.5, 0.6, 0.7, 0.8);
|
|
expect(paint.getColor()).toEqual(Float32Array.of(0.5, 0.6, 0.7, 0.8));
|
|
|
|
paint.setColorInt(CanvasKit.ColorAsInt(50, 100, 150, 200));
|
|
let color = paint.getColor();
|
|
expect(color.length).toEqual(4);
|
|
expect(color[0]).toBeCloseTo(50/255, 5); // Red
|
|
expect(color[1]).toBeCloseTo(100/255, 5); // Green
|
|
expect(color[2]).toBeCloseTo(150/255, 5); // Blue
|
|
expect(color[3]).toBeCloseTo(200/255, 5); // Alpha
|
|
|
|
paint.setColorInt(0xFF000000);
|
|
expect(paint.getColor()).toEqual(Float32Array.of(0, 0, 0, 1.0));
|
|
});
|
|
|
|
gm('draw shadow', (canvas) => {
|
|
const lightRadius = 20;
|
|
const flags = 0;
|
|
const lightPos = [500,500,20];
|
|
const zPlaneParams = [0,0,1];
|
|
const path = starPath(CanvasKit);
|
|
|
|
canvas.drawShadow(path, zPlaneParams, lightPos, lightRadius,
|
|
CanvasKit.BLACK, CanvasKit.MAGENTA, flags);
|
|
})
|
|
|
|
describe('ColorSpace Support', () => {
|
|
it('Can create an SRGB 8888 surface', () => {
|
|
const colorSpace = CanvasKit.SkColorSpace.SRGB;
|
|
const surface = CanvasKit.MakeCanvasSurface('test', CanvasKit.SkColorSpace.SRGB);
|
|
expect(surface).toBeTruthy('Could not make surface');
|
|
let info = surface.imageInfo()
|
|
expect(info.alphaType).toEqual(CanvasKit.AlphaType.Unpremul);
|
|
expect(info.colorType).toEqual(CanvasKit.ColorType.RGBA_8888);
|
|
expect(CanvasKit.SkColorSpace.Equals(info.colorSpace, colorSpace))
|
|
.toBeTruthy("Surface not created with correct color space.");
|
|
|
|
const pixels = surface.getCanvas().readPixels(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
|
CanvasKit.AlphaType.Unpremul, CanvasKit.ColorType.RGBA_8888, colorSpace);
|
|
expect(pixels).toBeTruthy('Could not read pixels from surface');
|
|
});
|
|
it('Can create a Display P3 surface', () => {
|
|
const colorSpace = CanvasKit.SkColorSpace.DISPLAY_P3;
|
|
const surface = CanvasKit.MakeCanvasSurface('test', CanvasKit.SkColorSpace.DISPLAY_P3);
|
|
expect(surface).toBeTruthy('Could not make surface');
|
|
if (surface.reportBackendType() !== 'GPU') {
|
|
console.log('Not expecting color space support in cpu backed suface.');
|
|
return;
|
|
}
|
|
let info = surface.imageInfo()
|
|
expect(info.alphaType).toEqual(CanvasKit.AlphaType.Unpremul);
|
|
expect(info.colorType).toEqual(CanvasKit.ColorType.RGBA_F16);
|
|
expect(CanvasKit.SkColorSpace.Equals(info.colorSpace, colorSpace))
|
|
.toBeTruthy("Surface not created with correct color space.");
|
|
|
|
const pixels = surface.getCanvas().readPixels(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
|
CanvasKit.AlphaType.Unpremul, CanvasKit.ColorType.RGBA_F16, colorSpace);
|
|
expect(pixels).toBeTruthy('Could not read pixels from surface');
|
|
});
|
|
it('Can create an Adobe RGB surface', () => {
|
|
const colorSpace = CanvasKit.SkColorSpace.ADOBE_RGB;
|
|
const surface = CanvasKit.MakeCanvasSurface('test', CanvasKit.SkColorSpace.ADOBE_RGB);
|
|
expect(surface).toBeTruthy('Could not make surface');
|
|
if (surface.reportBackendType() !== 'GPU') {
|
|
console.log('Not expecting color space support in cpu backed suface.');
|
|
return;
|
|
}
|
|
let info = surface.imageInfo()
|
|
expect(info.alphaType).toEqual(CanvasKit.AlphaType.Unpremul);
|
|
expect(info.colorType).toEqual(CanvasKit.ColorType.RGBA_F16);
|
|
expect(CanvasKit.SkColorSpace.Equals(info.colorSpace, colorSpace))
|
|
.toBeTruthy("Surface not created with correct color space.");
|
|
|
|
const pixels = surface.getCanvas().readPixels(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
|
CanvasKit.AlphaType.Unpremul, CanvasKit.ColorType.RGBA_F16, colorSpace);
|
|
expect(pixels).toBeTruthy('Could not read pixels from surface');
|
|
});
|
|
|
|
it('combine draws from several color spaces', () => {
|
|
const surface = CanvasKit.MakeCanvasSurface('test', CanvasKit.SkColorSpace.ADOBE_RGB);
|
|
expect(surface).toBeTruthy('Could not make surface');
|
|
if (surface.reportBackendType() !== 'GPU') {
|
|
console.log('Not expecting color space support in cpu backed suface.');
|
|
return;
|
|
}
|
|
const canvas = surface.getCanvas();
|
|
|
|
let paint = new CanvasKit.SkPaint();
|
|
paint.setColor(CanvasKit.RED, CanvasKit.SkColorSpace.ADOBE_RGB);
|
|
canvas.drawPaint(paint);
|
|
paint.setColor(CanvasKit.RED, CanvasKit.SkColorSpace.DISPLAY_P3); // 93.7 in adobeRGB
|
|
canvas.drawRect(CanvasKit.LTRBRect(200, 0, 400, 600), paint);
|
|
paint.setColor(CanvasKit.RED, CanvasKit.SkColorSpace.SRGB); // 85.9 in adobeRGB
|
|
canvas.drawRect(CanvasKit.LTRBRect(400, 0, 600, 600), paint);
|
|
|
|
// this test paints three bands of red, each the maximum red that a color space supports.
|
|
// They are each represented by skia by some color in the Adobe RGB space of the surface,
|
|
// as floats between 0 and 1.
|
|
|
|
// TODO(nifong) readpixels and verify correctness after f32 readpixels bug is fixed
|
|
});
|
|
}); // end describe('ColorSpace Support')
|
|
|
|
describe('DOMMatrix support', () => {
|
|
gm('sweep_gradient_dommatrix', (canvas) => {
|
|
const paint = new CanvasKit.SkPaint();
|
|
const shader = CanvasKit.SkShader.MakeSweepGradient(
|
|
100, 100, // x y coordinates
|
|
[CanvasKit.GREEN, CanvasKit.BLUE],
|
|
[0.0, 1.0],
|
|
CanvasKit.TileMode.Clamp,
|
|
new DOMMatrix().translate(-10, 100),
|
|
);
|
|
expect(shader).toBeTruthy('Could not make shader');
|
|
if (!shader) {
|
|
return;
|
|
}
|
|
|
|
paint.setShader(shader);
|
|
canvas.drawPaint(paint);
|
|
|
|
paint.delete();
|
|
shader.delete();
|
|
});
|
|
|
|
const radiansToDegrees = (rad) => {
|
|
return (rad / Math.PI) * 180;
|
|
}
|
|
|
|
// this should draw the same as concat_with4x4_canvas
|
|
gm('concat_dommatrix', (canvas) => {
|
|
const path = starPath(CanvasKit, CANVAS_WIDTH/2, CANVAS_HEIGHT/2);
|
|
const paint = new CanvasKit.SkPaint();
|
|
paint.setAntiAlias(true);
|
|
canvas.clear(CanvasKit.WHITE);
|
|
canvas.concat(new DOMMatrix().translate(CANVAS_WIDTH/2, 0, 0));
|
|
canvas.concat(new DOMMatrix().rotateAxisAngle(1, 0, 0, radiansToDegrees(Math.PI/3)));
|
|
canvas.concat(new DOMMatrix().rotateAxisAngle(0, 1, 0, radiansToDegrees(Math.PI/4)));
|
|
canvas.concat(new DOMMatrix().rotateAxisAngle(0, 0, 1, radiansToDegrees(Math.PI/16)));
|
|
canvas.concat(new DOMMatrix().translate(-CANVAS_WIDTH/2, 0, 0));
|
|
|
|
const localMatrix = canvas.getLocalToDevice();
|
|
expect4x4MatricesToMatch([
|
|
0.693519, -0.137949, 0.707106, 91.944030,
|
|
0.698150, 0.370924, -0.612372, -209.445297,
|
|
-0.177806, 0.918359, 0.353553, 53.342029,
|
|
0 , 0 , 0 , 1 ], localMatrix);
|
|
|
|
// Draw some stripes to help the eye detect the turn
|
|
const stripeWidth = 10;
|
|
paint.setColor(CanvasKit.BLACK);
|
|
for (let i = 0; i < CANVAS_WIDTH; i += 2*stripeWidth) {
|
|
canvas.drawRect(CanvasKit.LTRBRect(i, 0, i + stripeWidth, CANVAS_HEIGHT), paint);
|
|
}
|
|
|
|
paint.setColor(CanvasKit.YELLOW);
|
|
canvas.drawPath(path, paint);
|
|
paint.delete();
|
|
path.delete();
|
|
});
|
|
}); // end describe('DOMMatrix support')
|
|
|
|
});
|