-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Add HTML-in-Canvas APIs #11588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add HTML-in-Canvas APIs #11588
Changes from 13 commits
e181de1
8634ebe
afc4a4d
f151c83
74d67ae
f7d320a
3cad6d4
4367aac
84ec8e6
f351c3d
aed994e
8c3ce46
ff066c9
5e3c3d0
f8f119a
202adae
be22310
9866034
4e559a9
4838669
9fa39e9
f79ed95
0a243be
1f71b9a
5aeb03b
951bdee
ba5c560
4d77e94
d033976
b953591
a852071
5b5dc3d
49184b4
8d0edfc
0480023
ffe1e1e
bc57d89
00b5bf9
769de4c
ab2ee8f
b2cd7a3
4096cbc
3ccf75f
a27ade2
f3b7fe0
bd7a35c
46273d9
d9c4769
e3965e6
12f02aa
0a158e6
2df6477
c5e2815
2850d56
f4f738b
09b811d
542723b
7aee3ee
2c95e37
0a476ef
71347b5
22b725e
959ca6b
3350248
cb6c69d
ae964a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65673,6 +65673,7 @@ dictionary <dfn dictionary>AssignedNodesOptions</dfn> { | |
| <dd><span>Global attributes</span></dd> | ||
| <dd><code data-x="attr-canvas-width">width</code></dd> | ||
| <dd><code data-x="attr-canvas-height">height</code></dd> | ||
| <dd><code data-x="attr-canvas-layoutsubtree">layoutsubtree</code></dd> | ||
| <dt><span | ||
| data-x="concept-element-accessibility-considerations">Accessibility considerations</span>:</dt> | ||
| <dd><a href="https://w3c.github.io/html-aria/#el-canvas">For authors</a>.</dd> | ||
|
|
@@ -65775,6 +65776,12 @@ callback <dfn callback>BlobCallback</dfn> = undefined (<span>Blob</span>? blob); | |
| <p>The user agent must use a square pixel density consisting of one pixel of image data per | ||
| coordinate space unit for the bitmaps of a <code>canvas</code> and its rendering contexts.</p> | ||
|
|
||
| <p>The <dfn element-attr for="canvas"><code | ||
| data-x="attr-canvas-layoutsubtree">layoutsubtree</code></dfn> attribute is a <span>boolean | ||
| attribute</span>. If present, <span data-x="concept-tree-child">children</span> of the | ||
| <data>canvas</data> element are layed out, so that they can be drawn using <code | ||
| data-x="dom-context-2d-drawElementImage">drawElementImage()</code>.</p> | ||
|
|
||
| <p class="note">A <code>canvas</code> element can be sized arbitrarily by a style sheet, its | ||
| bitmap is then subject to the <span>'object-fit'</span> CSS property.</p> | ||
|
|
||
|
|
@@ -66274,6 +66281,8 @@ interface <dfn interface>CanvasRenderingContext2D</dfn> { | |
| <span>CanvasRenderingContext2D</span> includes <span>CanvasDrawPath</span>; | ||
| <span>CanvasRenderingContext2D</span> includes <span>CanvasUserInterface</span>; | ||
| <span>CanvasRenderingContext2D</span> includes <span>CanvasText</span>; | ||
| <span>CanvasRenderingContext2D</span> includes <span>CanvasDrawElementImage</span>; | ||
| <span>CanvasRenderingContext2D</span> includes <span>CanvasHitTestRegions</span>; | ||
| <span>CanvasRenderingContext2D</span> includes <span>CanvasDrawImage</span>; | ||
| <span>CanvasRenderingContext2D</span> includes <span>CanvasImageData</span>; | ||
| <span>CanvasRenderingContext2D</span> includes <span>CanvasPathDrawingStyles</span>; | ||
|
|
@@ -66393,6 +66402,29 @@ interface mixin <dfn interface>CanvasText</dfn> { | |
| <span>TextMetrics</span> <span data-x="dom-context-2d-measureText">measureText</span>(DOMString text); | ||
| }; | ||
|
|
||
| interface mixin <dfn interface>CanvasDrawElementImage</dfn> { | ||
| // drawing elements | ||
| undefined <span data-x="dom-context-2d-drawElementImage">drawElementImage</span>(<span>Element</span> element, unrestricted double x, unrestricted double y); | ||
| undefined <span data-x="dom-context-2d-drawElementImage">drawElementImage</span>(<span>Element</span> element, unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); | ||
| }; | ||
|
|
||
| dictionary <dfn dictionary>CanvasHitTestRect</dfn> { | ||
| double <dfn dict-member for="CanvasHitTestRect" data-x="dom-CanvasHitTestRect-x">x</dfn>; | ||
| double <dfn dict-member for="CanvasHitTestRect" data-x="dom-CanvasHitTestRect-y">y</dfn>; | ||
| double? <dfn dict-member for="CanvasHitTestRect" data-x="dom-CanvasHitTestRect-width">width</dfn>; | ||
| double? <dfn dict-member for="CanvasHitTestRect" data-x="dom-CanvasHitTestRect-height">height</dfn>; | ||
| }; | ||
|
|
||
| dictionary <dfn dictionary>CanvasElementHitTestRegion</dfn> { | ||
| <span>Element</span> <dfn dict-member for="CanvasElementHitTestRegion" data-x="dom-CanvasElementHitTestRegion-element">element</dfn>; | ||
| <span>CanvasHitTestRect</span> <dfn dict-member for="CanvasElementHitTestRegion" data-x="dom-CanvasElementHitTestRegion-rect">rect</dfn>; | ||
| }; | ||
|
|
||
| interface mixin <dfn interface>CanvasHitTestRegions</dfn> { | ||
| // hit testing | ||
| undefined <span data-x="dom-context-2d-setHitTestRegions">setHitTestRegions</span>(sequence<CanvasElementHitTestRegion> regions); | ||
| }; | ||
|
|
||
| interface mixin <dfn interface>CanvasDrawImage</dfn> { | ||
| // drawing images | ||
| undefined <span data-x="dom-context-2d-drawImage">drawImage</span>(<span>CanvasImageSource</span> image, unrestricted double dx, unrestricted double dy); | ||
|
|
@@ -70681,6 +70713,215 @@ try { | |
|
|
||
| </div> | ||
|
|
||
|
|
||
| <h6>Drawing elements</h6> | ||
|
|
||
| <dl class="domintro"> | ||
| <dt><code data-x=""><var>context</var>.<span subdfn data-x="dom-context-2d-drawElementImage">drawElementImage</span>(<var>element</var>, <var>x</var>, <var>y</var>)</code></dt> | ||
|
foolip marked this conversation as resolved.
Outdated
|
||
| <dt><code data-x=""><var>context</var>.<span data-x="dom-context-2d-drawElementImage">drawElementImage</span>(<var>element</var>, <var>x</var>, <var>y</var>, <var>w</var>, <var>h</var>)</code></dt> | ||
|
|
||
|
foolip marked this conversation as resolved.
Outdated
|
||
| <dd> | ||
| <p>Draws the given element onto the canvas. Throws a <code>TypeError</code> if the element isn't | ||
|
foolip marked this conversation as resolved.
Outdated
|
||
| a descendant of the canvas.</p> | ||
| </dd> | ||
| </dl> | ||
|
|
||
| <div w-nodev> | ||
|
|
||
| <p>Objects that implement the <code>CanvasDrawElementImage</code> interface have the <dfn method | ||
| for="CanvasDrawElementImage"><code | ||
| data-x="dom-context-2d-drawElementImage">drawElementImage()</code></dfn> method to draw | ||
|
foolip marked this conversation as resolved.
Outdated
|
||
| elements.</p> | ||
|
|
||
| <p>The <code data-x="dom-context-2d-drawElementImage">drawElementImage(element, x, y)</code> method, | ||
| when invoked, must <span>draw an element</span> with <span>this</span>, <var>element</var>, | ||
| <var>x</var>, <var>y</var>.</p> | ||
|
|
||
| <p>The <code data-x="dom-context-2d-drawElementImage">drawElementImage(element, x, y, w, h)</code> | ||
| method, when invoked, must <span>draw an element</span> with <span>this</span>, | ||
| <var>element</var>, <var>x</var>, <var>y</var>, <var>w</var>, and <var>h</var>.</p> | ||
|
|
||
| <p>To <dfn>draw an element</dfn>, with a <code>CanvasRenderingContext2D</code> <var>context</var>, | ||
| an element <var>element</var>, numbers <var>x</var> and <var>y</var>, and optional numbers | ||
| <var>w</var> and <var>h</var>:</p> | ||
|
|
||
| <ol> | ||
| <li><p>If <var>x</var> or <var>y</var> are infinite or NaN, then return.</p></li> | ||
|
|
||
| <li><p>If <var>w</var> and <var>h</var> are given and either are infinite or NaN, then | ||
| return.</p></li> | ||
|
|
||
| <li><p>Let <var>canvas</var> be the <code>canvas</code> element to which <var>context</var> is | ||
| bound.</p></li> | ||
|
|
||
| <li><p>If <var>element</var>'s <span>parent</span> is not <var>canvas</var>, then throw a | ||
| <code>TypeError</code>.</p></li> | ||
|
|
||
| <li><p>If <var>canvas</var> does not have a <code | ||
| data-x="attr-canvas-layoutsubtree">layoutsubtree</code> attribute specified, then throw a | ||
| <code>TypeError</code>.</p></li> | ||
|
|
||
| <li><p>Let <var>layoutBox</var> be <var>element</var>'s CSS layout box.</p></li> | ||
|
foolip marked this conversation as resolved.
Outdated
|
||
|
|
||
| <li><p>If not given, <var>w</var> and <var>h</var> must default to the width and height of | ||
| <var>layoutBox</var>.</p></li> | ||
|
|
||
| <li><p>If either <var>w</var> or <var>h</var> are zero, then return.</p></li> | ||
|
|
||
| <li><p>Paint <var>element</var> to the specified rectangular area without using any | ||
| <span>sensitive information</span>. Instead, either paint nothing or use static information that | ||
| is the same for all users.</p></li> | ||
| </ol> | ||
|
|
||
| <p>When drawing elements to a <code>canvas</code>, no information should be used that isn't | ||
| otherwise observable to author code. Such <dfn export>sensitive information</dfn> includes | ||
| but isn't limited to:</p> | ||
|
|
||
| <ul> | ||
| <li><p><span>CORS-cross-origin</span> data</p></li> | ||
|
|
||
| <li><p>system colors, themes, or preferences</p></li> | ||
|
|
||
| <li><p>spelling and grammar markers</p></li> | ||
|
|
||
| <li><p>search text (find-in-page) and text-fragment (fragment url) markers</p></li> | ||
|
|
||
| <li><p>visited link information</p></li> | ||
|
|
||
| <li><p>form autofill information</p></li> | ||
| </ul> | ||
|
|
||
| </div> | ||
|
|
||
|
|
||
| <h6>Hit testing</h6> | ||
|
|
||
| <dl class="domintro"> | ||
| <dt><code data-x=""><var>context</var>.<span subdfn data-x="dom-context-2d-setHitTestRegions">setHitTestRegions</span>(<var>regions</var>)</code></dt> | ||
|
|
||
| <dd> | ||
| <p>Sets hit test regions mapping given regions (rectangles) of the canvas to descendants of the | ||
| <code>canvas</code> element.</p> | ||
| </dd> | ||
| </dl> | ||
|
|
||
| <div w-nodev> | ||
|
|
||
| <p>Objects that implement the <code>CanvasHitTestRegions</code> interface have the <dfn method | ||
| for="CanvasHitTestRegions"><code | ||
| data-x="dom-context-2d-setHitTestRegions">setHitTestRegions()</code></dfn> method to set up | ||
| hit testing regions.</p> | ||
|
|
||
| <p>Each <code>canvas</code> element has a <dfn>hit test regions</dfn> | ||
| <span>list</span> of <span>hit test regions</span>s, initially empty.</p> | ||
|
foolip marked this conversation as resolved.
Outdated
|
||
|
|
||
| <p>A <dfn>hit test region</dfn> is a <span>struct</span> consisting of an | ||
| <dfn data-x="hit-test-region-element">element</dfn> (element), | ||
| <dfn data-x="hit-test-region-x">x</dfn> (number), | ||
| <dfn data-x="hit-test-region-y">y</dfn> (number), | ||
| <dfn data-x="hit-test-region-width">width</dfn> (number), and | ||
| <dfn data-x="hit-test-region-height">height</dfn> (number). | ||
|
|
||
| <p>The <code data-x="dom-context-2d-setHitTestRegions">setHitTestRegions(regions)</code> method, | ||
| when invoked, must <span>set hit test regions</span> with with <span>this</span> and | ||
| <var>regions</var>.</p> | ||
|
|
||
| <p>To <dfn>set hit test regions</dfn>, with a <code>CanvasRenderingContext2D</code> | ||
| <var>context</var> and a <span>list</span> of <code>CanvasElementHitTestRegion</code> | ||
| dictionaries <var>regions</var>:</p> | ||
|
|
||
| <ol> | ||
| <li><p>Let <var>newRegions</var> be an empty list.</p></li> | ||
|
|
||
| <li><p>Let <var>canvas</var> be the <code>canvas</code> element to which <var>this</var> is | ||
| bound.</p></li> | ||
|
|
||
| <li> | ||
| <p>For each <code>CanvasElementHitTestRegion</code> <var>region</var> in <var>regions</var>:</p> | ||
|
|
||
| <ol> | ||
| <li><p>If <var>region</var>["<code data-x="dom-CanvasElementHitTestRegion-element">element</code>"] | ||
| or <var>region</var>["<code data-x="dom-CanvasElementHitTestRegion-element">rect</code>"] do not | ||
| exist, then throw a <code>TypeError</code>.</p></li> | ||
| <!-- TODO: just make them required --> | ||
|
|
||
| <li><p>Let <var>element</var> be <var>region</var>["<code data-x="dom-CanvasElementHitTestRegion-element">element</code>"].</p></li> | ||
|
|
||
| <li><p>If <var>element</var>'s <span>parent</span> is not <var>canvas</var>, then throw a <code>TypeError</code>.</p></li> | ||
| <!-- TODO: what if the element moves later? --> | ||
|
|
||
| <li><p>Let <var>rect</var> be <var>region</var>["<code data-x="dom-CanvasElementHitTestRegion-rect">rect</code>"].</p></li> | ||
|
|
||
| <li><p>If <var>rect</var>["<code data-x="dom-CanvasHitTestRect-x">x</code>"] or | ||
| <var>rect</var>["<code data-x="dom-CanvasHitTestRect-y">y</code>"] do not exist, then throw a | ||
| <code>TypeError</code>.</p></li> | ||
| <!-- TODO: just make them required --> | ||
|
|
||
| <li><p>Let <var>x</var> be <var>rect</var>["<code data-x="dom-CanvasHitTestRect-x">x</code>"].</p></li> | ||
|
|
||
| <li><p>Let <var>y</var> be <var>rect</var>["<code data-x="dom-CanvasHitTestRect-y">y</code>"].</p></li> | ||
|
|
||
| <li><p>Let <var>layoutBox</var> be <var>element</var>'s CSS layout box.</p></li> | ||
|
|
||
| <li><p>Let <var>width</var> be <var>rect</var>["<code data-x="dom-CanvasHitTestRect-width">width</code>"] | ||
| if it exists, otherwise the width of <var>layoutBox</var>.</p></li> | ||
|
foolip marked this conversation as resolved.
Outdated
|
||
|
|
||
| <li><p>Let <var>height</var> be <var>rect</var>["<code data-x="dom-CanvasHitTestRect-height">height</code>"] | ||
| if it exists, otherwise the height of <var>layoutBox</var>.</p></li> | ||
| <!-- TODO: what if the layout changes later? --> | ||
|
|
||
| <li><p>Let <var>newRegion</var> be a <span>hit test region</span> whose | ||
| <span data-x="hit-test-region-element">element</span> is <var>element</var>, | ||
| <span data-x="hit-test-region-x">x</span> is <var>x</var>, | ||
| <span data-x="hit-test-region-y">y</span> is <var>y</var>, | ||
| <span data-x="hit-test-region-width">width</span> is <var>width</var>, and | ||
| <span data-x="hit-test-region-height">height</span> is <var>height</var>.</p></li> | ||
|
|
||
| <li><p>Append <var>newRegion</var> to <var>newRegions</var>.</p></li> | ||
| </ol> | ||
| </li> | ||
|
|
||
| <li><p>Set <var>canvas</var>'s <span>hit test regions</span> to <var>newRegions</var>.</p></li> | ||
| </ol> | ||
|
|
||
| <p>When performing hit testing for a <code>canvas</code> element <var>canvas</var> and coordinates | ||
| (<var>x</var>, <var>y</var>), run these steps:</p> | ||
|
|
||
| <ol> | ||
| <li> | ||
| <p>For each <span>hit test region</span> <var>region</var> in <var>canvas</var>'s <span>hit test regions</span>:</p> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely an edge case, and I suppose it's a bit of a gray area (see whatwg/infra#396) but how is this supposed to work if // Add multiple regions
ctx.setHitTestRegions([
{ element, rect: { x, y } },
{ element: anotherElement, rect: { x: anotherX, y: anotherY } }
]);
element.onclick = e => ctx.setHitTestRegions([]); // that was a 'once' handlerShould the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This kind of problem is sometimes handled in the spec by making a frozen copy of the thing to iterate before starting iteration. Do you think that'd be OK here?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would certainly be clearer as to what's supposed to happen yes. Now, whether it's the best behavior or not, I don't know and don't have any strong opinion. Both possibilities might come surprising depending on the case. The fact that the timing of hit-testing w.r.t. events propagation isn't well defined doesn't help...
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @szager made a good point here which is that really when we start dispatching events hit testing is already done. So rather than making a copy of the list here, the spec here needs to make clear how the list is used in hit testing and that it all happens before event dispatch. |
||
|
|
||
| <ol> | ||
| <li><p>Let <var>element</var> be <var>region</var>'s <span data-x="hit-test-region-element">element</span>.</p></li> | ||
|
|
||
| <li><p>If <var>element</var>'s <span>parent</span> is not <var>canvas</var>, then <span>continue</span>.</p></li> | ||
|
|
||
| <li><p>If (<var>x</var>, <var>y</var>) is not within the rectangle defined by <var>region</var>'s | ||
| <span data-x="hit-test-region-x">x</span>, <span data-x="hit-test-region-y">y</span>, | ||
|
foolip marked this conversation as resolved.
Outdated
|
||
| <span data-x="hit-test-region-width">width</span>, and | ||
| <span data-x="hit-test-region-height">height</span>, then <span>continue</span>.</p></li> | ||
| <!-- TODO: spell out exact test and boundary conditions --> | ||
|
|
||
| <li><p>Let <var>elementX</var> and <var>elementY</var> be the corresponding coordinates for | ||
| <var>element</var>, translating and scaling the coordinates such that (x, y) is the top left | ||
| corner and (x + width, y + height) is the bottom right corner.</p></li> | ||
| <!-- TODO: spell out exact mapping --> | ||
|
|
||
| <li><p>👋 Act as if (<var>elementX</var>, <var>elementY</var>) of <var>element</var> was hit.</p></li> | ||
|
|
||
| <li><p><span>Break</span>.</p></li> | ||
| </ol> | ||
|
|
||
| <p class="note">Hit testing isn't defined anywhere so there is no spec to modify or monkey patch. | ||
| The intention of the above is that things should behave as if each element was positioned at the | ||
| given region, with all the observable behavior that implies, such as pointer events firing at the | ||
| element and propagating like they would for a regular element.</p> | ||
| </li> | ||
| </ol> | ||
|
|
||
| </div> | ||
|
|
||
|
|
||
| <h6>Drawing images</h6> | ||
|
|
||
| <p>Objects that implement the <code>CanvasDrawImage</code> interface have the <dfn method | ||
|
|
@@ -139063,8 +139304,18 @@ legend[align=right i] { | |
| <p>A <code>canvas</code> element that <span>represents</span> <span>embedded content</span> is | ||
| expected to be treated as a <span>replaced element</span>; the contents of such elements are the | ||
| element's bitmap, if any, or else a <span>transparent black</span> bitmap with the same | ||
| <span>natural dimensions</span> as the element. Other <code>canvas</code> elements are expected | ||
| to be treated as ordinary elements in the rendering model.</p> | ||
| <span>natural dimensions</span> as the element. A <code>canvas</code> element that | ||
| <span>represents</span> <span>embedded content</span> and has a <code | ||
| data-x="attr-canvas-layoutsubtree">layoutsubtree</code> attribute specified is additionally | ||
| expected to be treated as 👋replaced element with subtree layout👋, where children are laid out | ||
| but not rendered. Additionally, children are exposed to assistive technologies (ATs).</p> | ||
|
|
||
| <p class="XXX">This needs to be reconciled with the definition of <span | ||
| data-x="replaced element">replaced elements</span>, which says that the content of replaced | ||
| elements is not considered in the CSS formatting model.</p> | ||
|
|
||
| <p>Other <code>canvas</code> elements are expected to be treated as ordinary elements in the | ||
| rendering model.</p> | ||
|
|
||
| <p>An <code>object</code> element that <span>represents</span> an image, plugin, or its | ||
| <span>content navigable</span> is expected to be treated as a <span>replaced element</span>. | ||
|
|
@@ -139111,6 +139362,7 @@ legend[align=right i] { | |
|
|
||
| <pre><code class="css">@namespace "http://www.w3.org/1999/xhtml"; | ||
|
|
||
| canvas[layoutsubtree] > * { isolation: isolate !important; contain: strict !important; } | ||
| iframe { border: 2px inset; } | ||
| <span id="video-object-fit">video { object-fit: contain; }</span></code></pre> | ||
|
|
||
|
|
@@ -145298,6 +145550,11 @@ interface <dfn interface>External</dfn> { | |
| <code data-x="attr-track-label">track</code> | ||
| <td> User-visible label | ||
| <td> <a href="#attribute-text">Text</a> | ||
| <tr> | ||
| <th> <code data-x="">layoutsubtree</code> | ||
| <td> <code data-x="attr-canvas-layoutsubtree">canvas</code> | ||
| <td> Whether to layout descendants | ||
| <td> <span>Boolean attribute</span> | ||
| <tr> | ||
| <th> <code data-x="">lang</code> | ||
| <td> <span data-x="attr-lang">HTML elements</span> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.