Record code coverage in canvaskit tests, increase coverage
Fix a bug with paragraph text direction that an incorrect unit test wasn't detecting. Change-Id: I73418ea8a90da097078d93ddf8692a55488f672f Reviewed-on: https://skia-review.googlesource.com/c/skia/+/292366 Commit-Queue: Nathaniel Nifong <nifong@google.com> Reviewed-by: Kevin Lubick <kjlubick@google.com>
This commit is contained in:
parent
a727122007
commit
59d299ba3f
3
modules/canvaskit/.gitignore
vendored
3
modules/canvaskit/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
package-lock.json
|
||||
fonts/*.cpp
|
||||
fonts/*.cpp
|
||||
coverage/*
|
@ -4,7 +4,9 @@ To compile CanvasKit, you will first need to [install `emscripten`][1]. This
|
||||
will set the environment `EMSDK` (among others) which is required for
|
||||
compilation.
|
||||
|
||||
# Compile and Test Locally
|
||||
[1]: https://emscripten.org/docs/getting_started/downloads.html
|
||||
|
||||
# Compile and Run Local Example
|
||||
|
||||
```
|
||||
make release # make debug is much faster and has better error messages
|
||||
@ -23,7 +25,67 @@ any of the "extras", one might run:
|
||||
|
||||
Such a stripped-down version is about half the size of the default release build.
|
||||
|
||||
[1]: https://emscripten.org/docs/getting_started/downloads.html
|
||||
# Unit tests, performance tests, and coverage.
|
||||
|
||||
To run unit tests and compute test coverage on a debug gpu build
|
||||
|
||||
```
|
||||
make debug
|
||||
make test-continuous
|
||||
```
|
||||
|
||||
This reads karma.conf.js, and opens a chrome browser and begins running all the test
|
||||
in `test/` it will detect changes to the tests in that directory and automatically
|
||||
run again, however it will automatically rebuild and reload canvaskit. Closing the
|
||||
chrome window will just cause it to re-opened. Kill the karma process to stop continuous
|
||||
monitoring for changes.
|
||||
|
||||
The tests are run with whichever build of canvaskit you last made. be sure to also
|
||||
test with `release`, `debug_cpu`, and `release_cpu`. testing with release builds will
|
||||
expose problems in closure compilation and usually forgotten externs.
|
||||
|
||||
## Coverage
|
||||
|
||||
Coverage will be automatically computed when running test-continuous locally. Note that
|
||||
the results will only be useful when testing a debug build. Open
|
||||
`coverage/<browser version>/index.html` For a summary and detailed line-by-line result.
|
||||
|
||||
## Measuring Performance
|
||||
|
||||
To measure the runtime of all benchmarks in `perf/`
|
||||
|
||||
```
|
||||
make release
|
||||
make perf
|
||||
```
|
||||
|
||||
Performacnce benchmarks also use karma, with a different config `karma.bench.conf.js`.
|
||||
It will run once and print results.
|
||||
|
||||
Typically, you'd want to run these at head, and with your CL to observe the effect of some
|
||||
optimization.
|
||||
|
||||
## Adding tests
|
||||
|
||||
The tests in `tests/` and `perf/` are grouped into files by topic.
|
||||
Within each file there are `describe` blocks further organizing the tests, and within those
|
||||
`it()` functions which test particular behaviors. `describe` and `it` are jasmine methods
|
||||
which can both be temporarily renamed `fdescribe` and `fit`. Which causes jasmine to only those.
|
||||
|
||||
We have also defined `gm` which is a method for defining a test which draws something to a canvas
|
||||
that is shapshotted and reported to gold.skia.org, where you can compare it with the snapshot at
|
||||
head.
|
||||
|
||||
## Testing from Gerrit
|
||||
|
||||
When submitting a CL in gerrit, click "choose tryjobs" and type canvaskit to filter them.
|
||||
select all of them, which at the time of this writing is four jobs, for each combination
|
||||
of perf/test gpu/cpu.
|
||||
|
||||
The performance results are reported to perf.skia.org
|
||||
gold results are reported to gold.skia.org
|
||||
|
||||
Coverage is not measured while running tests this way.
|
||||
|
||||
|
||||
# Infrastructure Playbook
|
||||
|
@ -115,7 +115,6 @@
|
||||
CanvasKit = CK;
|
||||
ParticlesAPI1(CanvasKit);
|
||||
RTShaderAPI1(CanvasKit);
|
||||
SurfaceAPI1(CanvasKit);
|
||||
ColorSupport(CanvasKit);
|
||||
});
|
||||
|
||||
@ -205,76 +204,6 @@
|
||||
surface.requestAnimationFrame(drawFrame);
|
||||
}
|
||||
|
||||
function SurfaceAPI1(CanvasKit) {
|
||||
const surface = CanvasKit.MakeCanvasSurface('surfaces');
|
||||
if (!surface) {
|
||||
console.error('Could not make surface');
|
||||
return;
|
||||
}
|
||||
console.log('SurfaceAPI1 top surface type = '+surface.reportBackendType() );
|
||||
const context = CanvasKit.currentContext();
|
||||
const canvas = surface.getCanvas();
|
||||
|
||||
//create a subsurface as a temporary workspace.
|
||||
const subSurface = surface.makeSurface({
|
||||
width: 50,
|
||||
height: 50,
|
||||
alphaType: CanvasKit.AlphaType.Premul,
|
||||
colorType: CanvasKit.ColorType.RGBA_8888,
|
||||
});
|
||||
|
||||
if (!subSurface) {
|
||||
console.error('Could not make subsurface');
|
||||
return;
|
||||
}
|
||||
console.log('SurfaceAPI1 subSurface type = '+subSurface.reportBackendType() );
|
||||
|
||||
// draw a small "scene"
|
||||
const paint = new CanvasKit.SkPaint();
|
||||
paint.setColor(CanvasKit.Color(139, 228, 135, 0.95)); // greenish
|
||||
paint.setStyle(CanvasKit.PaintStyle.Fill);
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
const subCanvas = subSurface.getCanvas();
|
||||
subCanvas.clear(CanvasKit.BLACK);
|
||||
subCanvas.drawRect(CanvasKit.LTRBRect(5, 15, 45, 40), paint);
|
||||
|
||||
paint.setColor(CanvasKit.Color(214, 93, 244)); // purplish
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const x = Math.random() * 50;
|
||||
const y = Math.random() * 50;
|
||||
|
||||
subCanvas.drawOval(CanvasKit.XYWHRect(x, y, 6, 6), paint);
|
||||
}
|
||||
|
||||
// Snap it off as an SkImage - this image will be in the form the
|
||||
// parent surface prefers (e.g. Texture for GPU / Raster for CPU).
|
||||
const img = subSurface.makeImageSnapshot();
|
||||
|
||||
// clean up the temporary surface
|
||||
subSurface.delete();
|
||||
paint.delete();
|
||||
|
||||
// Make it repeat a bunch with a shader
|
||||
const pattern = img.makeShader(CanvasKit.TileMode.Repeat, CanvasKit.TileMode.Mirror);
|
||||
const patternPaint = new CanvasKit.SkPaint();
|
||||
patternPaint.setShader(pattern);
|
||||
|
||||
let i = 0;
|
||||
|
||||
function drawFrame() {
|
||||
i++;
|
||||
CanvasKit.setCurrentContext(context);
|
||||
canvas.clear(CanvasKit.WHITE);
|
||||
|
||||
canvas.drawOval(CanvasKit.LTRBRect(i % 60, i % 60, 300 - (i% 60), 300 - (i % 60)), patternPaint);
|
||||
surface.flush();
|
||||
window.requestAnimationFrame(drawFrame);
|
||||
}
|
||||
window.requestAnimationFrame(drawFrame);
|
||||
|
||||
}
|
||||
|
||||
function ParagraphAPI1(CanvasKit, fontData) {
|
||||
if (!CanvasKit || !fontData) {
|
||||
return;
|
||||
|
@ -7,6 +7,7 @@
|
||||
CanvasKit.MakeSWCanvasSurface = function(idOrElement) {
|
||||
var canvas = idOrElement;
|
||||
if (canvas.tagName !== 'CANVAS') {
|
||||
// TODO(nifong): unit test
|
||||
canvas = document.getElementById(idOrElement);
|
||||
if (!canvas) {
|
||||
throw 'Canvas with id ' + idOrElement + ' was not found';
|
||||
|
@ -235,30 +235,6 @@ function copy2dArray(arr, dest, ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// arr should be a non-jagged 3d JS array (TypedArrays can't be nested
|
||||
// inside themselves.)
|
||||
// dest is something like CanvasKit.HEAPF32
|
||||
// ptr can be optionally provided if the memory was already allocated.
|
||||
function copy3dArray(arr, dest, ptr) {
|
||||
if (!arr || !arr.length || !arr[0].length) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!ptr) {
|
||||
ptr = CanvasKit._malloc(arr.length * arr[0].length * arr[0][0].length * dest.BYTES_PER_ELEMENT);
|
||||
}
|
||||
var idx = 0;
|
||||
var adjustedPtr = ptr / dest.BYTES_PER_ELEMENT;
|
||||
for (var x = 0; x < arr.length; x++) {
|
||||
for (var y = 0; y < arr[0].length; y++) {
|
||||
for (var z = 0; z < arr[0][0].length; z++) {
|
||||
dest[adjustedPtr + idx] = arr[x][y][z];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
var defaultPerspective = Float32Array.of(0, 0, 1);
|
||||
|
||||
// Copies the given DOMMatrix/Array/TypedArray to the CanvasKit heap and
|
||||
|
@ -76,6 +76,17 @@ module.exports = function(config) {
|
||||
],
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// Extra options that should only be applied locally
|
||||
|
||||
// Measure test coverage and write output to coverage/ directory
|
||||
cfg.reporters.push('coverage');
|
||||
cfg.preprocessors = {
|
||||
// Measure test coverage of these source files
|
||||
// Since this file is a combination of our code, and emscripten's glue,
|
||||
// we'll never see 100% coverage, but this lets us measure improvements.
|
||||
'canvaskit/bin/canvaskit.js': ['coverage'],
|
||||
};
|
||||
}
|
||||
|
||||
config.set(cfg);
|
||||
|
3494
modules/canvaskit/package-lock.json
generated
Normal file
3494
modules/canvaskit/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@
|
||||
"jasmine-core": "~3.1.0",
|
||||
"karma": "~3.0.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage": "^2.0.2",
|
||||
"karma-jasmine": "~1.1.2",
|
||||
"requirejs": "~2.3.5"
|
||||
},
|
||||
|
@ -15,7 +15,7 @@
|
||||
var ret = [];
|
||||
for (var i = 0; i < floatArray.length; i+=5) {
|
||||
var r = CanvasKit.LTRBRect(floatArray[i], floatArray[i+1], floatArray[i+2], floatArray[i+3]);
|
||||
if (floatArray[i+4] === 1) {
|
||||
if (floatArray[i+4] === 0) {
|
||||
r['direction'] = CanvasKit.TextDirection.RTL;
|
||||
} else {
|
||||
r['direction'] = CanvasKit.TextDirection.LTR;
|
||||
|
@ -33,6 +33,12 @@ describe('Core canvas behavior', () => {
|
||||
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();
|
||||
});
|
||||
|
||||
@ -593,6 +599,17 @@ describe('Core canvas behavior', () => {
|
||||
expect(paint.getColor()).toEqual(Float32Array.of(3.3, 2.2, 1.1, 0.5));
|
||||
});
|
||||
|
||||
gm('draw shadow', (canvas) => {
|
||||
const lightRadius = 30;
|
||||
const flags = 0;
|
||||
const lightPos = [250,150,300];
|
||||
const zPlaneParams = [0,0,1];
|
||||
const path = starPath(CanvasKit);
|
||||
|
||||
canvas.drawShadow(path, zPlaneParams, lightPos, lightRadius,
|
||||
CanvasKit.RED, CanvasKit.MAGENTA, flags);
|
||||
})
|
||||
|
||||
describe('ColorSpace Support', () => {
|
||||
it('Can create an SRGB 8888 surface', () => {
|
||||
const colorSpace = CanvasKit.SkColorSpace.SRGB;
|
||||
|
@ -178,7 +178,7 @@ describe('Paragraph Behavior', function() {
|
||||
expect(rects.length).toEqual(test.expectedNum);
|
||||
|
||||
for (const rect of rects) {
|
||||
expect(rect.direction).toEqual(CanvasKit.TextDirection.LTR);
|
||||
expect(rect.direction.value).toEqual(CanvasKit.TextDirection.LTR.value);
|
||||
const p = new CanvasKit.SkPaint();
|
||||
p.setColor(test.color);
|
||||
p.setStyle(CanvasKit.PaintStyle.Stroke);
|
||||
|
Loading…
Reference in New Issue
Block a user