|
5 | 5 | <link rel="help" href="https://github.com/WICG/html-in-canvas"> |
6 | 6 | <script src="/resources/testharness.js"></script> |
7 | 7 | <script src="/resources/testharnessreport.js"></script> |
| 8 | + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> |
8 | 9 | </head> |
9 | | -<body style="margin: 0;"> |
| 10 | +<body style="margin: 0;" onload="runTest()"> |
10 | 11 | <canvas id="canvas" style="position: absolute; left: 10px; top: 20px; width: 400px; height: 400px;" layoutsubtree> |
11 | | - <div id="target" style="position: absolute; left: 0; top: 0; width: 100px; height: 50px;"></div> |
| 12 | + <div id="target" style="position: absolute; left: 0; top: 0; width: 100px; height: 50px;"> |
| 13 | + <span id="nested-inline" drawable style="font: 25px/1 Ahem;">X</span> |
| 14 | + <div id="nested-block" drawable style="width: 20px; height: 30px;"></div> |
| 15 | + <div id="nested-non-drawable" style="width: 15px; height: 25px;"></div> |
| 16 | + </div> |
12 | 17 | </canvas> |
13 | 18 | <div id="outside" style="position: absolute; left: 10px; top: 10px; width: 100px; height: 50px;"></div> |
14 | 19 |
|
15 | 20 | <script> |
16 | 21 | 'use strict'; |
17 | 22 |
|
18 | | - // TODO(crbug.com/532229486): Add a test of inlines. |
19 | | - |
20 | | - test(() => { |
21 | | - const target = document.getElementById('target'); |
22 | | - let rect = target.getBoundingClientRect(); |
23 | | - assert_equals(rect.left, 10); |
24 | | - assert_equals(rect.top, 20); |
25 | | - |
26 | | - // Translate. |
27 | | - target.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
28 | | - rect = target.getBoundingClientRect(); |
29 | | - assert_equals(rect.left, 40); |
30 | | - assert_equals(rect.top, 60); |
31 | | - |
32 | | - // Scale and translate. |
33 | | - target.setCanvasTransform(new DOMMatrix().translate(50, 60).scale(2, 3)); |
34 | | - rect = target.getBoundingClientRect(); |
35 | | - assert_equals(rect.left, 60); |
36 | | - assert_equals(rect.top, 80); |
37 | | - assert_equals(rect.width, 200); |
38 | | - assert_equals(rect.height, 150); |
39 | | - |
40 | | - // Compound with CSS transform: Canvas transform applies before CSS transform. |
41 | | - // With CSS transform scale(2) around center (50, 25), target bounds are |
42 | | - // [-50..150, -25..75] relative to (0, 0). |
43 | | - // Canvas transform translates by (30, 40), giving [-20..180, 15..115]. |
44 | | - // Adding canvas position (10, 20) yields rect left = -10, top = 35. |
45 | | - // If canvas transform were applied after CSS transform, left would be 20, top would be 75. |
46 | | - target.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
47 | | - target.style.transform = 'scale(2)'; |
48 | | - rect = target.getBoundingClientRect(); |
49 | | - assert_approx_equals(rect.left, 10 + 30 - 50, 0.01); |
50 | | - assert_approx_equals(rect.top, 20 + 40 - 25, 0.01); |
51 | | - assert_approx_equals(rect.width, 200, 0.01); |
52 | | - assert_approx_equals(rect.height, 100, 0.01); |
53 | | - |
54 | | - // Compound with CSS translate and transform properties: Canvas transform |
55 | | - // applies before all CSS transforms, including individual transform properties. |
56 | | - target.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
57 | | - target.style.translate = '5px 10px'; |
58 | | - target.style.transform = 'scale(2)'; |
59 | | - rect = target.getBoundingClientRect(); |
60 | | - assert_approx_equals(rect.left, 10 + 30 + 5 - 50, 0.01); |
61 | | - assert_approx_equals(rect.top, 20 + 40 + 10 - 25, 0.01); |
62 | | - assert_approx_equals(rect.width, 200, 0.01); |
63 | | - assert_approx_equals(rect.height, 100, 0.01); |
64 | | - |
65 | | - // Reset. |
66 | | - target.style.translate = ''; |
67 | | - target.style.transform = ''; |
68 | | - target.setCanvasTransform(new DOMMatrix()); |
69 | | - rect = target.getBoundingClientRect(); |
70 | | - assert_equals(rect.left, 10); |
71 | | - assert_equals(rect.top, 20); |
72 | | - assert_equals(rect.width, 100); |
73 | | - assert_equals(rect.height, 50); |
74 | | - }, 'setCanvasTransform() affects getBoundingClientRect() on canvas child'); |
75 | | - |
76 | | - test(() => { |
77 | | - const outside = document.getElementById('outside'); |
78 | | - outside.setCanvasTransform(new DOMMatrix().translate(50, 50)); |
79 | | - const rect = outside.getBoundingClientRect(); |
80 | | - assert_equals(rect.left, 10); |
81 | | - assert_equals(rect.top, 10); |
82 | | - }, 'setCanvasTransform() does not affect getBoundingClientRect() outside canvas subtree'); |
| 23 | + const runTest = () => { |
| 24 | + test(() => { |
| 25 | + const target = document.getElementById('target'); |
| 26 | + let rect = target.getBoundingClientRect(); |
| 27 | + assert_equals(rect.left, 10); |
| 28 | + assert_equals(rect.top, 20); |
| 29 | + |
| 30 | + // Translate. |
| 31 | + target.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
| 32 | + rect = target.getBoundingClientRect(); |
| 33 | + assert_equals(rect.left, 40); |
| 34 | + assert_equals(rect.top, 60); |
| 35 | + |
| 36 | + // Scale and translate. |
| 37 | + target.setCanvasTransform(new DOMMatrix().translate(50, 60).scale(2, 3)); |
| 38 | + rect = target.getBoundingClientRect(); |
| 39 | + assert_equals(rect.left, 60); |
| 40 | + assert_equals(rect.top, 80); |
| 41 | + assert_equals(rect.width, 200); |
| 42 | + assert_equals(rect.height, 150); |
| 43 | + |
| 44 | + // Compound with CSS transform: Canvas transform applies before CSS transform. |
| 45 | + // With CSS transform scale(2) around center (50, 25), target bounds are |
| 46 | + // [-50..150, -25..75] relative to (0, 0). |
| 47 | + // Canvas transform translates by (30, 40), giving [-20..180, 15..115]. |
| 48 | + // Adding canvas position (10, 20) yields rect left = -10, top = 35. |
| 49 | + // If canvas transform were applied after CSS transform, left would be 20, top would be 75. |
| 50 | + target.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
| 51 | + target.style.transform = 'scale(2)'; |
| 52 | + rect = target.getBoundingClientRect(); |
| 53 | + assert_approx_equals(rect.left, 10 + 30 - 50, 0.01); |
| 54 | + assert_approx_equals(rect.top, 20 + 40 - 25, 0.01); |
| 55 | + assert_approx_equals(rect.width, 200, 0.01); |
| 56 | + assert_approx_equals(rect.height, 100, 0.01); |
| 57 | + |
| 58 | + // Compound with CSS translate and transform properties: Canvas transform |
| 59 | + // applies before all CSS transforms, including individual transform properties. |
| 60 | + target.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
| 61 | + target.style.translate = '5px 10px'; |
| 62 | + target.style.transform = 'scale(2)'; |
| 63 | + rect = target.getBoundingClientRect(); |
| 64 | + assert_approx_equals(rect.left, 10 + 30 + 5 - 50, 0.01); |
| 65 | + assert_approx_equals(rect.top, 20 + 40 + 10 - 25, 0.01); |
| 66 | + assert_approx_equals(rect.width, 200, 0.01); |
| 67 | + assert_approx_equals(rect.height, 100, 0.01); |
| 68 | + |
| 69 | + // Reset. |
| 70 | + target.style.translate = ''; |
| 71 | + target.style.transform = ''; |
| 72 | + target.setCanvasTransform(new DOMMatrix()); |
| 73 | + rect = target.getBoundingClientRect(); |
| 74 | + assert_equals(rect.left, 10); |
| 75 | + assert_equals(rect.top, 20); |
| 76 | + assert_equals(rect.width, 100); |
| 77 | + assert_equals(rect.height, 50); |
| 78 | + }, 'setCanvasTransform() affects getBoundingClientRect() on canvas child'); |
| 79 | + |
| 80 | + test(() => { |
| 81 | + const nestedInline = document.getElementById('nested-inline'); |
| 82 | + let rect = nestedInline.getBoundingClientRect(); |
| 83 | + assert_equals(rect.left, 10); |
| 84 | + assert_equals(rect.top, 20); |
| 85 | + assert_equals(rect.width, 25); |
| 86 | + assert_equals(rect.height, 25); |
| 87 | + |
| 88 | + // Translate. |
| 89 | + nestedInline.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
| 90 | + rect = nestedInline.getBoundingClientRect(); |
| 91 | + assert_equals(rect.left, 10 + 30); |
| 92 | + assert_equals(rect.top, 20 + 40); |
| 93 | + assert_equals(rect.width, 25); |
| 94 | + assert_equals(rect.height, 25); |
| 95 | + |
| 96 | + // Scale and translate. |
| 97 | + nestedInline.setCanvasTransform(new DOMMatrix().translate(50, 60).scale(2, 3)); |
| 98 | + rect = nestedInline.getBoundingClientRect(); |
| 99 | + assert_equals(rect.left, 10 + 50); |
| 100 | + assert_equals(rect.top, 20 + 60); |
| 101 | + assert_equals(rect.width, 2 * 25); |
| 102 | + assert_equals(rect.height, 3 * 25); |
| 103 | + |
| 104 | + // Test that canvas transform is unaffected by CSS margin. |
| 105 | + nestedInline.setCanvasTransform(new DOMMatrix().translate(50, 60).scale(2, 3)); |
| 106 | + nestedInline.style.marginLeft = '12px'; |
| 107 | + rect = nestedInline.getBoundingClientRect(); |
| 108 | + assert_equals(rect.left, 10 + 50); |
| 109 | + assert_equals(rect.top, 20 + 60); |
| 110 | + assert_equals(rect.width, 2 * 25); |
| 111 | + assert_equals(rect.height, 3 * 25); |
| 112 | + |
| 113 | + // Reset. |
| 114 | + nestedInline.style.marginLeft = '0'; |
| 115 | + nestedInline.setCanvasTransform(new DOMMatrix()); |
| 116 | + rect = nestedInline.getBoundingClientRect(); |
| 117 | + assert_equals(rect.left, 10); |
| 118 | + assert_equals(rect.top, 20); |
| 119 | + assert_equals(rect.width, 25); |
| 120 | + assert_equals(rect.height, 25); |
| 121 | + }, 'setCanvasTransform() affects getBoundingClientRect() on an inline nested drawable'); |
| 122 | + |
| 123 | + test(() => { |
| 124 | + const target = document.getElementById('target'); |
| 125 | + const nestedBlock = document.getElementById('nested-block'); |
| 126 | + |
| 127 | + // When ancestor has a canvas transform set, a nested drawable without its own |
| 128 | + // canvas transform does not inherit the ancestor's canvas transform. |
| 129 | + target.setCanvasTransform(new DOMMatrix().translate(100, 200)); |
| 130 | + let rect = nestedBlock.getBoundingClientRect(); |
| 131 | + assert_equals(rect.left, 10); |
| 132 | + assert_equals(rect.top, 20); |
| 133 | + |
| 134 | + // When the nested drawable also sets a canvas transform, it is relative to |
| 135 | + // the canvas and does not include the ancestor's canvas transform. |
| 136 | + nestedBlock.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
| 137 | + rect = nestedBlock.getBoundingClientRect(); |
| 138 | + assert_equals(rect.left, 10 + 30); |
| 139 | + assert_equals(rect.top, 20 + 40); |
| 140 | + assert_equals(rect.width, 20); |
| 141 | + assert_equals(rect.height, 30); |
| 142 | + |
| 143 | + // Reset. |
| 144 | + target.setCanvasTransform(new DOMMatrix()); |
| 145 | + nestedBlock.setCanvasTransform(new DOMMatrix()); |
| 146 | + }, 'setCanvasTransform() on ancestor and nested drawable'); |
| 147 | + |
| 148 | + test(() => { |
| 149 | + const nestedBlock = document.getElementById('nested-block'); |
| 150 | + let rect = nestedBlock.getBoundingClientRect(); |
| 151 | + assert_equals(rect.left, 10); |
| 152 | + assert_equals(rect.top, 20); |
| 153 | + assert_equals(rect.width, 20); |
| 154 | + assert_equals(rect.height, 30); |
| 155 | + |
| 156 | + // Translate. |
| 157 | + nestedBlock.setCanvasTransform(new DOMMatrix().translate(30, 40)); |
| 158 | + rect = nestedBlock.getBoundingClientRect(); |
| 159 | + assert_equals(rect.left, 10 + 30); |
| 160 | + assert_equals(rect.top, 20 + 40); |
| 161 | + |
| 162 | + // Scale and translate. |
| 163 | + nestedBlock.setCanvasTransform(new DOMMatrix().translate(50, 60).scale(2, 3)); |
| 164 | + rect = nestedBlock.getBoundingClientRect(); |
| 165 | + assert_equals(rect.left, 10 + 50); |
| 166 | + assert_equals(rect.top, 20 + 60); |
| 167 | + assert_equals(rect.width, 2 * 20); |
| 168 | + assert_equals(rect.height, 3 * 30); |
| 169 | + |
| 170 | + // Test that canvas transform is unaffected by CSS margin. |
| 171 | + nestedBlock.setCanvasTransform(new DOMMatrix().translate(50, 60).scale(2, 3)); |
| 172 | + nestedBlock.style.marginLeft = '12px'; |
| 173 | + rect = nestedBlock.getBoundingClientRect(); |
| 174 | + assert_equals(rect.left, 10 + 50); |
| 175 | + assert_equals(rect.top, 20 + 60); |
| 176 | + assert_equals(rect.width, 2 * 20); |
| 177 | + assert_equals(rect.height, 3 * 30); |
| 178 | + nestedBlock.style.marginLeft = ''; |
| 179 | + |
| 180 | + // Test that canvas transform applies before CSS transform. |
| 181 | + // If canvas transform applied after CSS transform, the translation of |
| 182 | + // 50, 60 would be scaled 2x. |
| 183 | + nestedBlock.setCanvasTransform(new DOMMatrix().translate(50, 60).scale(2, 3)); |
| 184 | + nestedBlock.style.transform = 'scale(2)'; |
| 185 | + nestedBlock.style.transformOrigin = 'top left'; |
| 186 | + rect = nestedBlock.getBoundingClientRect(); |
| 187 | + assert_equals(rect.left, 10 + 50); |
| 188 | + assert_equals(rect.top, 20 + 60); |
| 189 | + assert_equals(rect.width, 2 * 2 * 20); |
| 190 | + assert_equals(rect.height, 2 * 3 * 30); |
| 191 | + |
| 192 | + // Reset. |
| 193 | + nestedBlock.style.marginLeft = ''; |
| 194 | + nestedBlock.style.transform = ''; |
| 195 | + nestedBlock.style.transformOrigin = ''; |
| 196 | + nestedBlock.setCanvasTransform(new DOMMatrix()); |
| 197 | + rect = nestedBlock.getBoundingClientRect(); |
| 198 | + assert_equals(rect.left, 10); |
| 199 | + assert_equals(rect.top, 20); |
| 200 | + assert_equals(rect.width, 20); |
| 201 | + assert_equals(rect.height, 30); |
| 202 | + }, 'setCanvasTransform() affects getBoundingClientRect() on a block nested drawable'); |
| 203 | + |
| 204 | + test(() => { |
| 205 | + const target = document.getElementById('target'); |
| 206 | + const nestedNonDrawable = document.getElementById('nested-non-drawable'); |
| 207 | + |
| 208 | + // A non-drawable descendant inherits its ancestor's canvas transform. |
| 209 | + const initialRect = nestedNonDrawable.getBoundingClientRect(); |
| 210 | + target.setCanvasTransform(new DOMMatrix().translate(100, 200)); |
| 211 | + let rect = nestedNonDrawable.getBoundingClientRect(); |
| 212 | + assert_equals(rect.left, initialRect.left + 100); |
| 213 | + assert_equals(rect.top, initialRect.top + 200); |
| 214 | + assert_equals(rect.width, initialRect.width); |
| 215 | + assert_equals(rect.height, initialRect.height); |
| 216 | + |
| 217 | + // Reset. |
| 218 | + target.setCanvasTransform(new DOMMatrix()); |
| 219 | + rect = nestedNonDrawable.getBoundingClientRect(); |
| 220 | + assert_equals(rect.left, initialRect.left); |
| 221 | + assert_equals(rect.top, initialRect.top); |
| 222 | + }, 'A non-drawable descendant inherits its ancestor\'s canvas transform'); |
| 223 | + |
| 224 | + test(() => { |
| 225 | + const outside = document.getElementById('outside'); |
| 226 | + outside.setCanvasTransform(new DOMMatrix().translate(50, 50)); |
| 227 | + const rect = outside.getBoundingClientRect(); |
| 228 | + assert_equals(rect.left, 10); |
| 229 | + assert_equals(rect.top, 10); |
| 230 | + }, 'setCanvasTransform() does not affect getBoundingClientRect() outside canvas subtree'); |
| 231 | + } |
83 | 232 | </script> |
84 | 233 | </body> |
85 | 234 | </html> |
0 commit comments