summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/canvas/tools/yaml-new/text.yaml
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/canvas/tools/yaml-new/text.yaml')
-rw-r--r--testing/web-platform/tests/html/canvas/tools/yaml-new/text.yaml1680
1 files changed, 1680 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/canvas/tools/yaml-new/text.yaml b/testing/web-platform/tests/html/canvas/tools/yaml-new/text.yaml
new file mode 100644
index 0000000000..ca945c2953
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/tools/yaml-new/text.yaml
@@ -0,0 +1,1680 @@
+- name: 2d.text.font.parse.basic
+ code: |
+ ctx.font = '20px serif';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20PX SERIF';
+ @assert ctx.font === '20px serif'; @moz-todo
+
+- name: 2d.text.font.parse.tiny
+ code: |
+ ctx.font = '1px sans-serif';
+ @assert ctx.font === '1px sans-serif';
+
+- name: 2d.text.font.parse.complex
+ code: |
+ ctx.font = 'small-caps italic 400 12px/2 Unknown Font, sans-serif';
+ @assert ['italic small-caps 12px "Unknown Font", sans-serif', 'italic small-caps 12px Unknown Font, sans-serif'].includes(ctx.font);
+
+- name: 2d.text.font.parse.complex2
+ code: |
+ ctx.font = 'small-caps italic 400 12px/2 "Unknown Font #2", sans-serif';
+ @assert ctx.font === 'italic small-caps 12px "Unknown Font #2", sans-serif';
+
+- name: 2d.text.font.parse.family
+ code: |
+ ctx.font = '20px cursive,fantasy,monospace,sans-serif,serif,UnquotedFont,"QuotedFont\\\\\\","';
+ @assert ctx.font === '20px cursive, fantasy, monospace, sans-serif, serif, UnquotedFont, "QuotedFont\\\\\\","';
+
+ # TODO:
+ # 2d.text.font.parse.size.absolute
+ # xx-small x-small small medium large x-large xx-large
+ # 2d.text.font.parse.size.relative
+ # smaller larger
+ # 2d.text.font.parse.size.length.relative
+ # em ex px
+ # 2d.text.font.parse.size.length.absolute
+ # in cm mm pt pc
+
+- name: 2d.text.font.parse.size.percentage
+ canvas: 'style="font-size: 144px"'
+ canvasType: ['HtmlCanvas']
+ code: |
+ ctx.font = '50% serif';
+ @assert ctx.font === '72px serif'; @moz-todo
+ canvas.setAttribute('style', 'font-size: 100px');
+ @assert ctx.font === '72px serif'; @moz-todo
+
+- name: 2d.text.font.parse.size.percentage.default
+ canvasType: ['HtmlCanvas']
+ code: |
+ var canvas2 = document.createElement('canvas');
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.font = '1000% serif';
+ @assert ctx2.font === '100px serif'; @moz-todo
+
+- name: 2d.text.font.parse.system
+ desc: System fonts must be computed to explicit values
+ code: |
+ ctx.font = 'message-box';
+ @assert ctx.font !== 'message-box';
+
+- name: 2d.text.font.parse.invalid
+ code: |
+ ctx.font = '20px serif';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = '';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = 'bogus';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = 'inherit';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = '10px {bogus}';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = '10px initial';
+ @assert ctx.font === '20px serif'; @moz-todo
+
+ ctx.font = '20px serif';
+ ctx.font = '10px default';
+ @assert ctx.font === '20px serif'; @moz-todo
+
+ ctx.font = '20px serif';
+ ctx.font = '10px inherit';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = '10px revert';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = 'var(--x)';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = 'var(--x, 10px serif)';
+ @assert ctx.font === '20px serif';
+
+ ctx.font = '20px serif';
+ ctx.font = '1em serif; background: green; margin: 10px';
+ @assert ctx.font === '20px serif';
+
+- name: 2d.text.font.default
+ code: |
+ @assert ctx.font === '10px sans-serif';
+
+- name: 2d.text.font.relative_size
+ canvasType: ['HTMLCanvas']
+ code: |
+ var canvas2 = document.createElement('canvas');
+ var ctx2 = canvas2.getContext('2d');
+ ctx2.font = '1em sans-serif';
+ @assert ctx2.font === '10px sans-serif';
+
+- name: 2d.text.font.relative_size
+ canvasType: ['OffscreenCanvas', 'Worker']
+ code: |
+ ctx.font = '1em sans-serif';
+ @assert ctx.font === '10px sans-serif';
+
+- name: 2d.text.font.weight
+ code: |
+ ctx.font = 'italic 400 12px serif';
+ @assert ctx.font === 'italic 12px serif';
+
+ ctx.font = 'italic 300 12px serif';
+ @assert ctx.font === 'italic 300 12px serif';
+
+- name: 2d.text.align.valid
+ code: |
+ ctx.textAlign = 'start';
+ @assert ctx.textAlign === 'start';
+
+ ctx.textAlign = 'end';
+ @assert ctx.textAlign === 'end';
+
+ ctx.textAlign = 'left';
+ @assert ctx.textAlign === 'left';
+
+ ctx.textAlign = 'right';
+ @assert ctx.textAlign === 'right';
+
+ ctx.textAlign = 'center';
+ @assert ctx.textAlign === 'center';
+
+- name: 2d.text.align.invalid
+ code: |
+ ctx.textAlign = 'start';
+ ctx.textAlign = 'bogus';
+ @assert ctx.textAlign === 'start';
+
+ ctx.textAlign = 'start';
+ ctx.textAlign = 'END';
+ @assert ctx.textAlign === 'start';
+
+ ctx.textAlign = 'start';
+ ctx.textAlign = 'end ';
+ @assert ctx.textAlign === 'start';
+
+ ctx.textAlign = 'start';
+ ctx.textAlign = 'end\0';
+ @assert ctx.textAlign === 'start';
+
+- name: 2d.text.align.default
+ code: |
+ @assert ctx.textAlign === 'start';
+
+- name: 2d.text.baseline.valid
+ code: |
+ ctx.textBaseline = 'top';
+ @assert ctx.textBaseline === 'top';
+
+ ctx.textBaseline = 'hanging';
+ @assert ctx.textBaseline === 'hanging';
+
+ ctx.textBaseline = 'middle';
+ @assert ctx.textBaseline === 'middle';
+
+ ctx.textBaseline = 'alphabetic';
+ @assert ctx.textBaseline === 'alphabetic';
+
+ ctx.textBaseline = 'ideographic';
+ @assert ctx.textBaseline === 'ideographic';
+
+ ctx.textBaseline = 'bottom';
+ @assert ctx.textBaseline === 'bottom';
+
+- name: 2d.text.baseline.invalid
+ code: |
+ ctx.textBaseline = 'top';
+ ctx.textBaseline = 'bogus';
+ @assert ctx.textBaseline === 'top';
+
+ ctx.textBaseline = 'top';
+ ctx.textBaseline = 'MIDDLE';
+ @assert ctx.textBaseline === 'top';
+
+ ctx.textBaseline = 'top';
+ ctx.textBaseline = 'middle ';
+ @assert ctx.textBaseline === 'top';
+
+ ctx.textBaseline = 'top';
+ ctx.textBaseline = 'middle\0';
+ @assert ctx.textBaseline === 'top';
+
+- name: 2d.text.baseline.default
+ code: |
+ @assert ctx.textBaseline === 'alphabetic';
+
+- name: 2d.text.draw.baseline.top
+ desc: textBaseline top is the top of the em square (not the bounding box)
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'top';
+ ctx.fillText('CC', 0, 0);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: &load-font-variant-definition
+ _HtmlCanvas:
+ canvasType: ['HtmlCanvas']
+ load_font: |-
+ await document.fonts.ready;
+ _OffscreenCanvas:
+ canvasType: ['OffscreenCanvas', 'Worker']
+ load_font: |-
+ var f = new FontFace("{{ fonts[0] }}", "url('/fonts/{{ fonts[0] }}.ttf')");
+ f.load();
+ {% set root = 'self' if canvas_type == 'worker' else 'document' %}
+ {{ root }}.fonts.add(f);
+ await {{ root }}.fonts.ready;
+
+- name: 2d.text.draw.baseline.bottom
+ desc: textBaseline bottom is the bottom of the em square (not the bounding box)
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'bottom';
+ ctx.fillText('CC', 0, 50);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.baseline.middle
+ desc: textBaseline middle is the middle of the em square (not the bounding box)
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'middle';
+ ctx.fillText('CC', 0, 25);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.baseline.alphabetic
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'alphabetic';
+ ctx.fillText('CC', 0, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.baseline.ideographic
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'ideographic';
+ ctx.fillText('CC', 0, 31.25);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 95,45 ==~ 0,255,0,255; @moz-todo
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.baseline.hanging
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textBaseline = 'hanging';
+ ctx.fillText('CC', 0, 12.5);
+ @assert pixel 5,5 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 95,5 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.space.collapse.space
+ desc: Space characters are converted to U+0020, and are NOT collapsed
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('E EE', 0, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 255,0,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.space.collapse.other
+ desc: Space characters are converted to U+0020, and are NOT collapsed
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('E \x09\x0a\x0c\x0d \x09\x0a\x0c\x0dEE', 0, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 255,0,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.space.collapse.start
+ desc: Space characters at the start of a line are NOT collapsed
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText(' EE', 0, 37.5);
+ @assert pixel 25,25 ==~ 255,0,0,255; @moz-todo
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.space.collapse.end
+ desc: Space characters at the end of a line are NOT collapsed
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'right';
+ ctx.fillText('EE ', 100, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 255,0,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.width.space
+ desc: Space characters are converted to U+0020 and NOT collapsed
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ @assert ctx.measureText('A B').width === 150;
+ @assert ctx.measureText('A B').width === 200;
+ @assert ctx.measureText('A \x09\x0a\x0c\x0d \x09\x0a\x0c\x0dB').width === 650;
+ @assert ctx.measureText('A \x0b B').width >= 200;
+
+ @assert ctx.measureText(' AB').width === 150;
+ @assert ctx.measureText('AB ').width === 150;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.drawing.style.measure.rtl.text
+ desc: Measurement should follow canvas direction instead text direction
+ code: |
+ metrics = ctx.measureText('اَلْعَرَبِيَّةُ');
+ @assert metrics.actualBoundingBoxLeft < metrics.actualBoundingBoxRight;
+
+ metrics = ctx.measureText('hello');
+ @assert metrics.actualBoundingBoxLeft < metrics.actualBoundingBoxRight;
+
+- name: 2d.text.drawing.style.measure.textAlign
+ desc: Measurement should be related to textAlignment
+ code: |
+ ctx.textAlign = "right";
+ metrics = ctx.measureText('hello');
+ @assert metrics.actualBoundingBoxLeft > metrics.actualBoundingBoxRight;
+
+ ctx.textAlign = "left"
+ metrics = ctx.measureText('hello');
+ @assert metrics.actualBoundingBoxLeft < metrics.actualBoundingBoxRight;
+
+- name: 2d.text.drawing.style.measure.direction
+ desc: Measurement should follow text direction
+ code: |
+ ctx.direction = "ltr";
+ metrics = ctx.measureText('hello');
+ @assert metrics.actualBoundingBoxLeft < metrics.actualBoundingBoxRight;
+
+ ctx.direction = "rtl";
+ metrics = ctx.measureText('hello');
+ @assert metrics.actualBoundingBoxLeft > metrics.actualBoundingBoxRight;
+
+- name: 2d.text.draw.fill.basic
+ desc: fillText draws filled text
+ manual:
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('PASS', 5, 35);
+ expected: &passfill |
+ size 100 50
+ cr.set_source_rgb(0, 0, 0)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 0)
+ cr.select_font_face("Arial")
+ cr.set_font_size(35)
+ cr.translate(5, 35)
+ cr.text_path("PASS")
+ cr.fill()
+
+- name: 2d.text.draw.fill.unaffected
+ desc: fillText does not start a new path or subpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('FAIL', 5, 35);
+
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 5,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.text.draw.fill.rtl
+ desc: fillText respects Right-To-Left Override characters
+ manual:
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.strokeStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('\u202eFAIL \xa0 \xa0 SSAP', 5, 35);
+ expected: *passfill
+
+- name: 2d.text.draw.fill.maxWidth.large
+ desc: fillText handles maxWidth correctly
+ manual:
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('PASS', 5, 35, 200);
+ expected: *passfill
+
+- name: 2d.text.draw.fill.maxWidth.small
+ desc: fillText handles maxWidth correctly
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('fail fail fail fail fail', -100, 35, 90);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+- name: 2d.text.draw.fill.maxWidth.zero
+ desc: fillText handles maxWidth correctly
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('fail fail fail fail fail', 5, 35, 0);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+- name: 2d.text.draw.fill.maxWidth.negative
+ desc: fillText handles maxWidth correctly
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('fail fail fail fail fail', 5, 35, -1);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+- name: 2d.text.draw.fill.maxWidth.NaN
+ desc: fillText handles maxWidth correctly
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.font = '35px Arial, sans-serif';
+ ctx.fillText('fail fail fail fail fail', 5, 35, NaN);
+ _assertGreen(ctx, 100, 50);
+ expected: green
+
+- name: 2d.text.draw.stroke.basic
+ desc: strokeText draws stroked text
+ manual:
+ code: |
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.strokeStyle = '#0f0';
+ ctx.fillStyle = '#f00';
+ ctx.lineWidth = 1;
+ ctx.font = '35px Arial, sans-serif';
+ ctx.strokeText('PASS', 5, 35);
+ expected: |
+ size 100 50
+ cr.set_source_rgb(0, 0, 0)
+ cr.rectangle(0, 0, 100, 50)
+ cr.fill()
+ cr.set_source_rgb(0, 1, 0)
+ cr.select_font_face("Arial")
+ cr.set_font_size(35)
+ cr.set_line_width(1)
+ cr.translate(5, 35)
+ cr.text_path("PASS")
+ cr.stroke()
+
+- name: 2d.text.draw.stroke.unaffected
+ desc: strokeText does not start a new path or subpath
+ code: |
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ ctx.moveTo(0, 0);
+ ctx.lineTo(100, 0);
+
+ ctx.font = '35px Arial, sans-serif';
+ ctx.strokeStyle = '#f00';
+ ctx.strokeText('FAIL', 5, 35);
+
+ ctx.lineTo(100, 50);
+ ctx.lineTo(0, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fill();
+
+ @assert pixel 50,25 == 0,255,0,255;
+ @assert pixel 5,45 == 0,255,0,255;
+ expected: green
+
+- name: 2d.text.draw.kern.consistent
+ desc: Stroked and filled text should have exactly the same kerning so it overlaps
+ manual:
+ code: |
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.strokeStyle = '#0f0';
+ ctx.lineWidth = 3;
+ ctx.font = '20px Arial, sans-serif';
+ ctx.fillText('VAVAVAVAVAVAVA', -50, 25);
+ ctx.fillText('ToToToToToToTo', -50, 45);
+ ctx.strokeText('VAVAVAVAVAVAVA', -50, 25);
+ ctx.strokeText('ToToToToToToTo', -50, 45);
+ expected: green
+
+# CanvasTest is:
+# A = (0, 0) to (1em, 0.75em) (above baseline)
+# B = (0, 0) to (1em, -0.25em) (below baseline)
+# C = (0, -0.25em) to (1em, 0.75em) (the em square) plus some Xs above and below
+# D = (0, -0.25em) to (1em, 0.75em) (the em square) plus some Xs left and right
+# E = (0, -0.25em) to (1em, 0.75em) (the em square)
+# space = empty, 1em wide
+#
+# At 50px, "E" will fill the canvas vertically
+# At 67px, "A" will fill the canvas vertically
+#
+# Ideographic baseline is 0.125em above alphabetic
+# Mathematical baseline is 0.375em above alphabetic
+# Hanging baseline is 0.500em above alphabetic
+
+- name: 2d.text.draw.fill.maxWidth.fontface
+ desc: fillText works on @font-face fonts
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#f00';
+ ctx.fillText('EEEE', -50, 37.5, 40);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.fill.maxWidth.bound
+ desc: fillText handles maxWidth based on line size, not bounding box size
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('DD', 0, 37.5, 100);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.fontface
+ fonts:
+ - CanvasTest
+ test_type: promise
+ code: |
+ {{ load_font }}
+ ctx.font = '67px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('AA', 0, 50);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.fontface.repeat
+ desc: Draw with the font immediately, then wait a bit until and draw again. (This
+ crashes some version of WebKit.)
+ test_type: promise
+ fonts:
+ - CanvasTest
+ font_unused_in_dom: true
+ code: |
+ {{ load_font }}
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.font = '67px CanvasTest';
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('AA', 0, 50);
+
+ await new Promise(resolve => t.step_timeout(resolve, 500));
+ ctx.fillText('AA', 0, 50);
+ _assertPixelApprox(canvas, 5,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 95,5, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 25,25, 0,255,0,255, 2);
+ _assertPixelApprox(canvas, 75,25, 0,255,0,255, 2);
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.fontface.notinpage
+ desc: '@font-face fonts should work even if they are not used in the page'
+ test_type: promise
+ fonts:
+ - CanvasTest
+ font_unused_in_dom: true
+ code: |
+ {{ load_font }}
+ ctx.font = '67px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('AA', 0, 50);
+ @assert pixel 5,5 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 95,5 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 25,25 ==~ 0,255,0,255; @moz-todo
+ @assert pixel 75,25 ==~ 0,255,0,255; @moz-todo
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.align.left
+ desc: textAlign left is the left of the first em square (not the bounding box)
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'left';
+ ctx.fillText('DD', 0, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.align.right
+ desc: textAlign right is the right of the last em square (not the bounding box)
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'right';
+ ctx.fillText('DD', 100, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.align.start.ltr
+ desc: textAlign start with ltr is the left edge
+ canvas: dir="ltr"
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ {% if canvas_type != 'htmlcanvas' %}
+ ctx.direction = 'ltr';
+ {% endif %}
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'start';
+ ctx.fillText('DD', 0, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.align.start.rtl
+ desc: textAlign start with rtl is the right edge
+ canvas: dir="rtl"
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ {% if canvas_type != 'htmlcanvas' %}
+ ctx.direction = 'rtl';
+ {% endif %}
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'start';
+ ctx.fillText('DD', 100, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.align.end.ltr
+ desc: textAlign end with ltr is the right edge
+ test_type: promise
+ canvas: dir="ltr"
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ {% if canvas_type != 'htmlcanvas' %}
+ ctx.direction = 'ltr';
+ {% endif %}
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'end';
+ ctx.fillText('DD', 100, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.align.end.rtl
+ desc: textAlign end with rtl is the left edge
+ canvas: dir="rtl"
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ {% if canvas_type != 'htmlcanvas' %}
+ ctx.direction = 'rtl';
+ {% endif %}
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'end';
+ ctx.fillText('DD', 0, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.align.center
+ desc: textAlign center is the center of the em squares (not the bounding box)
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.textAlign = 'center';
+ ctx.fillText('DD', 50, 37.5);
+ @assert pixel 5,5 ==~ 0,255,0,255;
+ @assert pixel 95,5 ==~ 0,255,0,255;
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ @assert pixel 5,45 ==~ 0,255,0,255;
+ @assert pixel 95,45 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+
+- name: 2d.text.draw.space.basic
+ desc: U+0020 is rendered the correct size (1em wide)
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('E EE', -100, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.draw.space.collapse.nonspace
+ desc: Non-space characters are not converted to U+0020 and collapsed
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+ ctx.fillStyle = '#0f0';
+ ctx.fillText('E\x0b EE', -150, 37.5);
+ @assert pixel 25,25 ==~ 0,255,0,255;
+ @assert pixel 75,25 ==~ 0,255,0,255;
+ expected: green
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.width.basic
+ desc: The width of character is same as font used
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ @assert ctx.measureText('A').width === 50;
+ @assert ctx.measureText('AA').width === 100;
+ @assert ctx.measureText('ABCD').width === 200;
+
+ ctx.font = '100px CanvasTest';
+ @assert ctx.measureText('A').width === 100;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.width.empty
+ desc: The empty string has zero width
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ @assert ctx.measureText("").width === 0;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.advances
+ desc: Testing width advances
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ // Some platforms may return '-0'.
+ @assert Math.abs(ctx.measureText('Hello').advances[0]) === 0;
+ // Different platforms may render text slightly different.
+ @assert ctx.measureText('Hello').advances[1] >= 36;
+ @assert ctx.measureText('Hello').advances[2] >= 58;
+ @assert ctx.measureText('Hello').advances[3] >= 70;
+ @assert ctx.measureText('Hello').advances[4] >= 80;
+
+ var tm = ctx.measureText('Hello');
+ @assert ctx.measureText('Hello').advances[0] === tm.advances[0];
+ @assert ctx.measureText('Hello').advances[1] === tm.advances[1];
+ @assert ctx.measureText('Hello').advances[2] === tm.advances[2];
+ @assert ctx.measureText('Hello').advances[3] === tm.advances[3];
+ @assert ctx.measureText('Hello').advances[4] === tm.advances[4];
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.actualBoundingBox
+ desc: Testing actualBoundingBox
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ ctx.baseline = 'alphabetic'
+ // Different platforms may render text slightly different.
+ // Values that are nominally expected to be zero might actually vary by a
+ // pixel or so if the UA accounts for antialiasing at glyph edges, so we
+ // allow a slight deviation.
+ @assert Math.abs(ctx.measureText('A').actualBoundingBoxLeft) <= 1;
+ @assert ctx.measureText('A').actualBoundingBoxRight >= 50;
+ @assert ctx.measureText('A').actualBoundingBoxAscent >= 35;
+ @assert Math.abs(ctx.measureText('A').actualBoundingBoxDescent) <= 1;
+
+ @assert ctx.measureText('D').actualBoundingBoxLeft >= 48;
+ @assert ctx.measureText('D').actualBoundingBoxLeft <= 52;
+ @assert ctx.measureText('D').actualBoundingBoxRight >= 75;
+ @assert ctx.measureText('D').actualBoundingBoxRight <= 80;
+ @assert ctx.measureText('D').actualBoundingBoxAscent >= 35;
+ @assert ctx.measureText('D').actualBoundingBoxAscent <= 40;
+ @assert ctx.measureText('D').actualBoundingBoxDescent >= 12;
+ @assert ctx.measureText('D').actualBoundingBoxDescent <= 15;
+
+ @assert Math.abs(ctx.measureText('ABCD').actualBoundingBoxLeft) <= 1;
+ @assert ctx.measureText('ABCD').actualBoundingBoxRight >= 200;
+ @assert ctx.measureText('ABCD').actualBoundingBoxAscent >= 85;
+ @assert ctx.measureText('ABCD').actualBoundingBoxDescent >= 37;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.fontBoundingBox
+ desc: Testing fontBoundingBox measurements
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '40px CanvasTest';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ @assert ctx.measureText('A').fontBoundingBoxAscent === 30;
+ @assert ctx.measureText('A').fontBoundingBoxDescent === 10;
+
+ @assert ctx.measureText('ABCD').fontBoundingBoxAscent === 30;
+ @assert ctx.measureText('ABCD').fontBoundingBoxDescent === 10;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.fontBoundingBox.ahem
+ desc: Testing fontBoundingBox for font ahem
+ test_type: promise
+ fonts:
+ - Ahem
+ code: |
+ {{ load_font }}
+ ctx.font = '50px Ahem';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ @assert ctx.measureText('A').fontBoundingBoxAscent === 40;
+ @assert ctx.measureText('A').fontBoundingBoxDescent === 10;
+ @assert ctx.measureText('ABCD').fontBoundingBoxAscent === 40;
+ @assert ctx.measureText('ABCD').fontBoundingBoxDescent === 10;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.fontBoundingBox-reduced-ascent
+ desc: Testing fontBoundingBox for OffscreenCanvas with reduced ascent metric
+ test_type: promise
+ fonts:
+ - CanvasTest-ascent256
+ code: |
+ {{ load_font }}
+ ctx.font = '40px CanvasTest-ascent256';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ @assert ctx.measureText('A').fontBoundingBoxAscent === 10;
+ @assert ctx.measureText('A').fontBoundingBoxDescent === 10;
+
+ @assert ctx.measureText('ABCD').fontBoundingBoxAscent === 10;
+ @assert ctx.measureText('ABCD').fontBoundingBoxDescent === 10;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.fontBoundingBox-zero-descent
+ desc: Testing fontBoundingBox for OffscreenCanvas with zero descent metric
+ test_type: promise
+ fonts:
+ - CanvasTest-descent0
+ code: |
+ {{ load_font }}
+ ctx.font = '40px CanvasTest-descent0';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ @assert ctx.measureText('A').fontBoundingBoxAscent === 30;
+ @assert ctx.measureText('A').fontBoundingBoxDescent === 0;
+
+ @assert ctx.measureText('ABCD').fontBoundingBoxAscent === 30;
+ @assert ctx.measureText('ABCD').fontBoundingBoxDescent === 0;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.emHeights
+ desc: Testing emHeights
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '40px CanvasTest';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ @assert ctx.measureText('A').emHeightAscent === 30;
+ @assert ctx.measureText('A').emHeightDescent === 10;
+ @assert ctx.measureText('A').emHeightDescent + ctx.measureText('A').emHeightAscent === 40;
+
+ @assert ctx.measureText('ABCD').emHeightAscent === 30;
+ @assert ctx.measureText('ABCD').emHeightDescent === 10;
+ @assert ctx.measureText('ABCD').emHeightDescent + ctx.measureText('ABCD').emHeightAscent === 40;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.emHeights-low-ascent
+ desc: Testing emHeights with reduced ascent metric
+ test_type: promise
+ fonts:
+ - CanvasTest-ascent256
+ code: |
+ {{ load_font }}
+ ctx.font = '40px CanvasTest-ascent256';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ @assert ctx.measureText('A').emHeightAscent === 20;
+ @assert ctx.measureText('A').emHeightDescent === 20;
+ @assert ctx.measureText('A').emHeightDescent + ctx.measureText('A').emHeightAscent === 40;
+
+ @assert ctx.measureText('ABCD').emHeightAscent === 20;
+ @assert ctx.measureText('ABCD').emHeightDescent === 20;
+ @assert ctx.measureText('ABCD').emHeightDescent + ctx.measureText('ABCD').emHeightAscent === 40;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.emHeights-zero-descent
+ desc: Testing emHeights with zero descent metric
+ test_type: promise
+ fonts:
+ - CanvasTest-descent0
+ code: |
+ {{ load_font }}
+ ctx.font = '40px CanvasTest-descent0';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ @assert ctx.measureText('A').emHeightAscent === 40;
+ @assert ctx.measureText('A').emHeightDescent === 0;
+ @assert ctx.measureText('A').emHeightDescent + ctx.measureText('A').emHeightAscent === 40;
+
+ @assert ctx.measureText('ABCD').emHeightAscent === 40;
+ @assert ctx.measureText('ABCD').emHeightDescent === 0;
+ @assert ctx.measureText('ABCD').emHeightDescent + ctx.measureText('ABCD').emHeightAscent === 40;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.measure.baselines
+ desc: Testing baselines
+ test_type: promise
+ fonts:
+ - CanvasTest
+ code: |
+ {{ load_font }}
+ ctx.font = '50px CanvasTest';
+ ctx.direction = 'ltr';
+ ctx.align = 'left'
+ @assert Math.abs(ctx.measureText('A').alphabeticBaseline) === 0;
+ @assert ctx.measureText('A').ideographicBaseline === 6.25;
+ @assert ctx.measureText('A').hangingBaseline === 25;
+
+ @assert Math.abs(ctx.measureText('ABCD').alphabeticBaseline) === 0;
+ @assert ctx.measureText('ABCD').ideographicBaseline === 6.25;
+ @assert ctx.measureText('ABCD').hangingBaseline === 25;
+ variants: *load-font-variant-definition
+
+- name: 2d.text.drawing.style.absolute.spacing
+ desc: Testing letter spacing and word spacing with absolute length
+ code: |
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === '0px';
+
+ ctx.letterSpacing = '3px';
+ @assert ctx.letterSpacing === '3px';
+ @assert ctx.wordSpacing === '0px';
+
+ ctx.wordSpacing = '5px';
+ @assert ctx.letterSpacing === '3px';
+ @assert ctx.wordSpacing === '5px';
+
+ ctx.letterSpacing = '-1px';
+ ctx.wordSpacing = '-1px';
+ @assert ctx.letterSpacing === '-1px';
+ @assert ctx.wordSpacing === '-1px';
+
+ ctx.letterSpacing = '1PX';
+ ctx.wordSpacing = '10PX';
+ @assert ctx.letterSpacing === '1px';
+ @assert ctx.wordSpacing === '10px';
+
+- name: 2d.text.drawing.style.font-relative.spacing
+ desc: Testing letter spacing and word spacing with font-relative length
+ code: |
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === '0px';
+
+ ctx.letterSpacing = '1EX';
+ ctx.wordSpacing = '1EM';
+ @assert ctx.letterSpacing === '1ex';
+ @assert ctx.wordSpacing === '1em';
+
+ ctx.letterSpacing = '1ch';
+ ctx.wordSpacing = '1ic';
+ @assert ctx.letterSpacing === '1ch';
+ @assert ctx.wordSpacing === '1ic';
+
+- name: 2d.text.drawing.style.nonfinite.spacing
+ desc: Testing letter spacing and word spacing with nonfinite inputs
+ code: |
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === '0px';
+
+ function test_word_spacing(value) {
+ ctx.wordSpacing = value;
+ ctx.letterSpacing = value;
+ @assert ctx.wordSpacing === '0px';
+ @assert ctx.letterSpacing === '0px';
+ }
+ @nonfinite test_word_spacing(<0 NaN Infinity -Infinity>);
+
+- name: 2d.text.drawing.style.invalid.spacing
+ desc: Testing letter spacing and word spacing with invalid units
+ code: |
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === '0px';
+
+ function test_word_spacing(value) {
+ ctx.wordSpacing = value;
+ ctx.letterSpacing = value;
+ @assert ctx.wordSpacing === '0px';
+ @assert ctx.letterSpacing === '0px';
+ }
+ @nonfinite test_word_spacing(< '0s' '1min' '1deg' '1pp' 'initial' 'inherit' 'normal' 'none'>);
+
+- name: 2d.text.drawing.style.letterSpacing.measure
+ desc: Testing letter spacing with different length units
+ code: |
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === '0px';
+ var width_normal = ctx.measureText('Hello World').width;
+
+ function test_letter_spacing(value, difference_spacing, epsilon) {
+ ctx.letterSpacing = value;
+ @assert ctx.letterSpacing === value;
+ @assert ctx.wordSpacing === '0px';
+ width_with_letter_spacing = ctx.measureText('Hello World').width;
+ assert_approx_equals(width_with_letter_spacing, width_normal + difference_spacing, epsilon, "letter spacing doesn't work.");
+ }
+
+ // The first value is the letter Spacing to be set, the second value the
+ // change in length of string 'Hello World', note that there are 11 letters
+ // in 'hello world', so the length difference is always letterSpacing * 11.
+ // and the third value is the acceptable differencee for the length change,
+ // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
+ test_cases = [['3px', 33, 0.1],
+ ['5px', 55, 0.1],
+ ['-2px', -22, 0.1],
+ ['1em', 110, 0.1],
+ ['-0.1em', -11, 0.1],
+ ['1in', 1056, 0.1],
+ ['-0.1cm', -41.65, 0.2],
+ ['-0.6mm', -24,95, 0.2]]
+
+ for (const test_case of test_cases) {
+ test_letter_spacing(test_case[0], test_case[1], test_case[2]);
+ }
+
+- name: 2d.text.drawing.style.wordSpacing.measure
+ desc: Testing word spacing with different length units
+ code: |
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === '0px';
+ var width_normal = ctx.measureText('Hello World, again').width;
+
+ function test_word_spacing(value, difference_spacing, epsilon) {
+ ctx.wordSpacing = value;
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === value;
+ width_with_word_spacing = ctx.measureText('Hello World, again').width;
+ assert_approx_equals(width_with_word_spacing, width_normal + difference_spacing, epsilon, "word spacing doesn't work.");
+ }
+
+ // The first value is the word Spacing to be set, the second value the
+ // change in length of string 'Hello World', note that there are 2 words
+ // in 'Hello World, again', so the length difference is always wordSpacing * 2.
+ // and the third value is the acceptable differencee for the length change,
+ // note that unit such as 1cm/1mm doesn't map to an exact pixel value.
+ test_cases = [['3px', 6, 0.1],
+ ['5px', 10, 0.1],
+ ['-2px', -4, 0.1],
+ ['1em', 20, 0.1],
+ ['-0.5em', -10, 0.1],
+ ['1in', 192, 0.1],
+ ['-0.1cm', -7.57, 0.2],
+ ['-0.6mm', -4.54, 0.2]]
+
+ for (const test_case of test_cases) {
+ test_word_spacing(test_case[0], test_case[1], test_case[2]);
+ }
+
+- name: 2d.text.drawing.style.letterSpacing.change.font
+ desc: Set letter spacing and word spacing to font dependent value and verify it works after font change.
+ code: |
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === '0px';
+ // Get the width for 'Hello World' at default size, 10px.
+ var width_normal = ctx.measureText('Hello World').width;
+
+ ctx.letterSpacing = '1em';
+ @assert ctx.letterSpacing === '1em';
+ // 1em = 10px. Add 10px after each letter in "Hello World",
+ // makes it 110px longer.
+ var width_with_spacing = ctx.measureText('Hello World').width;
+ assert_approx_equals(width_with_spacing, width_normal + 110, 0.1, "letter-spacing error");
+
+ // Changing font to 20px. Without resetting the spacing, 1em letterSpacing
+ // is now 20px, so it's suppose to be 220px longer without any letterSpacing set.
+ ctx.font = '20px serif';
+ width_with_spacing = ctx.measureText('Hello World').width;
+ // Now calculate the reference spacing for "Hello World" with no spacing.
+ ctx.letterSpacing = '0em';
+ width_normal = ctx.measureText('Hello World').width;
+ assert_approx_equals(width_with_spacing, width_normal + 220, 0.1, "letter-spacing error after font change");
+
+- name: 2d.text.drawing.style.wordSpacing.change.font
+ desc: Set word spacing and word spacing to font dependent value and verify it works after font change.
+ code: |
+ @assert ctx.letterSpacing === '0px';
+ @assert ctx.wordSpacing === '0px';
+ // Get the width for 'Hello World, again' at default size, 10px.
+ var width_normal = ctx.measureText('Hello World, again').width;
+
+ ctx.wordSpacing = '1em';
+ @assert ctx.wordSpacing === '1em';
+ // 1em = 10px. Add 10px after each word in "Hello World, again",
+ // makes it 20px longer.
+ var width_with_spacing = ctx.measureText('Hello World, again').width;
+ @assert width_with_spacing === width_normal + 20;
+
+ // Changing font to 20px. Without resetting the spacing, 1em wordSpacing
+ // is now 20px, so it's suppose to be 40px longer without any wordSpacing set.
+ ctx.font = '20px serif';
+ width_with_spacing = ctx.measureText('Hello World, again').width;
+ // Now calculate the reference spacing for "Hello World, again" with no spacing.
+ ctx.wordSpacing = '0em';
+ width_normal = ctx.measureText('Hello World, again').width;
+ @assert width_with_spacing === width_normal + 40;
+
+- name: 2d.text.drawing.style.fontKerning
+ desc: Testing basic functionalities of fontKerning for canvas
+ code: |
+ @assert ctx.fontKerning === "auto";
+ ctx.fontKerning = "normal";
+ @assert ctx.fontKerning === "normal";
+ width_normal = ctx.measureText("TAWATAVA").width;
+ ctx.fontKerning = "none";
+ @assert ctx.fontKerning === "none";
+ width_none = ctx.measureText("TAWATAVA").width;
+ @assert width_normal < width_none;
+
+- name: 2d.text.drawing.style.fontKerning.with.uppercase
+ desc: Testing basic functionalities of fontKerning for canvas
+ code: |
+ @assert ctx.fontKerning === "auto";
+ ctx.fontKerning = "Normal";
+ @assert ctx.fontKerning === "auto";
+ ctx.fontKerning = "normal";
+ @assert ctx.fontKerning === "normal";
+ ctx.fontKerning = "Auto";
+ @assert ctx.fontKerning === "normal";
+ ctx.fontKerning = "auto";
+ ctx.fontKerning = "noRmal";
+ @assert ctx.fontKerning === "auto";
+ ctx.fontKerning = "auto";
+ ctx.fontKerning = "NoRMal";
+ @assert ctx.fontKerning === "auto";
+ ctx.fontKerning = "auto";
+ ctx.fontKerning = "NORMAL";
+ @assert ctx.fontKerning === "auto";
+
+ ctx.fontKerning = "None";
+ @assert ctx.fontKerning === "auto";
+ ctx.fontKerning = "none";
+ @assert ctx.fontKerning === "none";
+ ctx.fontKerning = "Auto";
+ @assert ctx.fontKerning === "none";
+ ctx.fontKerning = "auto";
+ ctx.fontKerning = "nOne";
+ @assert ctx.fontKerning === "auto";
+ ctx.fontKerning = "auto";
+ ctx.fontKerning = "nonE";
+ @assert ctx.fontKerning === "auto";
+ ctx.fontKerning = "auto";
+ ctx.fontKerning = "NONE";
+ @assert ctx.fontKerning === "auto";
+
+- name: 2d.text.drawing.style.fontVariant.settings
+ desc: Testing basic functionalities of fontVariant for canvas
+ code: |
+ // Setting fontVariantCaps with lower cases
+ @assert ctx.fontVariantCaps === "normal";
+
+ ctx.fontVariantCaps = "normal";
+ @assert ctx.fontVariantCaps === "normal";
+
+ ctx.fontVariantCaps = "small-caps";
+ @assert ctx.fontVariantCaps === "small-caps";
+
+ ctx.fontVariantCaps = "all-small-caps";
+ @assert ctx.fontVariantCaps === "all-small-caps";
+
+ ctx.fontVariantCaps = "petite-caps";
+ @assert ctx.fontVariantCaps === "petite-caps";
+
+ ctx.fontVariantCaps = "all-petite-caps";
+ @assert ctx.fontVariantCaps === "all-petite-caps";
+
+ ctx.fontVariantCaps = "unicase";
+ @assert ctx.fontVariantCaps === "unicase";
+
+ ctx.fontVariantCaps = "titling-caps";
+ @assert ctx.fontVariantCaps === "titling-caps";
+
+ // Setting fontVariantCaps with mixed-case values is not valid
+ ctx.fontVariantCaps = "nORmal";
+ @assert ctx.fontVariantCaps === "titling-caps";
+
+ ctx.fontVariantCaps = "normal";
+ @assert ctx.fontVariantCaps === "normal";
+
+ ctx.fontVariantCaps = "smaLL-caps";
+ @assert ctx.fontVariantCaps === "normal";
+
+ ctx.fontVariantCaps = "all-small-CAPS";
+ @assert ctx.fontVariantCaps === "normal";
+
+ ctx.fontVariantCaps = "pEtitE-caps";
+ @assert ctx.fontVariantCaps === "normal";
+
+ ctx.fontVariantCaps = "All-Petite-Caps";
+ @assert ctx.fontVariantCaps === "normal";
+
+ ctx.fontVariantCaps = "uNIcase";
+ @assert ctx.fontVariantCaps === "normal";
+
+ ctx.fontVariantCaps = "titling-CAPS";
+ @assert ctx.fontVariantCaps === "normal";
+
+ // Setting fontVariantCaps with non-existing font variant.
+ ctx.fontVariantCaps = "titling-caps";
+ ctx.fontVariantCaps = "abcd";
+ @assert ctx.fontVariantCaps === "titling-caps";
+
+- name: 2d.text.drawing.style.textRendering.settings
+ desc: Testing basic functionalities of textRendering in Canvas
+ code: |
+ // Setting textRendering with correct case.
+ @assert ctx.textRendering === "auto";
+
+ ctx.textRendering = "optimizeSpeed";
+ @assert ctx.textRendering === "optimizeSpeed";
+
+ ctx.textRendering = "optimizeLegibility";
+ @assert ctx.textRendering === "optimizeLegibility";
+
+ ctx.textRendering = "geometricPrecision";
+ @assert ctx.textRendering === "geometricPrecision";
+
+ ctx.textRendering = "auto";
+ @assert ctx.textRendering === "auto";
+
+ // Setting textRendering with incorrect case is ignored.
+ ctx.textRendering = "OPtimizeSpeed";
+ @assert ctx.textRendering === "auto";
+
+ ctx.textRendering = "OPtimizELEgibility";
+ @assert ctx.textRendering === "auto";
+
+ ctx.textRendering = "GeometricPrecision";
+ @assert ctx.textRendering === "auto";
+
+ ctx.textRendering = "optimizespeed";
+ @assert ctx.textRendering === "auto";
+
+ ctx.textRendering = "optimizelegibility";
+ @assert ctx.textRendering === "auto";
+
+ ctx.textRendering = "geometricprecision";
+ @assert ctx.textRendering === "auto";
+
+ ctx.textRendering = "optimizeLegibility";
+ @assert ctx.textRendering === "optimizeLegibility";
+
+ ctx.textRendering = "AUTO";
+ @assert ctx.textRendering === "optimizeLegibility";
+
+ ctx.textRendering = "Auto";
+ @assert ctx.textRendering === "optimizeLegibility";
+
+ // Setting textRendering with non-existing font variant.
+ ctx.textRendering = "abcd";
+ @assert ctx.textRendering === "optimizeLegibility";
+
+ ctx.textRendering = "normal";
+ @assert ctx.textRendering === "optimizeLegibility";
+
+ ctx.textRendering = "";
+ @assert ctx.textRendering === "optimizeLegibility";
+
+ ctx.textRendering = "auto";
+ @assert ctx.textRendering === "auto";
+
+- name: 2d.text.drawing.style.fontStretch.settings
+ desc: Testing value setting of fontStretch in Canvas
+ code: |
+ // Setting textRendering with lower cases
+ ctx.fontStretch = "ultra-condensed";
+ @assert ctx.fontStretch === "ultra-condensed";
+
+ ctx.fontStretch = "extra-condensed";
+ @assert ctx.fontStretch === "extra-condensed";
+
+ ctx.fontStretch = "condensed";
+ @assert ctx.fontStretch === "condensed";
+
+ ctx.fontStretch = "semi-condensed";
+ @assert ctx.fontStretch === "semi-condensed";
+
+ ctx.fontStretch = "normal";
+ @assert ctx.fontStretch === "normal";
+
+ ctx.fontStretch = "semi-expanded";
+ @assert ctx.fontStretch === "semi-expanded";
+
+ ctx.fontStretch = "expanded";
+ @assert ctx.fontStretch === "expanded";
+
+ ctx.fontStretch = "extra-expanded";
+ @assert ctx.fontStretch === "extra-expanded";
+
+ ctx.fontStretch = "ultra-expanded";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ // Setting fontStretch with lower cases and upper cases word,
+ // these values should be ignored.
+ ctx.fontStretch = "ulTra-condensed";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ ctx.fontStretch = "Extra-condensed";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ ctx.fontStretch = "cOndensed";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ ctx.fontStretch = "Semi-Condensed";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ ctx.fontStretch = "normaL";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ ctx.fontStretch = "semi-Expanded";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ ctx.fontStretch = "Expanded";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ ctx.fontStretch = "eXtra-expanded";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+ ctx.fontStretch = "abcd";
+ @assert ctx.fontStretch === "ultra-expanded";
+
+- name: 2d.text.fontVariantCaps1
+ desc: Testing small caps setting in fontVariant
+ code: |
+ ctx.font = "32px serif";
+ ctx.fontVariantCaps = "small-caps";
+ // This should render the same as font = "small-caps 32px serif".
+ ctx.fillText("Hello World", 20, 100);
+ reference: |
+ ctx.font = "small-caps 32px serif";
+ ctx.fillText("Hello World", 20, 100);
+
+- name: 2d.text.fontVariantCaps2
+ desc: Testing small caps setting in fontVariant
+ code: |
+ ctx.font = "small-caps 32px serif";
+ // "mismatch" test, to verify that small-caps does change the rendering.
+ smallCaps_len = ctx.measureText("Hello World").width;
+
+ ctx.font = "32px serif";
+ normalCaps_len = ctx.measureText("Hello World").width;
+ @assert smallCaps_len != normalCaps_len;
+
+- name: 2d.text.fontVariantCaps3
+ desc: Testing small caps setting in fontVariant
+ code: |
+ ctx.font = "32px serif";
+ ctx.fontVariantCaps = "all-small-caps";
+ // This should render the same as using font = "small-caps 32px serif"
+ // with all the underlying text in lowercase.
+ ctx.fillText("Hello World", 20, 100);
+ reference: |
+ ctx.font = "small-caps 32px serif";
+ ctx.fillText("hello world", 20, 100);
+
+- name: 2d.text.fontVariantCaps4
+ desc: Testing small caps setting in fontVariant
+ code: |
+ ctx.font = "small-caps 32px serif";
+ // fontVariantCaps overrides the small-caps setting from the font attribute
+ // (spec unclear, cf. https://github.com/whatwg/html/issues/8103)
+ ctx.fontVariantCaps = "all-small-caps";
+ ctx.fillText("Hello World", 20, 100);
+ reference: |
+ ctx.font = "small-caps 32px serif";
+ ctx.fillText("hello world", 20, 100);
+
+- name: 2d.text.fontVariantCaps5
+ desc: Testing small caps setting in fontVariant
+ code: |
+ ctx.font = "small-caps 32px serif";
+ // fontVariantCaps 'normal' does not override the setting from the font attribute.
+ // (spec unclear, cf. https://github.com/whatwg/html/issues/8103)
+ ctx.fontVariantCaps = "normal";
+ ctx.fillText("Hello World", 20, 100);
+ reference: |
+ ctx.font = "small-caps 32px serif";
+ ctx.fillText("Hello World", 20, 100);
+
+- name: 2d.text.fontVariantCaps6
+ desc: Testing small caps setting in fontVariant
+ code: |
+ // fontVariantCaps is reset when the font attribute is set.
+ // (spec unclear, cf. https://github.com/whatwg/html/issues/8103)
+ ctx.fontVariantCaps = "all-small-caps";
+ ctx.font = "32px serif";
+ ctx.fillText("Hello World", 20, 100);
+ reference: |
+ ctx.font = "32px serif";
+ ctx.fillText("Hello World", 20, 100);
+
+- name: 2d.text.setFont.mathFont
+ desc: crbug.com/1212190, make sure offscreencanvas doesn't crash with Math Font
+ code: |
+ ctx.font = "math serif";
+
+# TODO: shadows, alpha, composite, clip