Properties of Custom Paint
We wanted to capture a solid notion of the required and desirable properties of a Custom Paint API, so we can agree on goals before descending into API or implementation details.
So here’s our list :) Anything we should change, remove, or add?
Required Properties of Custom Paint
Custom Paint code happens explicitly after layout
We want custom paint to be able to respond to layout changes, otherwise it's not really much different to a canvas.
Custom Paint code can’t cause another style-layout-paint to occur before pixels on screen.
We don’t want custom paint code to be able to invalidate style/layout/paint within the same frame. We’ve seen this on the main thread code with style/layout, and this is a bad thing™. A bad actor can force every frame to do twice the amount of work required, it leads to unbounded amounts of work.
Custom Paint code is invalidated, not drawn on every frame (if it doesn’t need it).
We want to end up in a situation where we can intelligently not invoke a callback because it is not needed this frame. For example if the layout & style of an element hasn’t changed, we explicitly want to not call the callback, and just use a cached value.
Paint regions are invalidated by style.
We need a system that interoperates well with the built-ins and that explains CSS. That makes it so that web authors don’t need to understand two different systems. Part of this is that style invalidations should trigger an invalidation of paint on an element. It shouldn’t skip the style/layout invalidation system.
Custom paint augments existing elements in the DOM.
We don’t want web authors to rebuild the world in canvas if they don’t want to. If they just want to make their button have a new type of custom border, background, box-shadow, etc, etc, etc, they should be able to modify the paint on an existing element.
We don’t want Web Developers to increase DOM count/complexity, or muck around with layouts to achieve these effects.
The Web Developer should know how their paint code should behave. There shouldn’t be hidden magic.
Geometry Data passed in is correct and valuable.
Geom data passed in shouldn’t change underneath the system. Have geometry data of children available as well (may be useful for grid effects, etc).
Custom Paint functions can be shared across multiple elements.
We'd don't want a canvas to be shared across multiple elements. This means that it won't be able to properly respond to geometry sizes of the element it is "augmenting"; it'll have to stretch, crop, etc. Instead we'd like to share a Custom Paint function instead, which can properly respond to geometry changes, and be invoked multiple times.
Nice to have properties of Custom Paint
Fast RenderingContext (no foot-guns).
We shouldn’t have to maintain a full backing store for each canvas by default, should be disabled. This can be achieved by flipping the ‘tainted’ bit on a rendering context. This disallows pixel data readback.
Not explicitly tied to a particular thread / number of threads in the browser.
We’d like custom paint to not have thread affinity.
Consistent with other Houdini APIs, e.g. Custom Box Layout, Line Layout, Custom Style Resolution.
We’d like for all the APIs within this group be sane and consistent with each other.
Can define “overflow” on an element to achieve things like box-shadow.
As described. :)
Properties of Custom Paint that are up for debate
Able to optionally access written pixels
Should it be possible to flip a custom paint handler into a mode where pixels written by the JS function are able to be read back? Given ‘fast by default’, this wouldn’t normally be on.
Able to mark handlers as optional
There are some concerns about custom paint handlers causing performance issues. Should developers be able to mark custom painters as optional, so that when under load the browser can decide not to run them?