Commit c2635f87 authored by xlai's avatar xlai Committed by Commit bot

Correct color bleeding of no-repeat pattern in canvas2d

Currently the image pattern shader created is only padded
with 1 black transparent pixel right and bottom. We should
pad it on the left and top as well so that when pattern is
transformed, the color on its left and top will not bleed.

BUG=602509

Review-Url: https://codereview.chromium.org/2130063002
Cr-Commit-Position: refs/heads/master@{#404491}
parent ab2caa6f
...@@ -833,6 +833,12 @@ crbug.com/623120 virtual/gpu/fast/canvas/webgl/webgl-array-invalid-ranges.html [ ...@@ -833,6 +833,12 @@ crbug.com/623120 virtual/gpu/fast/canvas/webgl/webgl-array-invalid-ranges.html [
crbug.com/623120 fast/canvas/webgl/webgl-array-invalid-ranges.html [ NeedsManualRebaseline ] crbug.com/623120 fast/canvas/webgl/webgl-array-invalid-ranges.html [ NeedsManualRebaseline ]
crbug.com/623120 virtual/display_list_2d_canvas/fast/canvas/webgl/webgl-array-invalid-ranges.html [ NeedsManualRebaseline ] crbug.com/623120 virtual/display_list_2d_canvas/fast/canvas/webgl/webgl-array-invalid-ranges.html [ NeedsManualRebaseline ]
crbug.com/602509 fast/canvas/canvas-pattern-no-repeat-with-transformations.html [ NeedsRebaseline ]
crbug.com/602509 virtual/gpu/fast/canvas/canvas-pattern-no-repeat-with-transformations.html [ NeedsRebaseline ]
crbug.com/602509 virtual/display_list_2d_canvas/fast/canvas/canvas-pattern-no-repeat-with-transformations.html [ NeedsRebaseline ]
crbug.com/602509 fast/canvas/image-object-in-canvas.html [ NeedsRebaseline ]
crbug.com/602509 virtual/display_list_2d_canvas/fast/canvas/image-object-in-canvas.html [ NeedsRebaseline ]
# When drawing subpixel smoothed glyphs, CoreGraphics will fake bold the glyphs. # When drawing subpixel smoothed glyphs, CoreGraphics will fake bold the glyphs.
# In this configuration, the pixel smoothed glyphs will be created from subpixel smoothed glyphs. # In this configuration, the pixel smoothed glyphs will be created from subpixel smoothed glyphs.
# This means that CoreGraphics may draw outside the reported glyph bounds, and in this case does. # This means that CoreGraphics may draw outside the reported glyph bounds, and in this case does.
......
Failed assertion: got pixel [255,0,0,255] at (1,1), expected [0,255,0,255] Passed
Failed assertion: got pixel [255,0,0,255] at (98,1), expected [0,255,0,255]
Failed assertion: got pixel [255,0,0,255] at (1,48), expected [0,255,0,255]
Failed assertion: got pixel [255,0,0,255] at (1,1), expected [0,255,0,255] Passed
Failed assertion: got pixel [255,0,0,255] at (98,1), expected [0,255,0,255]
Failed assertion: got pixel [255,0,0,255] at (1,1), expected [0,255,0,255] Passed
Failed assertion: got pixel [255,0,0,255] at (1,48), expected [0,255,0,255]
<canvas id="canvas" width="270" height="420"></canvas>
<canvas id="pattern" width="20" height="20"></canvas>
<script type="text/javascript">
if (window.testRunner)
testRunner.dumpAsTextWithPixelResults();
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.strokeRect(0, 0, canvas.width, canvas.height);
var pCanvas = document.getElementById("pattern");
var pctx = pCanvas.getContext("2d");
pctx.fillStyle = "red";
pctx.fillRect(0, 0, 20, 20);
pctx.fillStyle = "green";
pctx.fillRect(1, 1, 18, 18);
var pattern = pctx.createPattern(pCanvas, 'no-repeat');
ctx.fillStyle = pattern;
ctx.strokeStyle = "blue";
function test(testPosX, testPosY, transformCallback)
{
ctx.save();
ctx.beginPath();
ctx.translate(testPosX, testPosY);
ctx.rect(0, 0, 100, 100);
// After transformCallback, no-repeat pattern should follow the new
// position; but rect will stay at wherever it was.
transformCallback();
ctx.fill(); // See the pattern
ctx.stroke(); // See the rect
ctx.restore();
}
function rotateCallback() { ctx.rotate(Math.PI / 180 * 25); }
function translateCallback() { ctx.translate(50, 50); }
function scaleCallback() { ctx.scale(2, 2); }
function transformCallback() { ctx.transform(1, 1, 0, 1, 0, 0); }
function resetTransformCallback() { ctx.resetTransform() }
function multipleTransformCallback()
{
ctx.translate(20, 20);
ctx.rotate(Math.PI / 180 * 10);
}
// Rotate the canvas by 90 degrees
// This is to test whether after save(), restore(), the canvas can return to
// this 90-degree-rotated state instead of its very initial state
ctx.translate(canvas.width/2, canvas.height/2);
ctx.rotate(Math.PI/2);
ctx.translate(-canvas.height/2, -canvas.width/2);
// Since the canvas is rotated 90 degrees, these three rectangles will appear
// on right side, from top to bottom.
test(10, 10, scaleCallback);
test(160, 10, rotateCallback);
test(310, 10, translateCallback);
// These three rectangles will appear on left side, from top to bottom.
test(10, 160, resetTransformCallback);
test(160, 160, transformCallback);
test(310, 160, multipleTransformCallback);
</script>
...@@ -49,22 +49,25 @@ sk_sp<SkShader> ImagePattern::createShader(const SkMatrix& localMatrix) const ...@@ -49,22 +49,25 @@ sk_sp<SkShader> ImagePattern::createShader(const SkMatrix& localMatrix) const
? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
SkShader::TileMode tileModeY = isRepeatY() SkShader::TileMode tileModeY = isRepeatY()
? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
int expandW = isRepeatX() ? 0 : 1; int borderPixelX = isRepeatX() ? 0 : 1;
int expandH = isRepeatY() ? 0 : 1; int borderPixelY = isRepeatY() ? 0 : 1;
// Create a transparent image 1 pixel wider and/or taller than the // Create a transparent image 2 pixels wider and/or taller than the
// original, then copy the orignal into it. // original, then copy the orignal into the middle of it.
// FIXME: Is there a better way to pad (not scale) an image in skia? // FIXME: Is there a better way to pad (not scale) an image in skia?
sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(
m_tileImage->width() + expandW, m_tileImage->height() + expandH); m_tileImage->width() + 2 * borderPixelX, m_tileImage->height() + 2 * borderPixelY);
if (!surface) if (!surface)
return SkShader::MakeColorShader(SK_ColorTRANSPARENT); return SkShader::MakeColorShader(SK_ColorTRANSPARENT);
SkPaint paint; SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode); paint.setXfermodeMode(SkXfermode::kSrc_Mode);
surface->getCanvas()->drawImage(m_tileImage, 0, 0, &paint); surface->getCanvas()->drawImage(m_tileImage, borderPixelX, borderPixelY, &paint);
return surface->makeImageSnapshot()->makeShader(tileModeX, tileModeY, &localMatrix); SkMatrix newLocalMatrix(localMatrix);
newLocalMatrix.postTranslate(-borderPixelX, -borderPixelY);
return surface->makeImageSnapshot()->makeShader(tileModeX, tileModeY, &newLocalMatrix);
} }
bool ImagePattern::isTextureBacked() const bool ImagePattern::isTextureBacked() const
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment