| - 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.tentative |
| desc: Test CanvasFilter() object |
| canvasType: |
| ['HTMLCanvas'] |
| code: | |
| @assert ctx.filter == 'none'; |
| ctx.filter = 'blur(5px)'; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = new CanvasFilter({filter: 'gaussianBlur', stdDeviation: 5}); |
| @assert ctx.filter.toString() == '[object CanvasFilter]'; |
| ctx.filter = new CanvasFilter([ |
| {filter: 'gaussianBlur', stdDeviation: 5}, |
| {filter: 'gaussianBlur', 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({filter: 'gaussianBlur', stdDeviation: 5}); |
| ctx.filter = 'this string is not a filter and should do nothing'; |
| @assert ctx.filter.toString() == '[object CanvasFilter]'; |
| |
| - name: 2d.filter.canvasFilterObject.tentative |
| desc: Test CanvasFilter() object |
| canvasType: ['OffscreenCanvas', 'Worker'] |
| code: | |
| @assert ctx.filter == 'none'; |
| ctx.filter = 'blur(5px)'; |
| @assert ctx.filter == 'blur(5px)'; |
| ctx.filter = new CanvasFilter({filter: 'gaussianBlur', stdDeviation: 5}); |
| @assert ctx.filter.toString() == '[object CanvasFilter]'; |
| ctx.filter = new CanvasFilter([ |
| {filter: 'gaussianBlur', stdDeviation: 5}, |
| {filter: 'gaussianBlur', stdDeviation: 10} |
| ]); |
| @assert ctx.filter.toString() == '[object CanvasFilter]'; |
| var canvas2 = new OffscreenCanvas(100, 50); |
| 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({filter: 'gaussianBlur', 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.tentative |
| desc: Test exceptions on CanvasFilter() blur.object |
| code: | |
| @assert throws TypeError ctx.filter = new CanvasFilter({filter: 'gaussianBlur'}); |
| @assert throws TypeError ctx.filter = new CanvasFilter({filter: 'gaussianBlur', stdDeviation: undefined}); |
| @assert throws TypeError ctx.filter = new CanvasFilter({filter: 'gaussianBlur', stdDeviation: 'foo'}); |
| @assert throws TypeError ctx.filter = new CanvasFilter({filter: 'gaussianBlur', stdDeviation: [1,2]}); |
| @assert throws TypeError ctx.filter = new CanvasFilter({filter: 'gaussianBlur', stdDeviation: NaN}); |
| @assert throws TypeError ctx.filter = new CanvasFilter({filter: 'gaussianBlur', stdDeviation: {}}); |
| |
| - name: 2d.filter.canvasFilterObject.colorMatrix.tentative |
| desc: Test the functionality of ColorMatrix filters in CanvasFilter objects |
| code: | |
| @assert throws TypeError new CanvasFilter({filter: 'colorMatrix', values: undefined}); |
| @assert throws TypeError new CanvasFilter({filter: 'colorMatrix', values: 'foo'}); |
| @assert throws TypeError new CanvasFilter({filter: 'colorMatrix', values: null}); |
| @assert throws TypeError new CanvasFilter({filter: 'colorMatrix', values: [1, 2, 3]}); |
| @assert throws TypeError new CanvasFilter({filter: '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({filter: '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({filter: 'colorMatrix', type: 'hueRotate', values: 0}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 255,0,0,255; |
| ctx.filter = new CanvasFilter({filter: 'colorMatrix', type: 'hueRotate', values: 90}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 0,91,0,255; |
| ctx.filter = new CanvasFilter({filter: 'colorMatrix', type: 'hueRotate', values: 180}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 0,109,109,255; |
| ctx.filter = new CanvasFilter({filter: 'colorMatrix', type: 'hueRotate', values: 270}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 109,18,255,255; |
| ctx.filter = new CanvasFilter({filter: '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({filter: 'colorMatrix', type: 'luminanceToAlpha'}); |
| ctx.fillRect(0, 0, 100, 50); |
| @assert pixel 10,10 ==~ 0,0,0,54; |
| ctx.filter = new CanvasFilter({filter: '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; |
| |
| - name: 2d.filter.canvasFilterObject.convolveMatrix.exceptions.tentative |
| desc: Test exceptions on CanvasFilter() convolveMatrix |
| code: | |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix'}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', divisor: 2}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: null}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: 1}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[1, 0], [0]]}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[1, 'a'], [0]]}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[1, 0], 0]}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[1, 0], [0, Infinity]]}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: []}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [1]}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [1, 2, 3, 4]}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[], []]}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[1, 2], []]}); |
| @assert throws TypeError new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[], [1, 2]]}); |
| // This should not throw an error |
| ctx.filter = new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[]]}); |
| ctx.filter = new CanvasFilter({filter: 'convolveMatrix', kernelMatrix: [[1]]}); |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.linear.tentative |
| 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({filter: '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, 2); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.identity.tentative |
| desc: Test pixels on CanvasFilter() componentTransfer with identity type |
| code: | |
| ctx.filter = new CanvasFilter({filter: '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); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.gamma.tentative |
| 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({filter: '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, 2); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.table.tentative |
| 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({filter: '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, 2); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.componentTransfer.discrete.tentative |
| 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; |
| 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({filter: '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, 2); |
| } |
| |
| - name: 2d.filter.canvasFilterObject.dropShadow.tentative |
| desc: Test CanvasFilter() dropShadow object. |
| size: 520, 420 |
| code: | |
| ctx.fillStyle = 'teal'; |
| ctx.fillRect(0, 0, 520, 50); |
| ctx.fillRect(0, 100, 520, 50); |
| ctx.fillRect(0, 200, 520, 50); |
| ctx.fillRect(0, 300, 520, 50); |
| |
| ctx.fillStyle = 'crimson'; |
| |
| // Parameter defaults. |
| ctx.filter = new CanvasFilter({filter: 'dropShadow'}); |
| ctx.fillRect(10, 10, 80, 80); |
| |
| // All parameters specified. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, |
| floodColor: 'purple', floodOpacity: 0.7}); |
| ctx.fillRect(110, 10, 80, 80); |
| |
| // Named color. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, |
| floodColor: 'purple'}); |
| ctx.fillRect(10, 110, 80, 80); |
| |
| // System color. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, |
| floodColor: 'LinkText'}); |
| ctx.fillRect(110, 110, 80, 80); |
| |
| // Numerical color. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, |
| floodColor: 'rgba(20, 50, 130, 1)'}); |
| ctx.fillRect(210, 110, 80, 80); |
| |
| // Transparent floodColor. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, |
| floodColor: 'rgba(20, 50, 130, 0.7)'}); |
| ctx.fillRect(310, 110, 80, 80); |
| |
| // Transparent floodColor and floodOpacity. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: 3, |
| floodColor: 'rgba(20, 50, 130, 0.7)', floodOpacity: 0.7}); |
| ctx.fillRect(410, 110, 80, 80); |
| |
| // No blur. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: 0, |
| floodColor: 'purple'}); |
| ctx.fillRect(10, 210, 80, 80); |
| |
| // Single float blur. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: 5, |
| floodColor: 'purple'}); |
| ctx.fillRect(110, 210, 80, 80); |
| |
| // Single negative float blur. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: -5, |
| floodColor: 'purple'}); |
| ctx.fillRect(210, 210, 80, 80); |
| |
| // Two floats (X&Y) blur. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: [3, 5], |
| floodColor: 'purple'}); |
| ctx.fillRect(310, 210, 80, 80); |
| |
| // Two negative floats (X&Y) blur. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: 9, dy: 12, stdDeviation: [-3, -5], |
| floodColor: 'purple'}); |
| ctx.fillRect(410, 210, 80, 80); |
| |
| // Degenerate parameter values. |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: [-5], dy: [], stdDeviation: null, |
| floodColor: 'purple', floodOpacity: [2]}); |
| ctx.fillRect(10, 310, 80, 80); |
| |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: null, dy: '5', stdDeviation: [[-5], ['3']], |
| floodColor: 'purple', floodOpacity: '0.8'}); |
| ctx.fillRect(110, 310, 80, 80); |
| |
| ctx.filter = new CanvasFilter( |
| {filter: 'dropShadow', dx: true, dy: ['10'], stdDeviation: false, |
| floodColor: 'purple', floodOpacity: ['0.4']}); |
| ctx.fillRect(210, 310, 80, 80); |
| html_reference: | |
| <svg xmlns="http://www.w3.org/2000/svg" |
| width=520 height=420 |
| color-interpolation-filters="sRGB"> |
| <rect x=0 y=0 width=100% height=50 fill="teal" /> |
| <rect x=0 y=100 width=100% height=50 fill="teal" /> |
| <rect x=0 y=200 width=100% height=50 fill="teal" /> |
| <rect x=0 y=300 width=100% height=50 fill="teal" /> |
| |
| <rect x=10 y=10 width=80 height=80 fill="crimson" |
| filter="drop-shadow(2px 2px 2px black)"/> |
| <rect x=110 y=10 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 5px rgba(128, 0, 128, 0.7))"/> |
| |
| <rect x=10 y=110 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 3px purple)"/> |
| <rect x=110 y=110 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 3px LinkText)"/> |
| <rect x=210 y=110 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 3px rgba(20, 50, 130, 1))"/> |
| <rect x=310 y=110 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 3px rgba(20, 50, 130, 0.7))"/> |
| <rect x=410 y=110 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 3px rgba(20, 50, 130, 0.49))"/> |
| |
| <rect x=10 y=210 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 0px purple)"/> |
| <rect x=110 y=210 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 5px purple)"/> |
| <rect x=210 y=210 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 0px purple)"/> |
| <filter id="separable-filter" |
| x="-100%" y="-100%" width="300%" height="300%"> |
| <feDropShadow dx=9 dy=12 stdDeviation="3 5" flood-color="purple"/> |
| </filter> |
| <rect x=310 y=210 width=80 height=80 fill="crimson" |
| filter="url(#separable-filter)"/> |
| <rect x=410 y=210 width=80 height=80 fill="crimson" |
| filter="drop-shadow(9px 12px 0px purple)"/> |
| |
| <rect x=10 y=310 width=80 height=80 fill="crimson" |
| filter="drop-shadow(-5px 0px 0px purple)"/> |
| <filter id="separable-filter-degenerate" |
| x="-100%" y="-100%" width="300%" height="300%"> |
| <feDropShadow dx=0 dy=5 stdDeviation="0 3" |
| flood-color="rgba(128, 0, 128, 0.8)"/> |
| </filter> |
| <rect x=110 y=310 width=80 height=80 fill="crimson" |
| filter="url(#separable-filter-degenerate)"/> |
| <rect x=210 y=310 width=80 height=80 fill="crimson" |
| filter="drop-shadow(1px 10px 0px rgba(128, 0, 128, 0.4))"/> |
| </svg> |
| |
| - name: 2d.filter.canvasFilterObject.dropShadow.exceptions.tentative |
| desc: Test exceptions on CanvasFilter() dropShadow object |
| code: | |
| @unroll @assert new CanvasFilter({\- |
| filter: 'dropShadow', \- |
| <dx | dy | floodOpacity>: \- |
| <10 | -1 | 0.5 | null | true | false | [] | [20] | '30'>}); |
| @unroll @assert new CanvasFilter({\- |
| filter: 'dropShadow', \- |
| <stdDeviation>: \- |
| <10 | -1 | 0.5 | null | true | false | [] | [20] | '30' | \- |
| [10, -1] | [0.5, null] | [true, false] | [[], [20]] | \- |
| ['30', ['40']]>}); |
| @unroll @assert new CanvasFilter({\- |
| filter: 'dropShadow', \- |
| <floodColor>: \- |
| <'red' | 'canvas' | 'rgba(4, -3, 0.5, 1)' | '#aabbccdd' | '#abcd'>}); |
| |
| @unroll @assert throws TypeError new CanvasFilter({\- |
| filter: 'dropShadow', \- |
| <dx | dy | floodOpacity>: \- |
| <NaN | Infinity | -Infinity | undefined | 'test' | {} | [1, 2]>}); |
| @unroll @assert throws TypeError new CanvasFilter({\- |
| filter: 'dropShadow', \- |
| <stdDeviation>: \- |
| <NaN | Infinity | -Infinity | undefined | 'test' | {} | [1, 2, 3] | \- |
| [1, NaN] | [1, Infinity] | [1, -Infinity] | [1, undefined] | \- |
| [1, 'test'] | [1, {}] | [1, [2, 3]]>}); |
| @unroll @assert throws TypeError new CanvasFilter({\- |
| filter: 'dropShadow', \- |
| <floodColor>: \- |
| <'test' | 'rgba(NaN, 3, 2, 1)' | 10 | undefined | null | NaN>}); |
| |
| - name: 2d.filter.canvasFilterObject.turbulence.inputTypes.tentative |
| desc: Test exceptions on CanvasFilter() turbulence object |
| code: | |
| const errorTestCases = [ |
| {baseFrequency: {}}, |
| {baseFrequency: -1}, |
| {baseFrequency: [0, -1]}, |
| {baseFrequency: NaN}, |
| {baseFrequency: Infinity}, |
| {baseFrequency: undefined}, |
| {baseFrequency: -Infinity}, |
| {baseFrequency: 'test'}, |
| |
| {numOctaves: {}}, |
| {numOctaves: -1}, |
| {numOctaves: NaN}, |
| {numOctaves: Infinity}, |
| {numOctaves: undefined}, |
| {numOctaves: -Infinity}, |
| {numOctaves: [1, 1]}, |
| {numOctaves: 'test'}, |
| |
| {seed: {}}, |
| {seed: NaN}, |
| {seed: Infinity}, |
| {seed: undefined}, |
| {seed: -Infinity}, |
| {seed: [1, 1]}, |
| {seed: 'test'}, |
| |
| {stitchTiles: {}}, |
| {stitchTiles: NaN}, |
| {stitchTiles: Infinity}, |
| {stitchTiles: undefined}, |
| {stitchTiles: -Infinity}, |
| {stitchTiles: [1, 1]}, |
| {stitchTiles: 'test'}, |
| {stitchTiles: null}, |
| {stitchTiles: []}, |
| {stitchTiles: [10]}, |
| {stitchTiles: 30}, |
| {stitchTiles: false}, |
| {stitchTiles: true}, |
| {stitchTiles: '10'}, |
| {stitchTiles: -1}, |
| |
| {type: {}}, |
| {type: NaN}, |
| {type: Infinity}, |
| {type: undefined}, |
| {type: -Infinity}, |
| {type: [1, 1]}, |
| {type: 'test'}, |
| {type: null}, |
| {type: []}, |
| {type: [10]}, |
| {type: 30}, |
| {type: false}, |
| {type: true}, |
| {type: '10'}, |
| {type: -1}, |
| ] |
| |
| // null and [] = 0 when parsed as number |
| const workingTestCases = [ |
| {baseFrequency: null}, |
| {baseFrequency: []}, |
| {baseFrequency: [10]}, |
| {baseFrequency: [10, 3]}, |
| {baseFrequency: 30}, |
| {baseFrequency: false}, |
| {baseFrequency: true}, |
| {baseFrequency: '10'}, |
| |
| {numOctaves: null}, |
| {numOctaves: []}, |
| {numOctaves: [10]}, |
| {numOctaves: 30}, |
| {numOctaves: false}, |
| {numOctaves: true}, |
| {numOctaves: '10'}, |
| |
| {seed: null}, |
| {seed: []}, |
| {seed: [10]}, |
| {seed: 30}, |
| {seed: false}, |
| {seed: true}, |
| {seed: '10'}, |
| {seed: -1}, |
| |
| {stitchTiles: 'stitch'}, |
| {stitchTiles: 'noStitch'}, |
| |
| {type: 'fractalNoise'}, |
| {type: 'turbulence'}, |
| ] |
| |
| for (testCase of errorTestCases) { |
| const filterOptions = {...{filter: 'turbulence'}, ...testCase}; |
| @assert throws TypeError new CanvasFilter(filterOptions); |
| } |
| |
| for (testCase of workingTestCases) { |
| const filterOptions = {...{filter: 'turbulence'}, ...testCase}; |
| @assert new CanvasFilter(filterOptions) != null; |
| } |