Skip to content

Commit d4a272e

Browse files
committed
[css-paint-api] Move creating classes to "draw a paint image" time.
General large cleanup.
1 parent e0b5957 commit d4a272e

File tree

1 file changed

+152
-77
lines changed

1 file changed

+152
-77
lines changed

css-paint-api/Overview.bs

Lines changed: 152 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -38,39 +38,53 @@ urlPrefix: http://www.ecma-international.org/ecma-262/6.0/#sec-; type: dfn;
3838
Introduction {#intro}
3939
=====================
4040

41-
The paint stage of CSS is responsible for painting the background, content and highlight of an element based on that element's geometry (as generated by the layout stage) and computed style.
41+
The paint stage of CSS is responsible for painting the background, content and highlight of an
42+
box based on that box's geometry (as generated by the layout stage) and computed style.
4243

43-
This specification describes an API which allows developers to paint a part of an element in response to geometry / computed style changes.
44+
This specification describes an API which allows developers to paint a part of an box in
45+
response to geometry / computed style changes with an additional <<image>> function.
4446

45-
Note: In a future version of the spec, support may be added for defining the clip, global alpha, filter on a portion of an element (for example on the background layers).
47+
Note: In a future version of the spec, support may be added for defining the clip, global alpha,
48+
filter on a portion of an box (for example on the background layers).
4649

4750
Paint Invalidation {#paint-invalidation}
4851
========================================
4952

50-
A <a>document</a> has an associated <b>paint name to input properties map</b>. Initially it is empty and is populated when {{registerPaint(name, paintCtor)}} is called.
53+
A <a>document</a> has an associated <dfn>paint name to input properties map</dfn>. Initially it is
54+
empty and is populated when {{registerPaint(name, paintCtor)}} is called.
5155

52-
Each <<paint()>> function for a fragment has an associated <b>paint valid flag</b>. It may be either <dfn>paint-valid</dfn> or <dfn>paint-invalid</dfn>. It is initially set to <a>paint-invalid</a>.
56+
Each <<paint()>> function for a box has an associated <dfn>paint valid flag</dfn>. It may be either
57+
<dfn>paint-valid</dfn> or <dfn>paint-invalid</dfn>. It is initially set to <a>paint-invalid</a>.
5358

54-
When the geometry (as determined by layout) of a <var>fragment</var> changes, each <<paint()>> function's <b>paint valid flag</b> should be set to <a>paint-invalid</a>.
59+
When the geometry (as determined by layout) of a |box| changes, each <<paint()>> function's <a>paint
60+
valid flag</a> should be set to <a>paint-invalid</a>.
5561

56-
When the computed style for an element changes, the user agent must run the following steps:
57-
1. For each <<paint()>> function on the element, perform the following substeps:
58-
1. Let <var>name</var> be the first argument of the <<paint()>> function.
59-
2. Let <var>inputProperties</var> be the result of performing a lookup in <b>paint name to input properties map</b> with |name| as the key.
60-
3. For each <var>property</var> in |inputProperties|, if the |property|'s <a>computed value</a> has changed, set the <b>paint valid flag</b> on the |fragment| to <a>paint-invalid</a>.
62+
When the computed style for an |box| changes, the user agent must run the following steps:
63+
1. For each <<paint()>> function on the |box|, perform the following substeps:
64+
1. Let |paintFunction| be the current <<paint()>> function on the |box|.
6165

62-
[[#drawing-an-image]] results in the <b>paint valid flag</b> for a <<paint()>> function to be set to <a>paint-valid</a>.
66+
2. Let |name| be the first argument of the <<paint()>> function.
6367

64-
Note: In a future version of the spec, support may be added for partial invalidation.
65-
The user agent will be able to specify a region of the rendering context which needs to be re-painted by the paint class.
68+
3. Let |inputProperties| be the result of lookuping up |name| on <a>paint name to input
69+
properties map</a>.
70+
71+
4. For each |property| in |inputProperties|, if the |property|'s <a>computed value</a> has
72+
changed, set the <a>paint valid flag</a> on the |paintFunction| to <a>paint-invalid</a>.
73+
74+
Performing <a>draw a paint image</a> results in the <a>paint valid flag</a> for a <<paint()>>
75+
function on a box to be set to <a>paint-valid</a>.
76+
77+
Note: In a future version of the spec, support may be added for partial invalidation. The user agent
78+
will be able to specify a region of the rendering context which needs to be re-painted by the
79+
paint class.
6680

6781
Paint Worklet {#paint-worklet}
6882
==============================
6983

7084
The {{paintWorklet}} attribute allows access to the {{Worklet}} responsible for all the classes
7185
which are related to painting.
7286

73-
The {{paintWorklet}}'s <b>worklet global scope type</b> is {{PaintWorkletGlobalScope}}.
87+
The {{paintWorklet}}'s <a>worklet global scope type</a> is {{PaintWorkletGlobalScope}}.
7488

7589
<pre class='idl'>
7690
partial interface Window {
@@ -88,11 +102,6 @@ interface PaintWorkletGlobalScope : WorkletGlobalScope {
88102
};
89103
</pre>
90104

91-
Registering Custom Paint {#registering-custom-paint}
92-
====================================================
93-
94-
The {{PaintWorkletGlobalScope}} has a map of <b>name to paint instance map</b>. Initially this map is empty; it is populated when {{registerPaint(name, paintCtor)}} is called.
95-
96105
<div class='note'>
97106
Note: This is how the class should look.
98107
<pre class='idl'>
@@ -103,25 +112,53 @@ The {{PaintWorkletGlobalScope}} has a map of <b>name to paint instance map</b>.
103112
</pre>
104113
</div>
105114

106-
When the <dfn method for=PaintWorkletGlobalScope>registerPaint(<var>name</var>, <var>paintCtor</var>)</dfn> method is called, the user agent <em>must</em> run the following steps:
107-
1. If the |name| is not a valid <<ident>>, <a>throw</a> a <a>NotSupportedError</a> and abort all these steps.
108-
2. If the |name| exists as a key in the <b>name to paint instance map</b>, <a>throw</a> a <a>NotSupportedError</a> and abort all these steps.
109-
3. If the result of <a>IsConstructor</a>(argument=|paintCtor|) is false, <a>throw</a> a <a>NotSupportedError</a> and abort all these steps.
110-
4. Let <var>prototype</var> be the result of <a>Get</a>(O=|paintCtor|, P="prototype").
111-
5. If the result of <a>IsCallable</a>(argument=<a>Get</a>(O=|prototype|, P="paint")) is false, <a>throw</a> a <a>NotSupportedError</a> and abort all these steps.
112-
6. Let <var>inputProperties</var> be the result of <a>Get</a>(O=|paintCtor|, P="inputProperties").
113-
7. If the result of <a>IsArray</a>(argument=|inputProperties|) is false, <a>throw</a> a <a>NotSupportedError</a> and abort all these steps.
114-
8. Add the key-value pair (|name| - |inputProperties|) to the <b>paint name to input properties map</b> of the associated <a>document</a>.
115-
9. Let <var>paintInstance</var> be the result of <a>Construct</a>(|paintCtor|).
116-
10. Add the key-value pair (|name| - |paintInstance|) to the <b>name to paint instance map</b> of the {{PaintWorkletGlobalScope}}.
115+
Registering Custom Paint {#registering-custom-paint}
116+
====================================================
117+
118+
The {{PaintWorkletGlobalScope}} has a <dfn>paint name to constructor map</dfn>. Initially this map
119+
is empty; it is populated when {{registerPaint(name, paintCtor)}} is called.
120+
121+
The {{PaintWorkletGlobalScope}} has a <dfn>paint name to instance map</dfn>. Initially this map is
122+
empty; it is populated when <a>draw a paint image</a> is invoked by the user agent.
123+
124+
Instances of paint classes in the <a>paint name to instance map</a> may be disposed and removed from
125+
the map by the user agent at any time. This may be done when a <<paint()>> function no longer is
126+
used, or the user agent needs to reclaim memory.
127+
128+
When the <dfn method for=PaintWorkletGlobalScope>registerPaint(|name|, |paintCtor|)</dfn> method is
129+
called, the user agent <em>must</em> run the following steps:
130+
1. If the |name| is not a valid <<ident>>, <a>throw</a> a <a>NotSupportedError</a> and abort all
131+
these steps.
132+
133+
2. If the |name| exists as a key in the <a>paint name to constructor map</a>, <a>throw</a> a
134+
<a>NotSupportedError</a> and abort all these steps.
135+
136+
3. If the result of <a>IsConstructor</a>(argument=|paintCtor|) is false, <a>throw</a> a
137+
<a>NotSupportedError</a> and abort all these steps.
138+
139+
4. Let |prototype| be the result of <a>Get</a>(O=|paintCtor|, P="prototype").
140+
141+
5. If the result of <a>IsCallable</a>(argument=<a>Get</a>(O=|prototype|, P="paint")) is false,
142+
<a>throw</a> a <a>NotSupportedError</a> and abort all these steps.
143+
144+
6. Let |inputProperties| be the result of <a>Get</a>(O=|paintCtor|, P="inputProperties").
145+
146+
7. If the result of <a>IsArray</a>(argument=|inputProperties|) is false, <a>throw</a> a
147+
<a>NotSupportedError</a> and abort all these steps.
117148

118-
Note: The list of CSS properties provided by the input properties getter can either be custom or native CSS properties.
149+
8. Add the key-value pair (|name| - |inputProperties|) to the <a>paint name to input properties
150+
map</a> of the associated <a>document</a>.
119151

120-
Note: The list of input properties should only be looked up once, the class doesn't have the opportunity to dynamically change its input properties.
152+
Note: The list of CSS properties provided by the input properties getter can either be custom or
153+
native CSS properties.
121154

122-
Note: In a future version of the spec, the author may be able to set an option to receive a different type of RenderingContext.
123-
In particular the author may want a WebGL rendering context to render 3D effects.
124-
There are complexities in setting up a WebGL rendering context to take the {{Geometry}} and {{StylePropertyMap}} as inputs.
155+
Note: The list of input properties should only be looked up once, the class doesn't have the
156+
opportunity to dynamically change its input properties.
157+
158+
Note: In a future version of the spec, the author may be able to set an option to receive a
159+
different type of RenderingContext. In particular the author may want a WebGL rendering context
160+
to render 3D effects. There are complexities in setting up a WebGL rendering context to take the
161+
{{Geometry}} and {{StylePropertyMap}} as inputs.
125162

126163
Issue(w3c/css-houdini-drafts#31): Allow author to specify the intrinsic size.
127164

@@ -190,6 +227,29 @@ When the user agent is to <dfn>create a PaintRenderingContext2D object</dfn> for
190227
Drawing an image {#drawing-an-image}
191228
====================================
192229

230+
If a <<paint()>> function for a fragment is <a>paint-invalid</a> and the fragment is within the
231+
visual viewport, then user agent <em>must</em> <a>draw a paint image</a> for the current frame. The
232+
user agent <em>may not</em> defer the <a>draw a paint image</a> operation until a subsequent frame.
233+
234+
The <a>draw a paint image</a> function should be invoked by the user agent during the <a>object size
235+
negotiation</a> algorithm which is responsible for rendering an <<image>>.
236+
237+
Note: The user agent may choose to <a>draw a paint image</a> for <<paint()>> functions not within
238+
the visual viewport.
239+
240+
<div class="example">
241+
If an author updates a style inside a <code>requestAnimationFrame</code>, e.g.
242+
<pre class='lang-javascript'>
243+
requestAnimationFrame(function() {
244+
element.styleMap.set('--custom-prop-invalidates-paint', 42);
245+
});
246+
</pre>
247+
And the <code>element</code> is inside the visual viewport, the user agent <em>msut</em> <a>draw
248+
a paint image</a> and display the result on the current frame.
249+
</div>
250+
251+
The {{Geometry}} object represents the geometry of the image that the author should draw.
252+
193253
<pre class='idl'>
194254
[Exposed=Worklet]
195255
interface Geometry {
@@ -198,69 +258,84 @@ interface Geometry {
198258
};
199259
</pre>
200260

201-
If a <<paint()>> function for a fragment is <a>paint-invalid</a> and the fragment is within the visual viewport,
202-
then user agent <em>must</em> <a>draw an image</a> for the current frame.
261+
When the user agent wants to <dfn>draw a paint image</dfn> of a <<paint()>> function for a |box|
262+
into its appropriate stacking level (as defined by the property the CSS property it's associated
263+
with), given it's |concreteObjectSize| (<a>concrete object size</a>) it <em>must</em> run the
264+
following steps:
265+
1. Let |paintFunction| be the current <<paint()>> function on the |box|.
203266

204-
Note: The user agent may choose to <a>draw an image</a> for <<paint()>> functions not within the visual viewport.
267+
2. If the <a>paint valid flag</a> for the |paintFunction| is <a>paint-valid</a> the user agent
268+
<em>may</em> use the drawn image from the previous invocation. If so it <em>may</em> abort
269+
all these steps and use the previously drawn image.
205270

206-
When the user agent wants to <dfn>draw an image</dfn> of a <<paint()>> for a <var>fragment</var> into its appropriate stacking level (as defined by the property the CSS property it's associated with) it <em>must</em> run the following steps:
207-
1. If the <b>paint valid flag</b> for the <<paint()>> function on the |fragment| is <a>paint-valid</a> the user agent <em>may</em> use the drawn image from the previous invocation.
208-
If so it can abort all these steps.
271+
Note: The user agent for implementation reasons may also continue with all these steps in
272+
this case. It can do this every frame, or multiple times per frame.
209273

210-
Note: The user agent for implementation reasons may also continue with all these steps in this case. It can do this every frame, or multiple times per frame.
274+
3. Let |name| be the first argument of the |paintFunction|.
211275

212-
2. Let <var>name</var> be the first argument of the <<paint()>> function.
276+
4. Let |workletGlobalScope| be a {{PaintWorkletGlobalScope}} from the list of <a>worklet's
277+
WorkletGlobalScopes</a> from the paint {{Worklet}}.
213278

214-
3. If no paint class was registered with |name|, the resulting image output will be an <a>invalid image</a> and the user agent must abort all these steps.
279+
The user agent <em>may</em> also <a>create a WorkletGlobalScope</a> given the paint
280+
{{Worklet}} and use that.
215281

216-
4. Let <var>inputProperties</var> be the result of looking up |name| on the associated <a>document</a>'s <b>paint name to input properties map</b>.
282+
Note: The user agent <em>may</em> use any policy for which {{PaintWorkletGlobalScope}} to
283+
select or create. It may use a single {{PaintWorkletGlobalScope}} or multiple and
284+
randomly assign between them.
217285

218-
5. Let <var>styleMap</var> be a new {{StylePropertyMap}} populated with <em>only</em> the <a>computed value</a>'s for properties listed in |inputProperties|.
286+
5. If no paint constructor exists on |workletGlobalScope|'s <a>paint name to constructor map</a>
287+
with key |name|, the resulting image output will be an <a>invalid image</a> and the user
288+
agent must abort all these steps.
219289

220-
6. Let <var>renderingContext</var> be the result of <a>create a PaintRenderingContext2D object</a> given:
221-
- "width" - The width of the |fragment|.
222-
- "height" - The height of the |fragment|.
290+
6. Let |paintInstance| be the result of looking up |name| on |workletGlobalScope|'s <a>paint
291+
name to instance map</a>. If |paintInstance| is null run the following substeps:
292+
1. Let |paintCtor| be the result of looking up |name| on <a>paint name to constructor
293+
map</a>.
223294

224-
Note: The |renderingContext| must not be re-used between invocations of paint. Implicitly this means that there is no stored data, or state on the |renderingContext| between invocations.
225-
For example you can't setup a clip on the context, and expect the same clip to be applied next time the paint method is called.
295+
2. Let |paintInstance| be the result of <a>Construct</a>(|paintCtor|).
226296

227-
7. Let <var>geometry</var> be a new {{Geometry}} initialized to the width and height of the |fragment|.
297+
3. Add the key-value pair (|name| - |paintInstance|) to the <a>paint name to instance
298+
map</a> of the |workletGlobalScope|.
228299

229-
8. Let |workletGlobalScope| be a {{PaintWorkletGlobalScope}} from the list of <b>worklet's
230-
WorkletGlobalScopes</b> from the paint {{Worklet}}.
300+
7. Let |inputProperties| be the result of looking up |name| on the associated <a>document</a>'s
301+
<a>paint name to input properties map</a>.
231302

232-
The user agent <em>may</em> also <a>create a WorkletGlobalScope</a> given the paint
233-
{{Worklet}} and use that.
303+
8. Let |styleMap| be a new {{StylePropertyMap}} populated with <em>only</em> the <a>computed
304+
value</a>'s for properties listed in |inputProperties|.
234305

235-
Note: The user agent <em>may</em> use any policy for which {{PaintWorkletGlobalScope}} to
236-
select or create.
237-
238-
9. Let |classInstance| be the result of performing a lookup in <b>name to paint instance map</b>
239-
with |name| as the key.
306+
9. Let |renderingContext| be the result of <a>create a PaintRenderingContext2D object</a> given:
307+
- "width" - The width given by |concreteObjectSize|.
308+
- "height" - The height given by |concreteObjectSize|.
240309

241-
10. Perform <a>Invoke</a>(O=|classInstance|, P="paint", Arguments=[|renderingContext|,
242-
|geometry|, |styleMap|).
310+
Note: The |renderingContext| must not be re-used between invocations of paint. Implicitly
311+
this means that there is no stored data, or state on the |renderingContext| between
312+
invocations. For example you can't setup a clip on the context, and expect the same clip
313+
to be applied next time the paint method is called.
243314

244-
11. The image output should be produced from the |renderingContext| given to the method.
315+
Note: Implicitly this also means that |renderingContext| is effectively "neutered" after a
316+
paint method is complete. The author code may hold a reference to |renderingContext| and
317+
invoke methods on it, but this will have no effect on the current image, or subsequent
318+
images.
245319

246-
If an exception is <a>thrown</a> the resulting image output will be an <a>invalid image</a>.
320+
10. Let |geometry| be a new {{Geometry}} initialized to the width and height defined by
321+
|concreteObjectSize|.
247322

248-
12. Set the <b>paint valid flag</b> for the <<paint()>> function on the |fragment| to <a>paint-valid</a>.
323+
11. Perform <a>Invoke</a>(O=|paintInstance|, P="paint", Arguments=[|renderingContext|,
324+
|geometry|, |styleMap|).
249325

250-
Note: The user agent should consider long running paint functions similar to long running script in the main execution context.
251-
For example, they should show a "unresponsive script" dialog or similar.
252-
In addition user agents should provide tooling within their debugging tools to show authors how expensive their paint classes are.
326+
12. The image output is to be produced from the |renderingContext| given to the method.
253327

254-
Note: The contents of the image are not designed to be accessible. Authors should communicate any useful information through the standard accessibility APIs.
328+
If an exception is <a>thrown</a> the resulting image output will be an <a>invalid image</a>.
255329

256-
Issue(w3c/css-houdini-drafts#24): Determine how to side-load images or other data.
330+
13. Set the <a>paint valid flag</a> for the |paintFunction| to <a>paint-valid</a>.
257331

258-
Issue: What information should we provide for read-modify-write use-cases?
259-
Are read-modify-write use-cases important for v1?
260-
For example, if you are sliding the previous paint output out?
261-
For providing the previous paint output we should provide an ImageBitmap if you ask.
332+
Note: The user agent <em>should</em> consider long running paint functions similar to long running
333+
script in the main execution context. For example, they <em>should</em> show a "unresponsive
334+
script" dialog or similar. In addition user agents <em>should</em> provide tooling within their
335+
debugging tools to show authors how expensive their paint classes are.
262336

263-
Issue: Describe what happens if a callback doesn't hit a frame timing boundary. I.e. just renders a transparent image instead?
337+
Note: The contents of the resulting image are not designed to be accessible. Authors <em>should</em>
338+
communicate any useful information through the standard accessibility APIs.
264339

265340
Examples {#examples}
266341
====================

0 commit comments

Comments
 (0)