WebGL: Copy context to NativeImage in straight orientation
Component: WebCore graphics | fbe51f1
Source/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp
Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h
NativeImage is WebCore's cross-context pixel handle — CGImage or IOSurface-backed — used whenever rendered content moves between canvas types or into the compositor. GraphicsContextGL performs actual GL rendering out-of-process in the GPU process; the Web process calls into it through RemoteGraphicsContextGLProxy, which forwards requests over IPC to RemoteGraphicsContextGL, with the resulting NativeImage returned back.
This replaces copyNativeImageYFlipped with copyNativeImage, moving the vertical flip into the copy step instead of drawing flipped content into an extra ImageBuffer. The Cocoa path flips via BlitFramebuffer into an IOSurface-backed CVPixelBuffer; the cross-platform ANGLE path flips in place with the new flipPixelBufferRows() helper on the read-back PixelBuffer before calling createNativeImageFromPixelBuffer(). New CoreGraphics image-provider SPI lets the Cocoa path's NativeImage wrap an IOSurface directly and hand it to CoreAnimation. NativeImage::create() and the GPU-process IPC messages are reworked accordingly, and the now-unneeded drawing-buffer copy-on-write machinery (prepareForDrawingBufferWrite/IfBound, IOSurfaceDrawingBuffer.cpp) is removed.
Before:
WebGL draw ──► CGIOSurfaceContext (flipped) ──► CGImage wraps it (y-flipped NativeImage)
──► drawn flipped into extra ImageBuffer ──► copied out
(copy-on-write triggered on next WebGL draw/context discard)
After (Cocoa, GraphicsContextGLCocoa::copyNativeImage):
WebGL draw ──► BlitFramebuffer flip into IOSurface-backed CVPixelBuffer
──► NativeImage::create(CVPixelBufferRef) ──► CGImageProviderCreate wraps IOSurface
──► handed to CA directly
After (generic ANGLE, GraphicsContextGLANGLE::copyNativeImage):
WebGL draw ──► readCompositedResults() into PixelBuffer ──► flipPixelBufferRows() (in-place CPU row swap)
──► createNativeImageFromPixelBuffer()
Significance
Eliminates a redundant copy/draw pass on every WebGL-to-NativeImage transfer and is explicit groundwork for zero-copy pixel sharing between 2D, WebGL, WebGPU, and bitmaprenderer contexts. The new SPI lands in AllowedSPI.toml under [[temporary-usage]], meaning WebKit's use of it is tracked for cleanup under a separate rdar rather than being a permanent dependency.
Audit directions
The forward-facing pattern is attacker-controlled dimensions flowing into a callback-driven image provider whose expected buffer size is established at creation time and never re-derived at use. Narrow: CGImageProviderCreate here wraps IOSurfaces behind callback structs (copyImageBlockSet, copyIOSurface, releaseInfo) with WebGL canvas dimensions and format flowing into info — check whether attacker-controlled canvas size or premultiplied-alpha flags can desync the buffer size CG expects from what is actually allocated, and whether the size math in flipPixelBufferRows and NativeImageCG.cpp's copyIOSurface agrees with it. Wider: the same shape appears at every other WebCore site that hands a provider or callback struct a size negotiated separately from the allocation — CGDataProviderCreateWithData users, CVPixelBuffer wrapping in the media pipeline, and WebGPU texture import; the tell is a size passed to a creation call and a separate size used inside the callback body. Widest: lifetime and release-callback correctness for the IOSurface/CVPixelBuffer objects crossing the Web-process→GPU-process boundary here is the same class as any refcounted handle whose release runs on a callback the other side controls the timing of — audit the analogous RemoteGraphicsContextGLProxy reply paths and other Remote*Proxy methods returning platform handles for release-ordering assumptions.