зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1307740 - Add more canvas filter tainting tests. r=tobytailor
MozReview-Commit-ID: JSISqvsTAmD --HG-- extra : rebase_source : 6aeb3daa3cb1c4919aeb3d44da99bb845d01d385
This commit is contained in:
Родитель
92b0f9ca83
Коммит
cadd5734c8
|
@ -10,9 +10,17 @@
|
|||
0 0 0 0 0
|
||||
0 0 0 1 0"/>
|
||||
</filter>
|
||||
<filter id="use-feFlood-as-map-on-SourceGraphic">
|
||||
<feFlood flood-color="lime" result='green'/>
|
||||
<!-- should shift everything up and to the left by 8 pixels (only respects A channel) -->
|
||||
<feDisplacementMap in="SourceGraphic" in2="green" scale="16"/>
|
||||
</filter>
|
||||
<filter id="render-cross-origin-red-feImage">
|
||||
<feImage xlink:href="http://example.com/tests/dom/canvas/test/image_red-16x16.png"/>
|
||||
</filter>
|
||||
<filter id="generate-green">
|
||||
<feFlood flood-color="lime" result='green'/>
|
||||
</filter>
|
||||
<filter id="use-SourceGraphic-as-map-on-red">
|
||||
<feImage xlink:href='image_red-16x16.png' result='img'/>
|
||||
<feDisplacementMap in="img" in2="SourceGraphic" scale="20"/>
|
||||
|
@ -28,7 +36,9 @@
|
|||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
<div id="canvasContainer"></div>
|
||||
<div id="canvasContainer" style="height:100px;"></div>
|
||||
<img id="same-origin-green" src="image_green-16x16.png"/>
|
||||
<img id="same-origin-red" src="image_red-16x16.png"/>
|
||||
<img id="cross-origin-green" src="http://example.com/tests/dom/canvas/test/image_green-16x16.png"/>
|
||||
<img id="cross-origin-red" src="http://example.com/tests/dom/canvas/test/image_red-16x16.png"/>
|
||||
<script>
|
||||
|
@ -39,11 +49,14 @@ function isPixel(ctx, x, y, r, g, b, a, d) {
|
|||
pg = pixel.data[1],
|
||||
pb = pixel.data[2],
|
||||
pa = pixel.data[3];
|
||||
ok(r - d <= pr && pr <= r + d &&
|
||||
g - d <= pg && pg <= g + d &&
|
||||
b - d <= pb && pb <= b + d &&
|
||||
a - d <= pa && pa <= a + d,
|
||||
var checkSucceeded = r - d <= pr && pr <= r + d &&
|
||||
g - d <= pg && pg <= g + d &&
|
||||
b - d <= pb && pb <= b + d &&
|
||||
a - d <= pa && pa <= a + d;
|
||||
ok(checkSucceeded,
|
||||
`pixel ${x},${y} is ${pr},${pg},${pb},${pa}; expected ${r},${g},${b},${a} +/- ${d}`);
|
||||
|
||||
return checkSucceeded;
|
||||
}
|
||||
|
||||
function expectCanvasCtxToBeTainted(ctx) {
|
||||
|
@ -79,7 +92,9 @@ function checkCanvasPixel(canvas, x, y, r, g, b, a, fuzz) {
|
|||
var captureCanvas = newCanvas();
|
||||
var captureCtx = SpecialPowers.wrap(captureCanvas.getContext('2d'));
|
||||
captureCtx.drawWindow(window, 0, 0, 16, 16, 'rgb(255, 255, 255)', 0);
|
||||
isPixel(captureCtx, x, y, r, g, b, a, fuzz);
|
||||
if (!isPixel(captureCtx, x, y, r, g, b, a, fuzz)) {
|
||||
info(captureCanvas.toDataURL('image/png'));
|
||||
}
|
||||
|
||||
container.removeChild(canvas);
|
||||
}
|
||||
|
@ -87,77 +102,231 @@ function checkCanvasPixel(canvas, x, y, r, g, b, a, fuzz) {
|
|||
function runTest() {
|
||||
|
||||
SpecialPowers.pushPrefEnv({ 'set': [['canvas.filters.enabled', true]] }, function () {
|
||||
var sameOriginGreenImage = document.getElementById('same-origin-green');
|
||||
var sameOriginRedImage = document.getElementById('same-origin-red');
|
||||
var crossOriginGreenImage = document.getElementById('cross-origin-green');
|
||||
var crossOriginRedImage = document.getElementById('cross-origin-red');
|
||||
|
||||
var canvas = newCanvas();
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
// A CSS filter should not taint the canvas.
|
||||
ctx.filter = 'grayscale(100%)';
|
||||
ctx.fillStyle = 'green';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 8,8, 92,92,92,255, 5);
|
||||
expectCanvasCtxToBeUntainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// An SVG filter should not taint the canvas.
|
||||
ctx.filter = 'url(#colormatrix-make-green)';
|
||||
ctx.fillStyle = 'red';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 8,8, 0,255,0,255, 5);
|
||||
expectCanvasCtxToBeUntainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// A CSS -> SVG -> CSS filter chain should not taint the canvas.
|
||||
ctx.filter = 'grayscale(100%) url(#colormatrix-make-green) grayscale(100%)';
|
||||
is(ctx.filter, 'grayscale(100%) url(#colormatrix-make-green) grayscale(100%)', 'filter chain should parse correctly');
|
||||
ctx.fillStyle = 'red';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 8,8, 183,183,183,255, 5);
|
||||
expectCanvasCtxToBeUntainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// An SVG -> CSS -> SVG filter chain should not taint the canvas.
|
||||
ctx.filter = 'url(#colormatrix-make-green) grayscale(100%) url(#colormatrix-make-green)';
|
||||
is(ctx.filter, 'url(#colormatrix-make-green) grayscale(100%) url(#colormatrix-make-green)', 'filter chain should parse correctly');
|
||||
ctx.fillStyle = 'red';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 8,8, 0,255,0,255, 5);
|
||||
expectCanvasCtxToBeUntainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// feDisplacementMap with untainted map input from feFlood should work and not taint
|
||||
ctx.filter = 'url(#use-feFlood-as-map-on-SourceGraphic)';
|
||||
ctx.fillStyle = 'blue';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 4,4, 0,0,255,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,255,255,255, 1);
|
||||
expectCanvasCtxToBeUntainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// feDisplacementMap with untainted map input from different SVG filter should work and not taint
|
||||
ctx.filter = 'url(#generate-green) url(#use-SourceGraphic-as-map-on-red)';
|
||||
is(ctx.filter, 'url(#generate-green) url(#use-SourceGraphic-as-map-on-red)', 'filter chain should parse correctly');
|
||||
ctx.fillStyle = 'blue';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 4,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,255,255,255, 1);
|
||||
expectCanvasCtxToBeUntainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// feDisplacementMap with untainted map input from different CSS filter should work and not taint
|
||||
ctx.filter = 'url(#generate-green) grayscale(100%) url(#use-SourceGraphic-as-map-on-red)';
|
||||
is(ctx.filter, 'url(#generate-green) grayscale(100%) url(#use-SourceGraphic-as-map-on-red)', 'filter chain should parse correctly');
|
||||
ctx.fillStyle = 'blue';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 4,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,255,255,255, 1);
|
||||
expectCanvasCtxToBeUntainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// drawImage with cross-origin image and SVG filter should apply the filter and taint the canvas.
|
||||
ctx.filter = 'url(#colormatrix-make-green)';
|
||||
ctx.drawImage(crossOriginRedImage, 0, 0);
|
||||
|
||||
// The color matrix should turn the red green.
|
||||
checkCanvasPixel(canvas, 8,8, 0,255,0,255, 5);
|
||||
|
||||
// But since the image was cross-origin, the canvas should now be tainted.
|
||||
checkCanvasPixel(canvas, 8,8, 0,255,0,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// Create new untainted canvas.
|
||||
canvas = newCanvas();
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.filter = 'url(#use-cross-origin-green-feImage-as-map-on-same-origin-red)';
|
||||
ctx.rect(0, 0, 16, 16);
|
||||
ctx.fill();
|
||||
|
||||
// The red feImage should be passed through the displacement map without being shifted
|
||||
checkCanvasPixel(canvas, 8,8, 255,0,0,255, 5);
|
||||
|
||||
// but it should have tainted the canvas.
|
||||
// drawImage with cross-origin image and CSS filter should apply the filter and taint the canvas.
|
||||
ctx.filter = 'grayscale(100%)';
|
||||
ctx.drawImage(crossOriginRedImage, 0, 0);
|
||||
checkCanvasPixel(canvas, 8,8, 53,53,53,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// feDisplacementMap with untainted map input from different CSS filter should work even on tainted canvas
|
||||
ctx.filter = 'url(#generate-green) grayscale(100%) url(#use-SourceGraphic-as-map-on-red)';
|
||||
is(ctx.filter, 'url(#generate-green) grayscale(100%) url(#use-SourceGraphic-as-map-on-red)', 'filter chain should parse correctly');
|
||||
ctx.fillStyle = 'blue';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 4,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,255,255,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// feDisplacementMap with untainted map input from feFlood should work even on tainted canvas
|
||||
ctx.filter = 'url(#use-feFlood-as-map-on-SourceGraphic)';
|
||||
ctx.fillStyle = 'blue';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 4,4, 0,0,255,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,255,255,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,255,255,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// Create new untainted canvas.
|
||||
canvas = newCanvas();
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
// cross-origin feImage should render correctly and taint the canvas
|
||||
ctx.filter = 'url(#render-cross-origin-red-feImage)';
|
||||
ctx.rect(0, 0, 16, 16);
|
||||
ctx.fill();
|
||||
|
||||
// red feImage should have rendered
|
||||
checkCanvasPixel(canvas, 8,8, 255,0,0,255, 5);
|
||||
|
||||
// but it should have tainted the canvas.
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
|
||||
// Create new untainted canvas.
|
||||
canvas = newCanvas();
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
// cross-origin feImage should be ignored as map input to a displacement map, and taint the canvas.
|
||||
ctx.filter = 'url(#use-cross-origin-green-feImage-as-map-on-same-origin-red)';
|
||||
ctx.rect(0, 0, 16, 16);
|
||||
ctx.fill();
|
||||
checkCanvasPixel(canvas, 4,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,0,0,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
|
||||
// Create new untainted canvas.
|
||||
canvas = newCanvas();
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
expectCanvasCtxToBeUntainted(ctx);
|
||||
|
||||
// cross-origin SourceGraphic should be ignored as map input to a displacement map, and taint the canvas.
|
||||
// SourceGraphic: cross-origin image_green-16x16.png,
|
||||
// gets used as map to shift same-origin image_red-16x16.png,
|
||||
// but should get ignored so that image_red-16x16.png gets drawn unshifted.
|
||||
ctx.filter = 'url(#use-SourceGraphic-as-map-on-red)';
|
||||
ctx.drawImage(crossOriginGreenImage, 0, 0);
|
||||
|
||||
// expect to see red because cross-origin image_green-16x16.png should not have displaced the red away
|
||||
checkCanvasPixel(canvas, 8,8, 255,0,0,255, 5);
|
||||
|
||||
checkCanvasPixel(canvas, 4,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,0,0,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
|
||||
// cross-origin feImage should be ignored as map to displacement map, and taint the canvas.
|
||||
// SourceGraphic: cross-origin image_green-16x16.png,
|
||||
// Cross-origin feImage image_red-16x16.png gets used as map to shift SourceGraphic,
|
||||
// but should get ignored so that image_green-16x16.png gets drawn unshifted.
|
||||
ctx.filter = 'url(#use-cross-origin-red-feImage-as-map-on-SourceGraphic)';
|
||||
ctx.drawImage(crossOriginGreenImage, 0, 0);
|
||||
|
||||
// expect to see green because cross-origin image_red-16x16.png should not have displaced the green away
|
||||
checkCanvasPixel(canvas, 8,8, 0,255,0,255, 5);
|
||||
|
||||
checkCanvasPixel(canvas, 4,4, 0,255,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 0,255,0,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 0,255,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 0,255,0,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
|
||||
// Create new untainted canvas.
|
||||
canvas = newCanvas();
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
// feDisplacementMap with tainted map input from different CSS filter should be ignored
|
||||
ctx.filter = 'grayscale(100%) url(#use-SourceGraphic-as-map-on-red)';
|
||||
is(ctx.filter, 'grayscale(100%) url(#use-SourceGraphic-as-map-on-red)', 'filter chain should parse correctly');
|
||||
ctx.drawImage(crossOriginGreenImage, 0, 0);
|
||||
checkCanvasPixel(canvas, 4,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,0,0,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
ctx.clearRect(0, 0, 16, 16);
|
||||
|
||||
// Create new untainted canvas.
|
||||
canvas = newCanvas();
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
// feDisplacementMap with tainted feImage map input from different SVG filter should be ignored
|
||||
ctx.filter = 'url(#render-cross-origin-red-feImage) url(#use-SourceGraphic-as-map-on-red)';
|
||||
is(ctx.filter, 'url(#render-cross-origin-red-feImage) url(#use-SourceGraphic-as-map-on-red)', 'filter chain should parse correctly');
|
||||
ctx.fillStyle = 'blue';
|
||||
ctx.fillRect(0, 0, 16, 16);
|
||||
checkCanvasPixel(canvas, 4,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,4, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 4,12, 255,0,0,255, 1);
|
||||
checkCanvasPixel(canvas, 12,12, 255,0,0,255, 1);
|
||||
expectCanvasCtxToBeTainted(ctx);
|
||||
|
||||
// Paint 'canvas' (which is red and tainted) into a different canvas and makes sure it taints that other canvas.
|
||||
var secondCanvas = newCanvas();
|
||||
var secondCtx = secondCanvas.getContext('2d');
|
||||
secondCtx.filter = 'grayscale(100%)';
|
||||
secondCtx.drawImage(canvas, 0, 0);
|
||||
checkCanvasPixel(secondCanvas, 4,4, 53,53,53,255, 1);
|
||||
checkCanvasPixel(secondCanvas, 12,4, 53,53,53,255, 1);
|
||||
checkCanvasPixel(secondCanvas, 4,12, 53,53,53,255, 1);
|
||||
checkCanvasPixel(secondCanvas, 12,12, 53,53,53,255, 1);
|
||||
expectCanvasCtxToBeTainted(secondCtx);
|
||||
|
||||
// Fill the left half with blue (i.e. an untainted SourceGraphic) and make sure the canvas is still tainted.
|
||||
secondCtx.fillStyle = "blue";
|
||||
secondCtx.fillRect(0, 0, 8, 16);
|
||||
checkCanvasPixel(secondCanvas, 4,4, 17,17,17,255, 1);
|
||||
checkCanvasPixel(secondCanvas, 12,4, 53,53,53,255, 1);
|
||||
checkCanvasPixel(secondCanvas, 4,12, 17,17,17,255, 1);
|
||||
checkCanvasPixel(secondCanvas, 12,12, 53,53,53,255, 1);
|
||||
expectCanvasCtxToBeTainted(secondCtx);
|
||||
|
||||
SimpleTest.finish();
|
||||
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче