-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Conversation
Handwavy things that need fleshing out are marked with 👋
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad to see this being worked on, thanks.
Not quite sure how much discussion should be held at this stage. So to note, this doesn't seem to fully match the latest state of https://github.com/WICG/html-in-canvas. e.g. the rename to drawHTMLElement
. The layoutsubtree
attribute is also missing along with the implications to the existing fallback contents.
Still, thanks for making this move.
source
Outdated
|
||
<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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why limit what can be painted rather than simply tainting the canvas? I guess many use cases won't need any readback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/WICG/html-in-canvas does have a tainting mode, but we've been discussing whether we should keep it. The issue is that we can't do the same for WebGL and WebGPU, because the pixels can always be exfiltrated using shaders.
@Kaiido thank you for the review! I've fleshed things out more, renaming to There's still some handwaving going on of course, in particular what causes the subtree to be laid out but not painted. |
source
Outdated
<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.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should also say that each child is laid out as if it's the only child.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should also put contain: layout
in the UA style sheet, in that case maybe don't need isolation: isolate
.
I've fleshed this out some more now, in particular the hit testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One common complain with the use of dictionaries in the Canvas2D API is that this makes GC kick in very often during animations which has a non-negligible performance cost.
This API shape makes a big use of such dictionaries with one for the wrapper CanvasElementHitTestRegion and then a nested one for the CanvasHitTestRect, and I guess there will be scenarios where multiple of these will need to be updated at every frame. Since the values are copied over from the passed objects to new internal objects, it's unclear if even a careful author, who would try to reuse the same objects, could avoid GC at all here.
On the other hand, I really like how this API shape enables future additions like using a Path2D
, or even a bitmap mask, instead of a CanvasHitTestRect. (btw can we bikeshed on rect
for that purpose?)
It's not my area of expertise, but would an actual exposed interface allow for non copy from JS, so that authors can just update the regions instead of setting new ones?
|
||
<ol> | ||
<li> | ||
<p>For each <span>hit test region</span> <var>region</var> in <var>canvas</var>'s <span>hit test regions</span>:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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 setHitTestRegions
is called during this iteration? E.g.
// 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' handler
Should the anotherElement
still perform the hit-test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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.
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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"CSS layout box" should be linked to something, probably "border box rect" from some CSS spec
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it https://drafts.csswg.org/css-display/#box? (true question)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@progers I think you suggested that "border box rect" is the right term, WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of https://drafts.csswg.org/css-box-4/#valdef-box-border-box which seems to map back to https://drafts.csswg.org/css-display/#box, so I think box would work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go with https://drafts.csswg.org/css-box-4/#border-box, box seems to be a more generic term.
Handwavy things that need fleshing out are marked with 👋
(See WHATWG Working Mode: Changes for more details.)
/canvas.html ( diff )
/index.html ( diff )
/indices.html ( diff )
/rendering.html ( diff )