ddd0a333f4
Instead of using the test font(s), now ship with a small (100k) Monospace font. This can be disabled by: compile.sh no_font ... This saves about 350k (164k gzipped) in binary size. Bug: skia: Change-Id: I195e3b35bea86d0f096066c1c6a44a4b602571f3 Reviewed-on: https://skia-review.googlesource.com/c/176580 Reviewed-by: Ben Wagner <bungeman@google.com>
655 lines
26 KiB
JavaScript
655 lines
26 KiB
JavaScript
// The increased timeout is especially needed with larger binaries
|
|
// like in the debug/gpu build
|
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
|
|
|
|
describe('CanvasKit\'s Canvas 2d Behavior', function() {
|
|
// Note, don't try to print the CanvasKit object - it can cause Karma/Jasmine to lock up.
|
|
var CanvasKit = null;
|
|
const LoadCanvasKit = new Promise(function(resolve, reject) {
|
|
if (CanvasKit) {
|
|
resolve();
|
|
} else {
|
|
CanvasKitInit({
|
|
locateFile: (file) => '/canvaskit/'+file,
|
|
}).then((_CanvasKit) => {
|
|
CanvasKit = _CanvasKit;
|
|
resolve();
|
|
});
|
|
}
|
|
});
|
|
|
|
let container = document.createElement('div');
|
|
document.body.appendChild(container);
|
|
const CANVAS_WIDTH = 600;
|
|
const CANVAS_HEIGHT = 600;
|
|
|
|
beforeEach(function() {
|
|
container.innerHTML = `
|
|
<canvas width=600 height=600 id=test></canvas>`;
|
|
});
|
|
|
|
afterEach(function() {
|
|
container.innerHTML = '';
|
|
});
|
|
|
|
describe('color strings', function() {
|
|
function hex(s) {
|
|
return parseInt(s, 16);
|
|
}
|
|
|
|
it('parses hex color strings', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
const parseColor = CanvasKit._testing.parseColor;
|
|
expect(parseColor('#FED')).toEqual(
|
|
CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), 1));
|
|
expect(parseColor('#FEDC')).toEqual(
|
|
CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), hex('CC')/255));
|
|
expect(parseColor('#fed')).toEqual(
|
|
CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), 1));
|
|
expect(parseColor('#fedc')).toEqual(
|
|
CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), hex('CC')/255));
|
|
done();
|
|
}));
|
|
});
|
|
it('parses rgba color strings', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
const parseColor = CanvasKit._testing.parseColor;
|
|
expect(parseColor('rgba(117, 33, 64, 0.75)')).toEqual(
|
|
CanvasKit.Color(117, 33, 64, 0.75));
|
|
expect(parseColor('rgb(117, 33, 64, 0.75)')).toEqual(
|
|
CanvasKit.Color(117, 33, 64, 0.75));
|
|
expect(parseColor('rgba(117,33,64)')).toEqual(
|
|
CanvasKit.Color(117, 33, 64, 1.0));
|
|
expect(parseColor('rgb(117,33, 64)')).toEqual(
|
|
CanvasKit.Color(117, 33, 64, 1.0));
|
|
done();
|
|
}));
|
|
});
|
|
it('parses named color strings', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
const parseColor = CanvasKit._testing.parseColor;
|
|
expect(parseColor('grey')).toEqual(
|
|
CanvasKit.Color(128, 128, 128, 1.0));
|
|
expect(parseColor('blanchedalmond')).toEqual(
|
|
CanvasKit.Color(255, 235, 205, 1.0));
|
|
expect(parseColor('transparent')).toEqual(
|
|
CanvasKit.Color(0, 0, 0, 0));
|
|
done();
|
|
}));
|
|
});
|
|
|
|
it('properly produces color strings', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
const colorToString = CanvasKit._testing.colorToString;
|
|
|
|
expect(colorToString(CanvasKit.Color(102, 51, 153, 1.0))).toEqual('#663399');
|
|
|
|
expect(colorToString(CanvasKit.Color(255, 235, 205, 0.5))).toEqual(
|
|
'rgba(255, 235, 205, 0.50196078)');
|
|
|
|
done();
|
|
}));
|
|
});
|
|
|
|
it('can multiply colors by alpha', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
const multiplyByAlpha = CanvasKit.multiplyByAlpha;
|
|
|
|
const testCases = [
|
|
{
|
|
inColor: CanvasKit.Color(102, 51, 153, 1.0),
|
|
inAlpha: 1.0,
|
|
outColor: CanvasKit.Color(102, 51, 153, 1.0),
|
|
},
|
|
{
|
|
inColor: CanvasKit.Color(102, 51, 153, 1.0),
|
|
inAlpha: 0.8,
|
|
outColor: CanvasKit.Color(102, 51, 153, 0.8),
|
|
},
|
|
{
|
|
inColor: CanvasKit.Color(102, 51, 153, 0.8),
|
|
inAlpha: 0.7,
|
|
outColor: CanvasKit.Color(102, 51, 153, 0.56),
|
|
},
|
|
{
|
|
inColor: CanvasKit.Color(102, 51, 153, 0.8),
|
|
inAlpha: 1000,
|
|
outColor: CanvasKit.Color(102, 51, 153, 1.0),
|
|
},
|
|
];
|
|
|
|
for (let tc of testCases) {
|
|
// Print out the test case if the two don't match.
|
|
expect(multiplyByAlpha(tc.inColor, tc.inAlpha))
|
|
.toBe(tc.outColor, JSON.stringify(tc));
|
|
}
|
|
|
|
done();
|
|
}));
|
|
});
|
|
}); // end describe('color string parsing')
|
|
|
|
function multipleCanvasTest(testname, done, test) {
|
|
const skcanvas = CanvasKit.MakeCanvas(CANVAS_WIDTH, CANVAS_HEIGHT);
|
|
skcanvas._config = 'software_canvas';
|
|
const realCanvas = document.getElementById('test');
|
|
realCanvas._config = 'html_canvas';
|
|
realCanvas.width = CANVAS_WIDTH;
|
|
realCanvas.height = CANVAS_HEIGHT;
|
|
|
|
let promises = [];
|
|
|
|
for (let canvas of [skcanvas, realCanvas]) {
|
|
test(canvas);
|
|
// canvas has .toDataURL (even though skcanvas is not a real Canvas)
|
|
// so this will work.
|
|
promises.push(reportCanvas(canvas, testname, canvas._config));
|
|
}
|
|
Promise.all(promises).then(() => {
|
|
skcanvas.dispose();
|
|
done();
|
|
}).catch(reportError(done));
|
|
}
|
|
|
|
describe('Path drawing API', function() {
|
|
it('supports all the line types', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
multipleCanvasTest('all_line_drawing_operations', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
ctx.scale(3.0, 3.0);
|
|
ctx.moveTo(20, 5);
|
|
ctx.lineTo(30, 20);
|
|
ctx.lineTo(40, 10);
|
|
ctx.lineTo(50, 20);
|
|
ctx.lineTo(60, 0);
|
|
ctx.lineTo(20, 5);
|
|
|
|
ctx.moveTo(20, 80);
|
|
ctx.bezierCurveTo(90, 10, 160, 150, 190, 10);
|
|
|
|
ctx.moveTo(36, 148);
|
|
ctx.quadraticCurveTo(66, 188, 120, 136);
|
|
ctx.lineTo(36, 148);
|
|
|
|
ctx.rect(5, 170, 20, 25);
|
|
|
|
ctx.moveTo(150, 180);
|
|
ctx.arcTo(150, 100, 50, 200, 20);
|
|
ctx.lineTo(160, 160);
|
|
|
|
ctx.moveTo(20, 120);
|
|
ctx.arc(20, 120, 18, 0, 1.75 * Math.PI);
|
|
ctx.lineTo(20, 120);
|
|
|
|
ctx.moveTo(150, 5);
|
|
ctx.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI)
|
|
|
|
ctx.lineWidth = 2;
|
|
ctx.stroke();
|
|
|
|
// Test edgecases and draw direction
|
|
ctx.beginPath();
|
|
ctx.arc(50, 100, 10, Math.PI, -Math.PI/2);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.arc(75, 100, 10, Math.PI, -Math.PI/2, true);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.arc(100, 100, 10, Math.PI, 100.1 * Math.PI, true);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.arc(125, 100, 10, Math.PI, 100.1 * Math.PI, false);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.ellipse(155, 100, 10, 15, Math.PI/8, 100.1 * Math.PI, Math.PI, true);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.ellipse(180, 100, 10, 15, Math.PI/8, Math.PI, 100.1 * Math.PI, true);
|
|
ctx.stroke();
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('handles all the transforms as specified', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
multipleCanvasTest('all_matrix_operations', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
ctx.rect(10, 10, 20, 20);
|
|
|
|
ctx.scale(2.0, 4.0);
|
|
ctx.rect(30, 10, 20, 20);
|
|
ctx.resetTransform();
|
|
|
|
ctx.rotate(Math.PI / 3);
|
|
ctx.rect(50, 10, 20, 20);
|
|
ctx.resetTransform();
|
|
|
|
ctx.translate(30, -2);
|
|
ctx.rect(70, 10, 20, 20);
|
|
ctx.resetTransform();
|
|
|
|
ctx.translate(60, 0);
|
|
ctx.rotate(Math.PI / 6);
|
|
ctx.transform(1.5, 0, 0, 0.5, 0, 0, 0); // effectively scale
|
|
ctx.rect(90, 10, 20, 20);
|
|
ctx.resetTransform();
|
|
|
|
ctx.save();
|
|
ctx.setTransform(2, 0, -.5, 2.5, -40, 120);
|
|
ctx.rect(110, 10, 20, 20);
|
|
ctx.lineTo(110, 0);
|
|
ctx.restore();
|
|
ctx.lineTo(220, 120);
|
|
|
|
ctx.scale(3.0, 3.0);
|
|
ctx.font = '6pt Noto Mono';
|
|
ctx.fillText('This text should be huge', 10, 80);
|
|
ctx.resetTransform();
|
|
|
|
ctx.strokeStyle = 'black';
|
|
ctx.lineWidth = 2;
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(250, 30);
|
|
ctx.lineTo(250, 80);
|
|
ctx.scale(3.0, 3.0);
|
|
ctx.lineTo(280/3, 90/3);
|
|
ctx.closePath();
|
|
ctx.strokeStyle = 'black';
|
|
ctx.lineWidth = 5;
|
|
ctx.stroke();
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('properly saves and restores states, even when drawing shadows', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
multipleCanvasTest('shadows_and_save_restore', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
ctx.strokeStyle = '#000';
|
|
ctx.fillStyle = '#CCC';
|
|
ctx.shadowColor = 'rebeccapurple';
|
|
ctx.shadowBlur = 1;
|
|
ctx.shadowOffsetX = 3;
|
|
ctx.shadowOffsetY = -8;
|
|
ctx.rect(10, 10, 30, 30);
|
|
|
|
ctx.save();
|
|
ctx.strokeStyle = '#C00';
|
|
ctx.fillStyle = '#00C';
|
|
ctx.shadowBlur = 0;
|
|
ctx.shadowColor = 'transparent';
|
|
|
|
ctx.stroke();
|
|
|
|
ctx.restore();
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(36, 148);
|
|
ctx.quadraticCurveTo(66, 188, 120, 136);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.shadowColor = '#993366AA';
|
|
ctx.shadowOffsetX = 8;
|
|
ctx.shadowBlur = 5;
|
|
ctx.setTransform(2, 0, -.5, 2.5, -40, 120);
|
|
ctx.rect(110, 10, 20, 20);
|
|
ctx.lineTo(110, 0);
|
|
ctx.resetTransform();
|
|
ctx.lineTo(220, 120);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = 'green';
|
|
ctx.font = '16pt Noto Mono';
|
|
ctx.fillText('This should be shadowed', 20, 80);
|
|
|
|
ctx.beginPath();
|
|
ctx.lineWidth = 6;
|
|
ctx.ellipse(10, 290, 30, 30, 0, 0, Math.PI * 2);
|
|
ctx.scale(2, 1);
|
|
ctx.moveTo(10, 290)
|
|
ctx.ellipse(10, 290, 30, 60, 0, 0, Math.PI * 2);
|
|
ctx.resetTransform();
|
|
ctx.shadowColor = '#993366AA';
|
|
ctx.scale(3, 1);
|
|
ctx.moveTo(10, 290)
|
|
ctx.ellipse(10, 290, 30, 90, 0, 0, Math.PI * 2);
|
|
ctx.stroke();
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('fills/strokes rects and supports some global settings', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
multipleCanvasTest('global_dashed_rects', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
ctx.scale(1.1, 1.1);
|
|
ctx.translate(10, 10);
|
|
// Shouldn't impact the fillRect calls
|
|
ctx.setLineDash([5, 3]);
|
|
|
|
ctx.fillStyle = 'rgba(200, 0, 100, 0.81)';
|
|
ctx.fillRect(20, 30, 100, 100);
|
|
|
|
ctx.globalAlpha = 0.81;
|
|
ctx.fillStyle = 'rgba(200, 0, 100, 1.0)';
|
|
ctx.fillRect(120, 30, 100, 100);
|
|
// This shouldn't do anything
|
|
ctx.globalAlpha = 0.1;
|
|
|
|
ctx.fillStyle = 'rgba(200, 0, 100, 0.9)';
|
|
ctx.globalAlpha = 0.9;
|
|
// Intentional no-op to check ordering
|
|
ctx.clearRect(220, 30, 100, 100);
|
|
ctx.fillRect(220, 30, 100, 100);
|
|
|
|
ctx.fillRect(320, 30, 100, 100);
|
|
ctx.clearRect(330, 40, 80, 80);
|
|
|
|
ctx.strokeStyle = 'blue';
|
|
ctx.lineWidth = 3;
|
|
ctx.setLineDash([5, 3]);
|
|
ctx.strokeRect(20, 150, 100, 100);
|
|
ctx.setLineDash([50, 30]);
|
|
ctx.strokeRect(125, 150, 100, 100);
|
|
ctx.lineDashOffset = 25;
|
|
ctx.strokeRect(230, 150, 100, 100);
|
|
ctx.setLineDash([2, 5, 9]);
|
|
ctx.strokeRect(335, 150, 100, 100);
|
|
|
|
ctx.setLineDash([5, 2]);
|
|
ctx.moveTo(336, 400);
|
|
ctx.quadraticCurveTo(366, 488, 120, 450);
|
|
ctx.lineTo(300, 400);
|
|
ctx.stroke();
|
|
|
|
ctx.font = '36pt Noto Mono';
|
|
ctx.strokeText('Dashed', 20, 350);
|
|
ctx.fillText('Not Dashed', 20, 400);
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('supports gradients, which respect clip/save/restore', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
multipleCanvasTest('gradients_clip', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
|
|
var rgradient = ctx.createRadialGradient(200, 300, 10, 100, 100, 300);
|
|
|
|
rgradient.addColorStop(0, 'red');
|
|
rgradient.addColorStop(.7, 'white');
|
|
rgradient.addColorStop(1, 'blue');
|
|
|
|
ctx.fillStyle = rgradient;
|
|
ctx.globalAlpha = 0.7;
|
|
ctx.fillRect(0,0,600,600);
|
|
ctx.globalAlpha = 0.95;
|
|
|
|
ctx.beginPath();
|
|
ctx.arc(300, 100, 90, 0, Math.PI*1.66);
|
|
ctx.closePath();
|
|
ctx.strokeStyle = 'yellow';
|
|
ctx.lineWidth = 5;
|
|
ctx.stroke();
|
|
ctx.save();
|
|
ctx.clip();
|
|
|
|
var lgradient = ctx.createLinearGradient(200, 20, 420, 40);
|
|
|
|
lgradient.addColorStop(0, 'green');
|
|
lgradient.addColorStop(.5, 'cyan');
|
|
lgradient.addColorStop(1, 'orange');
|
|
|
|
ctx.fillStyle = lgradient;
|
|
|
|
ctx.fillRect(200, 30, 200, 300);
|
|
|
|
ctx.restore();
|
|
ctx.fillRect(550, 550, 40, 40);
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('can draw png images', function(done) {
|
|
let skImageData = null;
|
|
let htmlImage = null;
|
|
let skPromise = fetch('/assets/mandrill_512.png')
|
|
.then((response) => response.arrayBuffer())
|
|
.then((buffer) => {
|
|
skImageData = buffer;
|
|
|
|
});
|
|
let realPromise = fetch('/assets/mandrill_512.png')
|
|
.then((response) => response.blob())
|
|
.then((blob) => createImageBitmap(blob))
|
|
.then((bitmap) => {
|
|
htmlImage = bitmap;
|
|
});
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
Promise.all([realPromise, skPromise]).then(() => {
|
|
multipleCanvasTest('draw_image', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
let img = htmlImage;
|
|
if (canvas._config == 'software_canvas') {
|
|
img = canvas.decodeImage(skImageData);
|
|
}
|
|
ctx.drawImage(img, 30, -200);
|
|
|
|
ctx.globalAlpha = 0.7
|
|
ctx.rotate(.1);
|
|
ctx.imageSmoothingQuality = 'medium';
|
|
ctx.drawImage(img, 200, 350, 150, 100);
|
|
ctx.rotate(-.2);
|
|
ctx.imageSmoothingEnabled = false;
|
|
ctx.drawImage(img, 100, 150, 400, 350, 10, 400, 150, 100);
|
|
});
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('can get and put pixels', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
multipleCanvasTest('get_put_imagedata', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
// Make a gradient so we see if the pixels copying worked
|
|
let grad = ctx.createLinearGradient(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
|
grad.addColorStop(0, 'yellow');
|
|
grad.addColorStop(1, 'red');
|
|
ctx.fillStyle = grad;
|
|
ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
|
|
|
let iData = ctx.getImageData(400, 100, 200, 150);
|
|
expect(iData.width).toBe(200);
|
|
expect(iData.height).toBe(150);
|
|
expect(iData.data.byteLength).toBe(200*150*4);
|
|
ctx.putImageData(iData, 10, 10);
|
|
ctx.putImageData(iData, 350, 350, 100, 75, 45, 40);
|
|
ctx.strokeRect(350, 350, 200, 150);
|
|
|
|
let box = ctx.createImageData(20, 40);
|
|
ctx.putImageData(box, 10, 300);
|
|
let biggerBox = ctx.createImageData(iData);
|
|
ctx.putImageData(biggerBox, 10, 350);
|
|
expect(biggerBox.width).toBe(iData.width);
|
|
expect(biggerBox.height).toBe(iData.height);
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('can make patterns', function(done) {
|
|
let skImageData = null;
|
|
let htmlImage = null;
|
|
let skPromise = fetch('/assets/mandrill_512.png')
|
|
.then((response) => response.arrayBuffer())
|
|
.then((buffer) => {
|
|
skImageData = buffer;
|
|
|
|
});
|
|
let realPromise = fetch('/assets/mandrill_512.png')
|
|
.then((response) => response.blob())
|
|
.then((blob) => createImageBitmap(blob))
|
|
.then((bitmap) => {
|
|
htmlImage = bitmap;
|
|
});
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
Promise.all([realPromise, skPromise]).then(() => {
|
|
multipleCanvasTest('draw_patterns', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
let img = htmlImage;
|
|
if (canvas._config == 'software_canvas') {
|
|
img = canvas.decodeImage(skImageData);
|
|
}
|
|
ctx.fillStyle = '#EEE';
|
|
ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
|
ctx.lineWidth = 20;
|
|
ctx.scale(0.2, 0.4);
|
|
|
|
let pattern = ctx.createPattern(img, 'repeat');
|
|
ctx.fillStyle = pattern;
|
|
ctx.fillRect(0, 0, 1500, 750);
|
|
|
|
pattern = ctx.createPattern(img, 'repeat-x');
|
|
ctx.fillStyle = pattern;
|
|
ctx.fillRect(1500, 0, 3000, 750);
|
|
|
|
ctx.globalAlpha = 0.7
|
|
pattern = ctx.createPattern(img, 'repeat-y');
|
|
ctx.fillStyle = pattern;
|
|
ctx.fillRect(0, 750, 1500, 1500);
|
|
ctx.strokeRect(0, 750, 1500, 1500);
|
|
|
|
pattern = ctx.createPattern(img, 'no-repeat');
|
|
ctx.fillStyle = pattern;
|
|
pattern.setTransform({a: 1, b: -.1, c:.1, d: 0.5, e: 1800, f:800});
|
|
ctx.fillRect(0, 0, 3000, 1500);
|
|
});
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('can get and put pixels', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
function drawPoint(ctx, x, y, color) {
|
|
ctx.fillStyle = color;
|
|
ctx.fillRect(x, y, 1, 1);
|
|
}
|
|
const IN = 'purple';
|
|
const OUT = 'orange';
|
|
const SCALE = 8;
|
|
|
|
// Check to see if these points are in or out on each of the
|
|
// test configurations.
|
|
const pts = [[3, 3], [4, 4], [5, 5], [10, 10], [8, 10], [6, 10],
|
|
[6.5, 9], [15, 10], [17, 10], [17, 11], [24, 24],
|
|
[25, 25], [26, 26], [27, 27]];
|
|
const tests = [
|
|
{
|
|
xOffset: 0,
|
|
yOffset: 0,
|
|
fillType: 'nonzero',
|
|
strokeWidth: 0,
|
|
testFn: (ctx, x, y) => ctx.isPointInPath(x * SCALE, y * SCALE, 'nonzero'),
|
|
},
|
|
{
|
|
xOffset: 30,
|
|
yOffset: 0,
|
|
fillType: 'evenodd',
|
|
strokeWidth: 0,
|
|
testFn: (ctx, x, y) => ctx.isPointInPath(x * SCALE, y * SCALE, 'evenodd'),
|
|
},
|
|
{
|
|
xOffset: 0,
|
|
yOffset: 30,
|
|
fillType: null,
|
|
strokeWidth: 1,
|
|
testFn: (ctx, x, y) => ctx.isPointInStroke(x * SCALE, y * SCALE),
|
|
},
|
|
{
|
|
xOffset: 30,
|
|
yOffset: 30,
|
|
fillType: null,
|
|
strokeWidth: 2,
|
|
testFn: (ctx, x, y) => ctx.isPointInStroke(x * SCALE, y * SCALE),
|
|
},
|
|
];
|
|
multipleCanvasTest('points_in_path_stroke', done, (canvas) => {
|
|
let ctx = canvas.getContext('2d');
|
|
ctx.font = '20px Noto Mono';
|
|
// Draw some visual aids
|
|
ctx.fillText('path-nonzero', 60, 30);
|
|
ctx.fillText('path-evenodd', 300, 30);
|
|
ctx.fillText('stroke-1px-wide', 60, 260);
|
|
ctx.fillText('stroke-2px-wide', 300, 260);
|
|
ctx.fillText('purple is IN, orange is OUT', 20, 560);
|
|
|
|
// Scale up to make single pixels easier to see
|
|
ctx.scale(SCALE, SCALE);
|
|
for (let test of tests) {
|
|
ctx.beginPath();
|
|
let xOffset = test.xOffset;
|
|
let yOffset = test.yOffset;
|
|
|
|
ctx.fillStyle = '#AAA';
|
|
ctx.lineWidth = test.strokeWidth;
|
|
ctx.rect(5+xOffset, 5+yOffset, 20, 20);
|
|
ctx.arc(15+xOffset, 15+yOffset, 8, 0, Math.PI*2, false);
|
|
if (test.fillType) {
|
|
ctx.fill(test.fillType);
|
|
} else {
|
|
ctx.stroke();
|
|
}
|
|
|
|
for (let pt of pts) {
|
|
let [x, y] = pt;
|
|
x += xOffset;
|
|
y += yOffset;
|
|
// naively apply transform when querying because the points queried
|
|
// ignore the CTM.
|
|
if (test.testFn(ctx, x, y)) {
|
|
drawPoint(ctx, x, y, IN);
|
|
} else {
|
|
drawPoint(ctx, x, y, OUT);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}));
|
|
});
|
|
|
|
it('can read default properties', function(done) {
|
|
LoadCanvasKit.then(catchException(done, () => {
|
|
const skcanvas = CanvasKit.MakeCanvas(CANVAS_WIDTH, CANVAS_HEIGHT);
|
|
const realCanvas = document.getElementById('test');
|
|
realCanvas.width = CANVAS_WIDTH;
|
|
realCanvas.height = CANVAS_HEIGHT;
|
|
|
|
const skcontext = skcanvas.getContext('2d');
|
|
const realContext = realCanvas.getContext('2d');
|
|
|
|
const toTest = ['font', 'lineWidth', 'strokeStyle', 'lineCap',
|
|
'lineJoin', 'miterLimit', 'shadowOffsetY',
|
|
'shadowBlur', 'shadowColor', 'shadowOffsetX',
|
|
'globalAlpha', 'globalCompositeOperation',
|
|
'lineDashOffset', 'imageSmoothingEnabled',
|
|
'imageFilterQuality'];
|
|
|
|
// Compare all the default values of the properties of skcanvas
|
|
// to the default values on the properties of a real canvas.
|
|
for(let attr of toTest) {
|
|
expect(skcontext[attr]).toBe(realContext[attr], attr);
|
|
}
|
|
|
|
skcanvas.dispose();
|
|
done();
|
|
}));
|
|
});
|
|
}); // end describe('Path drawing API')
|
|
|
|
|
|
});
|