← All reports

[HTML-in-Canvas] Drawing the canvas by setting the content of the layer

Component: WebCore Canvas | 1b9d7b2

Source/WebKit/GPUProcess/graphics/RemoteImageBuffer.messages.in

+ PrepareForDisplay() -> (std::optional<WebKit::ImageBufferBackendHandle> backendHandle)

Source/WebCore/platform/graphics/ImageBufferBackend.h

+ virtual RefPtr<GraphicsLayerContentsDisplayDelegate> layerContentsDisplayDelegate();
+ virtual void releaseLayerContentsDisplayDelegate();
- virtual RefPtr<GraphicsLayerContentsDisplayDelegate> layerContentsDisplayDelegate() const;

Source/WebCore/rendering/RenderLayerBacking.cpp

(WebCore::RenderLayerBacking::containsPaintedContent const)
(WebCore::RenderLayerBacking::destroyGraphicsLayers)

A canvas either paints into its layer's backing store or, when accelerated, hands the compositor a contents layer backed by a display delegate (an IOSurface on Cocoa, a Skia-backed surface on GTK/WPE) so no repaint is needed. In GPU-process mode the ImageBuffer lives in the GPU process and WebContent holds a RemoteImageBufferProxy, so the displayable surface must be fetched over IPC. HTML-in-Canvas renders "drawable" child DOM elements into the canvas, which requires contents to change after layout and paint.

Drawable 2D canvases with accelerated backends now present through a contents layer (CanvasAsLayerContents) instead of painting into their GraphicsLayer (CanvasPaintedToLayer). ImageBufferBackend gains a non-const layerContentsDisplayDelegate() and releaseLayerContentsDisplayDelegate(), and a new RemoteImageBuffer::PrepareForDisplay message returns the display surface to WebContent.

WebContent                               GPU Process
RemoteImageBufferProxy
  ├── PrepareForDisplay ───────────────► RemoteImageBuffer
  │                                        └─► backend.prepareForDisplay()
  │◄── display surface ────────────────────┘
  └─► layerContentsDisplayDelegate() ─► contents layer (CanvasAsLayerContents)
disconnect() / releaseLayerContentsDisplayDelegate() ─► drop delegate

Canvas pixels can now update after the Paint step, a prerequisite for firing the HTML-in-Canvas paint event after Paint. The change adds a WebContent-to-GPU-process PrepareForDisplay message that returns a display surface handle.

A compromised WebContent can send PrepareForDisplay at arbitrary times: check behavior when the remote image buffer is already released, when the backend is non-accelerated, and when the message repeats. The display delegate is now shared across WebContent, GPU process and compositor with new release/disconnect paths, so look at a canvas toggling between drawable and non-drawable (swapping painted and contents-layer modes and calling clearContentsFromLayer) and at GPU-process crash recovery for stale delegate or surface use-after-release.