| - name: 2d.filter.value |
| desc: test if ctx.filter works correctly |
| code: | |
| @assert ctx.filter == 'none'; |
| ctx.filter = 'blur(5px)'; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.save(); |
| ctx.filter = 'none'; |
| @assert ctx.filter == 'none'; |
| ctx.restore(); |
| @assert ctx.filter == 'blur(5px)'; |
| |
| ctx.filter = 'blur(10)'; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = 'blur 10px'; |
| @assert ctx.filter == 'blur(5px)'; |
| |
| ctx.filter = 'inherit'; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = 'initial'; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = 'unset'; |
| @assert ctx.filter == 'blur(5px)'; |
| |
| ctx.filter = ''; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = null; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = undefined; |
| @assert ctx.filter == 'blur(5px)'; |
| |
| ctx.filter = 'blur( 5px)'; |
| assert_equals(ctx.filter, 'blur( 5px)'); |
| |
| - name: 2d.filter.canvasFilterObject |
| desc: Test CanvasFilter() object |
| code: | |
| @assert ctx.filter == 'none'; |
| ctx.filter = 'blur(5px)'; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = new CanvasFilter({blur: {stdDeviation: 5}}); |
| @assert ctx.filter.toString() == '[object CanvasFilter]'; |
| ctx.filter = new CanvasFilter([{blur: {stdDeviation: 5}}, {blur: {stdDeviation: 10}}]); |
| @assert ctx.filter.toString() == '[object CanvasFilter]'; |
| var canvas2 = document.createElement('canvas'); |
| var ctx2 = canvas2.getContext('2d'); |
| ctx2.filter = ctx.filter; |
| @assert ctx.filter.toString() == '[object CanvasFilter]'; |
| ctx.filter = 'blur(5px)'; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = 'none'; |
| @assert ctx.filter == 'none'; |
| ctx.filter = new CanvasFilter({blur: {stdDeviation: 5}}); |
| ctx.filter = "this string is not a filter and should do nothing"; |
| @assert ctx.filter.toString() == '[object CanvasFilter]'; |
| |
| - name: 2d.filter.canvasFilterObject.blur.exceptions |
| desc: Test exceptions on CanvasFilter() blur.object |
| code: | |
| @assert throws TypeError ctx.filter = new CanvasFilter({blur: null}); |
| @assert throws TypeError ctx.filter = new CanvasFilter({blur: {}}); |
| @assert throws TypeError ctx.filter = new CanvasFilter({blur: {stdDevation: null}}); |
| @assert throws TypeError ctx.filter = new CanvasFilter({blur: {stdDeviation: "foo"}}); |
| |
| - name: 2d.filter.canvasFilterObject.colorMatrix |
| desc: Test the functionality of ColorMatrix filters in CanvasFilter objects |
| code: | |
| @assert throws TypeError new CanvasFilter({colorMatrix: {values: undefined}}); |
| @assert throws TypeError new CanvasFilter({colorMatrix: {values: "foo"}}); |
| @assert throws TypeError new CanvasFilter({colorMatrix: {values: null}}); |
| @assert throws TypeError new CanvasFilter({colorMatrix: {values: [1, 2, 3]}}); |
| @assert throws TypeError new CanvasFilter({colorMatrix: {values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, "a"]}}); |
| @assert throws TypeError new CanvasFilter({colorMatrix: {values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, Infinity]}}); |
| ctx.fillStyle = "#f00"; |
| ctx.filter = new CanvasFilter({colorMatrix: {type: "hueRotate", values: 0}}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 255,0,0,255; |
| ctx.filter = new CanvasFilter({colorMatrix: {type: "hueRotate", values: 90}}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 0,91,0,255; |
| ctx.filter = new CanvasFilter({colorMatrix: {type: "hueRotate", values: 180}}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 0,109,109,255; |
| ctx.filter = new CanvasFilter({colorMatrix: {type: "hueRotate", values: 270}}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 109,18,255,255; |
| ctx.filter = new CanvasFilter({colorMatrix: {type: "saturate", values: 0.5}}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 155,27,27,255; |
| ctx.clearRect(0, 0, 100, 50); |
| ctx.filter = new CanvasFilter({colorMatrix: {type: "luminanceToAlpha"}}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 0,0,0,54; |
| ctx.filter = new CanvasFilter({colorMatrix: {values: [ |
| 0, 0, 0, 0, 0, |
| 1, 1, 1, 1, 0, |
| 0, 0, 0, 0, 0, |
| 0, 0, 0, 1, 0 |
| ]}}); |
| ctx.fillRect(0, 0, 50, 25); |
| ctx.fillStyle = "#0f0"; |
| ctx.fillRect(50, 0, 50, 25); |
| ctx.fillStyle = "#00f"; |
| ctx.fillRect(0, 25, 50, 25); |
| ctx.fillStyle = "#fff"; |
| ctx.fillRect(50, 25, 50, 25); |
| @assert pixel 10,10 ==~ 0,255,0,255; |
| @assert pixel 60,10 ==~ 0,255,0,255; |
| @assert pixel 10,30 ==~ 0,255,0,255; |
| @assert pixel 60,30 ==~ 0,255,0,255; |
| expected: green |
| |
| - name: 2d.filter.canvasFilterObject.convolveMatrix.exceptions |
| desc: Test exceptions on CanvasFilter() convolveMatrix |
| code: | |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {}}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: null}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {divisor: 2}}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: null}}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: 1}}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0]]}}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, "a"], [0]]}}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], 0]}}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: [[1, 0], [0, Infinity]]}}); |
| @assert throws TypeError new CanvasFilter({convolveMatrix: {kernelMatrix: []}}); |
| // This should not throw an error |
| ctx.filter = new CanvasFilter({convolveMatrix: {kernelMatrix: [[]]}}); |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.linear |
| desc: Test pixels on CanvasFilter() componentTransfer with linear type |
| code: | |
| // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement |
| function getColor(inputColor, slopes, intercepts) { |
| return [ |
| Math.max(0, Math.min(1, inputColor[0]/255 * slopes[0] + intercepts[0])) * 255, |
| Math.max(0, Math.min(1, inputColor[1]/255 * slopes[1] + intercepts[1])) * 255, |
| Math.max(0, Math.min(1, inputColor[2]/255 * slopes[2] + intercepts[2])) * 255, |
| ]; |
| } |
| |
| const slopes = [0.5, 1.2, -0.2]; |
| const intercepts = [0.25, 0, 0.5]; |
| ctx.filter = new CanvasFilter({componentTransfer: { |
| funcR: {type: "linear", slope: slopes[0], intercept: intercepts[0]}, |
| funcG: {type: "linear", slope: slopes[1], intercept: intercepts[1]}, |
| funcB: {type: "linear", slope: slopes[2], intercept: intercepts[2]}, |
| }}); |
| |
| const inputColors = [ |
| [255, 255, 255], |
| [0, 0, 0], |
| [127, 0, 34], |
| [252, 186, 3], |
| [50, 68, 87], |
| ]; |
| |
| for (const color of inputColors) { |
| let outputColor = getColor(color, slopes, intercepts); |
| ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; |
| ctx.fillRect(0, 0, 10, 10); |
| _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, "5,5", `${outputColor[0]},${outputColor[1]},${outputColor[2]}`, 2); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.identity |
| desc: Test pixels on CanvasFilter() componentTransfer with identity type |
| code: | |
| ctx.filter = new CanvasFilter({componentTransfer: { |
| funcR: {type: "identity"}, |
| funcG: {type: "identity"}, |
| funcB: {type: "identity"}, |
| }}); |
| |
| const inputColors = [ |
| [255, 255, 255], |
| [0, 0, 0], |
| [127, 0, 34], |
| [252, 186, 3], |
| [50, 68, 87], |
| ]; |
| |
| for (const color of inputColors) { |
| ctx.fillStyle = `rgba(${color[0]}, ${color[1]}, ${color[2]}, 1)`, |
| ctx.fillRect(0, 0, 10, 10); |
| _assertPixel(canvas, 5, 5, color[0],color[1],color[2],255, "5,5", `${color[0]},${color[1]},${color[2]}`); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.gamma |
| desc: Test pixels on CanvasFilter() componentTransfer with gamma type |
| code: | |
| // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement |
| function getColor(inputColor, amplitude, exponent, offset) { |
| return [ |
| Math.max(0, Math.min(1, Math.pow(inputColor[0]/255, exponent[0]) * amplitude[0] + offset[0])) * 255, |
| Math.max(0, Math.min(1, Math.pow(inputColor[1]/255, exponent[1]) * amplitude[1] + offset[1])) * 255, |
| Math.max(0, Math.min(1, Math.pow(inputColor[2]/255, exponent[2]) * amplitude[2] + offset[2])) * 255, |
| ]; |
| } |
| |
| const amplitudes = [2, 1.1, 0.5]; |
| const exponents = [5, 3, 1]; |
| const offsets = [0.25, 0, 0.5]; |
| ctx.filter = new CanvasFilter({componentTransfer: { |
| funcR: {type: "gamma", amplitude: amplitudes[0], exponent: exponents[0], offset: offsets[0]}, |
| funcG: {type: "gamma", amplitude: amplitudes[1], exponent: exponents[1], offset: offsets[1]}, |
| funcB: {type: "gamma", amplitude: amplitudes[2], exponent: exponents[2], offset: offsets[2]}, |
| }}); |
| |
| const inputColors = [ |
| [255, 255, 255], |
| [0, 0, 0], |
| [127, 0, 34], |
| [252, 186, 3], |
| [50, 68, 87], |
| ]; |
| |
| for (const color of inputColors) { |
| let outputColor = getColor(color, amplitudes, exponents, offsets); |
| ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; |
| ctx.fillRect(0, 0, 10, 10); |
| _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, "5,5", `${outputColor[0]},${outputColor[1]},${outputColor[2]}`, 2); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.table |
| desc: Test pixels on CanvasFilter() componentTransfer with table type |
| code: | |
| // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement |
| function getTransformedValue(C, V) { |
| // Get the right interval |
| const n = V.length - 1; |
| const k = C == 1 ? n - 1 : Math.floor(C * n); |
| return V[k] + (C - k/n) * n * (V[k + 1] - V[k]); |
| } |
| |
| function getColor(inputColor, tableValues) { |
| const result = [0, 0, 0]; |
| for (const i in inputColor) { |
| const C = inputColor[i]/255; |
| const Cprime = getTransformedValue(C, tableValues[i]); |
| result[i] = Math.max(0, Math.min(1, Cprime)) * 255; |
| } |
| return result; |
| } |
| |
| tableValuesR = [0, 0, 1, 1]; |
| tableValuesG = [2, 0, 0.5, 3]; |
| tableValuesB = [1, -1, 5, 0]; |
| ctx.filter = new CanvasFilter({componentTransfer: { |
| funcR: {type: "table", tableValues: tableValuesR}, |
| funcG: {type: "table", tableValues: tableValuesG}, |
| funcB: {type: "table", tableValues: tableValuesB}, |
| }}); |
| |
| const inputColors = [ |
| [255, 255, 255], |
| [0, 0, 0], |
| [127, 0, 34], |
| [252, 186, 3], |
| [50, 68, 87], |
| ]; |
| |
| for (const color of inputColors) { |
| let outputColor = getColor(color, [tableValuesR, tableValuesG, tableValuesB]); |
| ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; |
| ctx.fillRect(0, 0, 10, 10); |
| _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, "5,5", `${outputColor[0]},${outputColor[1]},${outputColor[2]}`, 2); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.discrete |
| desc: Test pixels on CanvasFilter() componentTransfer with discrete type |
| code: | |
| // From https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement |
| function getTransformedValue(C, V) { |
| // Get the right interval |
| const n = V.length - 1; |
| const k = C == 1 ? n - 1 : Math.floor(C * n); |
| return V[k]; |
| } |
| |
| function getColor(inputColor, tableValues) { |
| const result = [0, 0, 0]; |
| for (const i in inputColor) { |
| const C = inputColor[i]/255; |
| const Cprime = getTransformedValue(C, tableValues[i]); |
| result[i] = Math.max(0, Math.min(1, Cprime)) * 255; |
| } |
| return result; |
| } |
| |
| tableValuesR = [0, 0, 1, 1]; |
| tableValuesG = [2, 0, 0.5, 3]; |
| tableValuesB = [1, -1, 5, 0]; |
| ctx.filter = new CanvasFilter({componentTransfer: { |
| funcR: {type: "discrete", tableValues: tableValuesR}, |
| funcG: {type: "discrete", tableValues: tableValuesG}, |
| funcB: {type: "discrete", tableValues: tableValuesB}, |
| }}); |
| |
| const inputColors = [ |
| [255, 255, 255], |
| [0, 0, 0], |
| [127, 0, 34], |
| [252, 186, 3], |
| [50, 68, 87], |
| ]; |
| |
| for (const color of inputColors) { |
| let outputColor = getColor(color, [tableValuesR, tableValuesG, tableValuesB]); |
| ctx.fillStyle = `rgb(${color[0]}, ${color[1]}, ${color[2]})`; |
| ctx.fillRect(0, 0, 10, 10); |
| _assertPixelApprox(canvas, 5, 5, outputColor[0],outputColor[1],outputColor[2],255, "5,5", `${outputColor[0]},${outputColor[1]},${outputColor[2]}`, 2); |
| } |