[canvaskit] Fix shadow bugs
This also adds a helper option to writing canvas2d spec tests to see the CanvasKit option side by side with the real canvas version. Bug: skia:9940, skia:9947 Change-Id: Ia8fc4e1332d3896933b86291181bc3ba890d26ed Reviewed-on: https://skia-review.googlesource.com/c/skia/+/275618 Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
54de2fa48d
commit
a093cffed2
@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `MakeTwoPointConicalGradientShader` will be renamed soon. Calls can be replaced with
|
||||
`SkShader.MakeTwoPointConicalGradient`.
|
||||
|
||||
### Fixed
|
||||
- Shadows are properly draw on fillRect and strokeRect in the canvas2d emulation layer.
|
||||
- Shadow offsets properly ignore the CTM in the canvas2d emulation layer.
|
||||
|
||||
## [0.13.0] - 2020-02-28
|
||||
|
||||
### Deprecated
|
||||
|
@ -674,7 +674,7 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
var shadowPaint = this._shadowPaint(fillPaint);
|
||||
if (shadowPaint) {
|
||||
this._canvas.save();
|
||||
this._canvas.concat(this._shadowOffsetMatrix());
|
||||
this._applyShadowOffsetMatrix();
|
||||
this._canvas.drawPath(path, shadowPaint);
|
||||
this._canvas.restore();
|
||||
shadowPaint.dispose();
|
||||
@ -685,6 +685,16 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
|
||||
this.fillRect = function(x, y, width, height) {
|
||||
var fillPaint = this._fillPaint();
|
||||
|
||||
var shadowPaint = this._shadowPaint(fillPaint);
|
||||
if (shadowPaint) {
|
||||
this._canvas.save();
|
||||
this._applyShadowOffsetMatrix();
|
||||
this._canvas.drawRect(CanvasKit.XYWHRect(x, y, width, height), shadowPaint);
|
||||
this._canvas.restore();
|
||||
shadowPaint.dispose();
|
||||
}
|
||||
|
||||
this._canvas.drawRect(CanvasKit.XYWHRect(x, y, width, height), fillPaint);
|
||||
fillPaint.dispose();
|
||||
}
|
||||
@ -697,7 +707,7 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
var shadowPaint = this._shadowPaint(fillPaint);
|
||||
if (shadowPaint) {
|
||||
this._canvas.save();
|
||||
this._canvas.concat(this._shadowOffsetMatrix());
|
||||
this._applyShadowOffsetMatrix();
|
||||
this._canvas.drawTextBlob(blob, x, y, shadowPaint);
|
||||
this._canvas.restore();
|
||||
shadowPaint.dispose();
|
||||
@ -991,12 +1001,13 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
this.transform(a, b, c, d, e, f);
|
||||
}
|
||||
|
||||
// Returns the matrix representing the offset of the shadows. This unapplies
|
||||
// the effects of the scale, which should not affect the shadow offsets.
|
||||
this._shadowOffsetMatrix = function() {
|
||||
var sx = this._currentTransform[0];
|
||||
var sy = this._currentTransform[4];
|
||||
return CanvasKit.SkMatrix.translated(this._shadowOffsetX/sx, this._shadowOffsetY/sy);
|
||||
// We need to apply the shadowOffsets on the device coordinates, so we undo
|
||||
// the CTM, apply the offsets, then re-apply the CTM.
|
||||
this._applyShadowOffsetMatrix = function() {
|
||||
var inverted = CanvasKit.SkMatrix.invert(this._currentTransform);
|
||||
this._canvas.concat(inverted);
|
||||
this._canvas.concat(CanvasKit.SkMatrix.translated(this._shadowOffsetX, this._shadowOffsetY));
|
||||
this._canvas.concat(this._currentTransform);
|
||||
}
|
||||
|
||||
// Returns the shadow paint for the current settings or null if there
|
||||
@ -1066,7 +1077,7 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
var shadowPaint = this._shadowPaint(strokePaint);
|
||||
if (shadowPaint) {
|
||||
this._canvas.save();
|
||||
this._canvas.concat(this._shadowOffsetMatrix());
|
||||
this._applyShadowOffsetMatrix();
|
||||
this._canvas.drawPath(path, shadowPaint);
|
||||
this._canvas.restore();
|
||||
shadowPaint.dispose();
|
||||
@ -1078,6 +1089,15 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
|
||||
this.strokeRect = function(x, y, width, height) {
|
||||
var strokePaint = this._strokePaint();
|
||||
|
||||
var shadowPaint = this._shadowPaint(strokePaint);
|
||||
if (shadowPaint) {
|
||||
this._canvas.save();
|
||||
this._applyShadowOffsetMatrix();
|
||||
this._canvas.drawRect(CanvasKit.XYWHRect(x, y, width, height), shadowPaint);
|
||||
this._canvas.restore();
|
||||
shadowPaint.dispose();
|
||||
}
|
||||
this._canvas.drawRect(CanvasKit.XYWHRect(x, y, width, height), strokePaint);
|
||||
strokePaint.dispose();
|
||||
}
|
||||
@ -1090,7 +1110,7 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
var shadowPaint = this._shadowPaint(strokePaint);
|
||||
if (shadowPaint) {
|
||||
this._canvas.save();
|
||||
this._canvas.concat(this._shadowOffsetMatrix());
|
||||
this._applyShadowOffsetMatrix();
|
||||
this._canvas.drawTextBlob(blob, x, y, shadowPaint);
|
||||
this._canvas.restore();
|
||||
shadowPaint.dispose();
|
||||
|
@ -267,6 +267,18 @@ describe('CanvasKit\'s Canvas 2d Behavior', function() {
|
||||
realCanvas.width = CANVAS_WIDTH;
|
||||
realCanvas.height = CANVAS_HEIGHT;
|
||||
|
||||
if (!done) {
|
||||
console.log('debugging canvaskit');
|
||||
test(realCanvas);
|
||||
test(skcanvas);
|
||||
const png = skcanvas.toDataURL();
|
||||
const img = document.createElement('img');
|
||||
document.body.appendChild(img);
|
||||
img.src = png;
|
||||
debugger;
|
||||
return;
|
||||
}
|
||||
|
||||
let promises = [];
|
||||
|
||||
for (let canvas of [skcanvas, realCanvas]) {
|
||||
@ -611,6 +623,33 @@ describe('CanvasKit\'s Canvas 2d Behavior', function() {
|
||||
}));
|
||||
});
|
||||
|
||||
it('apply shadows correctly when rotated', function(done) {
|
||||
LoadCanvasKit.then(catchException(done, () => {
|
||||
multipleCanvasTest('shadows_with_rotate_skbug_9947', done, (canvas) => {
|
||||
const ctx = canvas.getContext('2d');
|
||||
const angle = 240;
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
||||
ctx.save();
|
||||
ctx.translate(80, 80);
|
||||
ctx.rotate((angle * Math.PI) / 180);
|
||||
ctx.shadowOffsetX = 10;
|
||||
ctx.shadowOffsetY = 10;
|
||||
ctx.shadowColor = 'rgba(100,100,100,0.5)';
|
||||
ctx.shadowBlur = 1;
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.strokeStyle = 'red';
|
||||
ctx.beginPath();
|
||||
ctx.rect(-20, -20, 40, 40);
|
||||
ctx.fill();
|
||||
ctx.fillRect(30, 30, 40, 40);
|
||||
ctx.strokeRect(30, -20, 40, 40);
|
||||
ctx.fillText('text', -20, -30);
|
||||
ctx.restore();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
it('can make patterns', function(done) {
|
||||
let skImageData = null;
|
||||
let htmlImage = null;
|
||||
|
Loading…
Reference in New Issue
Block a user