Skip to content

Commit adb0798

Browse files
committed
Convert HDR video frames to SDR when drawing to canvas
https://bugs.webkit.org/show_bug.cgi?id=240972 rdar://98692644 Reviewed by Jer Noble. Core Animation has a bug with accelerated rendering where drawing an image with HDR color space metadata does not correctly tone map the image. To work around this, we perform our own color space conversion of the image to the destination color space in this case. By using CGIOSurfaceContextGetSurface, we limit this workaround to CGContexts that are backed by an IOSurface (and so use accelerated drawing). Doing this color space conversion inside GraphicsContextCG::drawNativeImage means that we'll do it each time the image is drawn. Ideally this would only be done once for a given { CGImage, DestinationColorSpace } pair. * LayoutTests/fast/canvas/canvas-drawImage-hdr-video-expected.txt: Added. * LayoutTests/fast/canvas/canvas-drawImage-hdr-video.html: Added. * LayoutTests/fast/canvas/resources/hdr.mp4: Added. * LayoutTests/platform/gtk/fast/canvas/canvas-drawImage-hdr-video-expected.txt: Added. * Source/WTF/wtf/PlatformHave.h: * Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h: * Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp: (WebCore::GraphicsContextCG::drawNativeImage): * Source/WebCore/platform/graphics/cg/GraphicsContextCG.h: * Source/WebCore/platform/graphics/cocoa/GraphicsContextCocoa.mm: (WebCore::GraphicsContextCG::convertToDestinationColorSpaceIfNeeded): * Source/WebCore/platform/graphics/cocoa/IOSurface.h: * Source/WebCore/platform/graphics/cocoa/IOSurface.mm: (WebCore::IOSurface::bitmapConfiguration const): (WebCore::IOSurface::createCompatibleBitmap): (WebCore::IOSurface::ensurePlatformContext): * Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp: (WebCore::GraphicsContextCG::convertToDestinationColorSpaceIfNeeded): Canonical link: https://commits.webkit.org/254973@main
1 parent 2daf672 commit adb0798

File tree

13 files changed

+109
-9
lines changed

13 files changed

+109
-9
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Pixel at 1920,540: 0,174,0,255
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!DOCTYPE html>
2+
<script src="../../resources/js-test-pre.js"></script>
3+
<script src="../../media/utilities.js"></script>
4+
<pre id=log></pre>
5+
<script>
6+
if (window.testRunner) {
7+
testRunner.dumpAsText();
8+
testRunner.waitUntilDone();
9+
}
10+
11+
let video = document.createElement("video");
12+
13+
waitForVideoFrame(video, async function() {
14+
let canvas = document.createElement("canvas");
15+
canvas.width = 3840;
16+
canvas.height = 2160;
17+
18+
let ctx = canvas.getContext("2d");
19+
ctx.drawImage(video, 0, 0);
20+
21+
let x = 1920;
22+
let y = 540;
23+
24+
let data = ctx.getImageData(x, y, 1, 1).data;
25+
log.textContent = `Pixel at ${x},${y}: ${[...data]}`;
26+
27+
if (window.testRunner)
28+
testRunner.notifyDone();
29+
});
30+
31+
video.src = "resources/hdr.mp4";
32+
</script>
56.9 KB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Pixel at 1920,540: 16,223,6,255

LayoutTests/platform/win/TestExpectations

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,6 +3669,7 @@ editing/selection/character-granularity-rect.html [ Skip ]
36693669
editing/selection/ios [ Skip ]
36703670
fast/canvas/canvas-createPattern-video-loading.html [ Skip ]
36713671
fast/canvas/canvas-createPattern-video-modify.html [ Skip ]
3672+
fast/canvas/canvas-drawImage-hdr-video.html [ Skip ]
36723673
fast/events/before-input-prevent-insert-replacement.html [ Skip ]
36733674
fast/events/input-event-insert-replacement.html [ Skip ]
36743675
fast/forms/scroll-into-view-and-show-validation-message.html [ Skip ]

Source/WTF/wtf/PlatformHave.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@
728728
#define HAVE_WEBP 1
729729
#define HAVE_IMAGEIO_FIX_FOR_RADAR_59589723 1
730730
#define HAVE_CGS_FIX_FOR_RADAR_97530095 0
731+
#define HAVE_CORE_ANIMATION_FIX_FOR_RADAR_93560567 0
731732
#endif
732733

733734
#if PLATFORM(COCOA)

Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ CGImageRef CGIOSurfaceContextCreateImage(CGContextRef);
307307
CGImageRef CGIOSurfaceContextCreateImageReference(CGContextRef);
308308
CGColorSpaceRef CGIOSurfaceContextGetColorSpace(CGContextRef);
309309
void CGIOSurfaceContextSetDisplayMask(CGContextRef, uint32_t mask);
310+
IOSurfaceRef CGIOSurfaceContextGetSurface(CGContextRef);
310311
#endif // HAVE(IOSURFACE)
311312

312313
#if PLATFORM(COCOA)

Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ void GraphicsContextCG::drawNativeImage(NativeImage& nativeImage, const FloatSiz
285285
CGContextStateSaver stateSaver(context, false);
286286
auto transform = CGContextGetCTM(context);
287287

288+
convertToDestinationColorSpaceIfNeeded(image);
289+
288290
auto subImage = image;
289291
auto currentImageSize = imageLogicalSize(image.get(), options);
290292

Source/WebCore/platform/graphics/cg/GraphicsContextCG.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ class WEBCORE_EXPORT GraphicsContextCG : public GraphicsContext {
136136
#endif
137137

138138
private:
139+
void convertToDestinationColorSpaceIfNeeded(RetainPtr<CGImageRef>&);
140+
139141
GraphicsContextPlatformPrivate* m_data { nullptr };
140142
};
141143

Source/WebCore/platform/graphics/cocoa/GraphicsContextCocoa.mm

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#import "DisplayListRecorder.h"
3030
#import "GraphicsContextCG.h"
3131
#import "GraphicsContextPlatformPrivateCG.h"
32+
#import "IOSurface.h"
3233
#import "IntRect.h"
3334
#import <pal/spi/cg/CoreGraphicsSPI.h>
3435
#import <pal/spi/cocoa/FeatureFlagsSPI.h>
@@ -224,4 +225,34 @@ static inline void setPatternPhaseInUserSpace(CGContextRef context, CGPoint phas
224225
CGContextFillPath(platformContext);
225226
}
226227

228+
void GraphicsContextCG::convertToDestinationColorSpaceIfNeeded(RetainPtr<CGImageRef>& image)
229+
{
230+
#if HAVE(CORE_ANIMATION_FIX_FOR_RADAR_93560567)
231+
UNUSED_PARAM(image);
232+
#else
233+
if (!CGColorSpaceUsesITUR_2100TF(CGImageGetColorSpace(image.get())))
234+
return;
235+
236+
auto context = platformContext();
237+
238+
auto destinationSurface = CGIOSurfaceContextGetSurface(context);
239+
if (!destinationSurface)
240+
return;
241+
242+
auto destinationColorSpace = CGIOSurfaceContextGetColorSpace(context);
243+
if (!destinationColorSpace)
244+
return;
245+
246+
auto surface = IOSurface::createFromSurface(destinationSurface, DestinationColorSpace(destinationColorSpace));
247+
248+
auto width = CGImageGetWidth(image.get());
249+
auto height = CGImageGetHeight(image.get());
250+
251+
auto bitmapContext = surface->createCompatibleBitmap(width, height);
252+
CGContextDrawImage(bitmapContext.get(), CGRectMake(0, 0, width, height), image.get());
253+
254+
image = adoptCF(CGBitmapContextCreateImage(bitmapContext.get()));
255+
#endif
256+
}
257+
227258
} // namespace WebCore

0 commit comments

Comments
 (0)