From f6212cd47d01ef82465d3a8431df62a17cae0b4e Mon Sep 17 00:00:00 2001 From: adroitwhiz Date: Mon, 8 Jun 2020 21:04:54 -0400 Subject: [PATCH 1/2] Properly render gradients when strokeScaling=false --- src/item/Item.js | 6 +++--- src/item/Shape.js | 2 +- src/path/CompoundPath.js | 2 +- src/path/Path.js | 2 +- src/style/Color.js | 20 +++++++++++++++++--- 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/item/Item.js b/src/item/Item.js index d6cd8558..43e5a900 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -4279,16 +4279,16 @@ new function() { // Injection scope for hit-test functions shared with project * Not defined in Path as it is required by other classes too, * e.g. PointText. */ - _setStyles: function(ctx, param, viewMatrix) { + _setStyles: function(ctx, param, viewMatrix, strokeMatrix) { // We can access internal properties since we're only using this on // items without children, where styles would be merged. var style = this._style, matrix = this._matrix; if (style.hasFill()) { - ctx.fillStyle = style.getFillColor().toCanvasStyle(ctx, matrix); + ctx.fillStyle = style.getFillColor().toCanvasStyle(ctx, matrix, strokeMatrix); } if (style.hasStroke()) { - ctx.strokeStyle = style.getStrokeColor().toCanvasStyle(ctx, matrix); + ctx.strokeStyle = style.getStrokeColor().toCanvasStyle(ctx, matrix, strokeMatrix); ctx.lineWidth = style.getStrokeWidth(); var strokeJoin = style.getStrokeJoin(), strokeCap = style.getStrokeCap(), diff --git a/src/item/Shape.js b/src/item/Shape.js index 53cec0f7..f4842a38 100644 --- a/src/item/Shape.js +++ b/src/item/Shape.js @@ -261,7 +261,7 @@ var Shape = Item.extend(/** @lends Shape# */{ ctx.closePath(); } if (!dontPaint && (hasFill || hasStroke)) { - this._setStyles(ctx, param, viewMatrix); + this._setStyles(ctx, param, viewMatrix, strokeMatrix); if (hasFill) { ctx.fill(style.getFillRule()); ctx.shadowColor = 'rgba(0,0,0,0)'; diff --git a/src/path/CompoundPath.js b/src/path/CompoundPath.js index 9ee5c48b..ae6be96c 100644 --- a/src/path/CompoundPath.js +++ b/src/path/CompoundPath.js @@ -311,7 +311,7 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{ children[i].draw(ctx, param, strokeMatrix); if (!param.clip) { - this._setStyles(ctx, param, viewMatrix); + this._setStyles(ctx, param, viewMatrix, strokeMatrix); var style = this._style; if (style.hasFill()) { ctx.fill(style.getFillRule()); diff --git a/src/path/Path.js b/src/path/Path.js index 19848a9c..76d0091e 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -2321,7 +2321,7 @@ new function() { // Scope for drawing if (!dontPaint && (hasFill || hasStroke)) { // If the path is part of a compound path or doesn't have a fill // or stroke, there is no need to continue. - this._setStyles(ctx, param, viewMatrix); + this._setStyles(ctx, param, viewMatrix, strokeMatrix); if (hasFill) { ctx.fill(style.getFillRule()); // If shadowColor is defined, clear it after fill, so it diff --git a/src/style/Color.js b/src/style/Color.js index d97b6fc4..1f8d6efb 100644 --- a/src/style/Color.js +++ b/src/style/Color.js @@ -899,8 +899,11 @@ var Color = Base.extend(new function() { + components.join(',') + ')'; }, - toCanvasStyle: function(ctx, matrix) { - if (this._canvasStyle) + toCanvasStyle: function(ctx, matrix, strokeMatrix) { + // strokeMatrix can change without triggering _changed here, so we + // can't use a cached gradient here. + var strokeMayChange = this._type === 'gradient' && strokeMatrix; + if (this._canvasStyle && !strokeMayChange) return this._canvasStyle; // Normal colors are simply represented by their CSS string. if (this._type !== 'gradient') @@ -923,6 +926,12 @@ var Color = Base.extend(new function() { if (highlight) highlight = inverse._transformPoint(highlight); } + if (strokeMatrix) { + origin = strokeMatrix._transformPoint(origin); + destination = strokeMatrix._transformPoint(destination); + if (highlight) + highlight = strokeMatrix._transformPoint(highlight); + } if (gradient._radial) { var radius = destination.getDistance(origin); if (highlight) { @@ -948,7 +957,12 @@ var Color = Base.extend(new function() { offset == null ? i / (l - 1) : offset, stop._color.toCanvasStyle()); } - return this._canvasStyle = canvasGradient; + // Don't store gradients that may change in the cache. + // If we cached a gradient that was transformed by strokeMatrix + // then set strokeScaling to true, then the transformed gradient + // could get "stuck" in the cache. + if (!strokeMayChange) this._canvasStyle = canvasGradient; + return canvasGradient; }, /** From b25ce1958c9b104783a69ffabc7b95bfb348a970 Mon Sep 17 00:00:00 2001 From: adroitwhiz Date: Mon, 8 Jun 2020 20:56:43 -0400 Subject: [PATCH 2/2] Add test for strokeScaling gradients --- test/tests/Color.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/tests/Color.js b/test/tests/Color.js index 7dfabeaa..a86ad503 100644 --- a/test/tests/Color.js +++ b/test/tests/Color.js @@ -306,6 +306,41 @@ test('Gradients with applyMatrix', function() { comparePixels(path, shape); }); +test('Gradients with strokeScaling: false', function() { + var topLeft = [100, 100]; + var bottomRight = [400, 400]; + var gradientColor = { + gradient: { + stops: ['yellow', 'red', 'blue'] + }, + origin: topLeft, + destination: bottomRight + } + + var path = new Shape.Rectangle({ + topLeft: topLeft, + bottomRight: bottomRight, + fillColor: gradientColor, + strokeScaling: true + }); + + var shape = new Shape.Rectangle({ + topLeft: topLeft, + bottomRight: bottomRight, + fillColor: gradientColor, + strokeScaling: false + }); + + comparePixels(path, shape); + + path.scale(2); + path.rotate(45); + shape.scale(2); + shape.rotate(45); + + comparePixels(path, shape); +}) + test('Modifying group.strokeColor for multiple children', function() { var item = new Group(new Path(), new Path()); item.strokeColor = 'red';