6 #include <Metal/Metal.h>
8 #include "flutter/common/settings.h"
9 #include "flutter/common/task_runners.h"
10 #include "flutter/flow/layers/layer_tree.h"
11 #include "flutter/fml/platform/darwin/cf_utils.h"
12 #include "flutter/fml/synchronization/waitable_event.h"
13 #include "flutter/fml/trace_event.h"
14 #include "flutter/shell/common/platform_view.h"
15 #include "flutter/shell/common/rasterizer.h"
18 #include "third_party/skia/include/utils/mac/SkCGUtils.h"
21 id<FlutterViewEngineDelegate> _delegate;
25 - (instancetype)init {
26 NSAssert(NO,
@"FlutterView must initWithDelegate");
31 NSAssert(NO,
@"FlutterView must initWithDelegate");
36 NSAssert(NO,
@"FlutterView must initWithDelegate");
41 if (@available(iOS 13.0, *)) {
42 return self.window.windowScene.screen;
44 return UIScreen.mainScreen;
47 - (MTLPixelFormat)pixelFormat {
48 if ([
self.layer isKindOfClass:NSClassFromString(
@"CAMetalLayer")]) {
51 #pragma clang diagnostic push
52 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
53 CAMetalLayer* layer = (CAMetalLayer*)
self.layer;
54 return layer.pixelFormat;
56 return MTLPixelFormatBGRA8Unorm;
58 - (BOOL)isWideGamutSupported {
59 if (![_delegate isUsingImpeller]) {
63 FML_DCHECK(
self.screen);
68 return self.screen.traitCollection.displayGamut != UIDisplayGamutSRGB;
73 enableWideGamut:(BOOL)isWideGamutEnabled {
74 if (delegate == nil) {
75 NSLog(
@"FlutterView delegate was nil.");
80 self = [
super initWithFrame:CGRectNull];
85 self.layer.opaque = opaque;
91 self.backgroundColor = UIColor.clearColor;
97 static void PrintWideGamutWarningOnce() {
98 static BOOL did_print = NO;
102 FML_DLOG(WARNING) <<
"Rendering wide gamut colors is turned on but isn't "
103 "supported, downgrading the color gamut to sRGB.";
107 - (void)layoutSubviews {
108 if ([
self.layer isKindOfClass:NSClassFromString(
@"CAMetalLayer")]) {
111 #pragma clang diagnostic push
112 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
113 CAMetalLayer* layer = (CAMetalLayer*)
self.layer;
114 #pragma clang diagnostic pop
115 CGFloat screenScale =
self.screen.scale;
116 layer.allowsGroupOpacity = YES;
117 layer.contentsScale = screenScale;
118 layer.rasterizationScale = screenScale;
119 layer.framebufferOnly = flutter::Settings::kSurfaceDataAccessible ? NO : YES;
120 BOOL isWideGamutSupported =
self.isWideGamutSupported;
122 CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB);
123 layer.colorspace = srgb;
129 layer.pixelFormat = MTLPixelFormatRGBA16Float;
131 PrintWideGamutWarningOnce();
135 [
super layoutSubviews];
140 + (BOOL)forceSoftwareRendering {
144 + (void)setForceSoftwareRendering:(BOOL)forceSoftwareRendering {
148 + (Class)layerClass {
153 - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {
154 TRACE_EVENT0(
"flutter",
"SnapshotFlutterView");
156 if (layer !=
self.layer || context ==
nullptr) {
160 auto screenshot = [_delegate takeScreenshot:flutter::Rasterizer::ScreenshotType::UncompressedImage
163 if (!screenshot.data || screenshot.data->isEmpty() || screenshot.frame_size.isEmpty()) {
167 NSData* data = [NSData dataWithBytes:const_cast<void*>(screenshot.data->data())
168 length:screenshot.data->size()];
170 fml::CFRef<CGDataProviderRef> image_data_provider(
171 CGDataProviderCreateWithCFData(
reinterpret_cast<CFDataRef
>(data)));
173 fml::CFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
176 size_t bits_per_component = 8u;
177 size_t bits_per_pixel = 32u;
178 size_t bytes_per_row_multiplier = 4u;
179 CGBitmapInfo bitmap_info =
180 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedLast) |
181 static_cast<uint32_t
>(kCGBitmapByteOrder32Big));
183 switch (screenshot.pixel_format) {
184 case flutter::Rasterizer::ScreenshotFormat::kUnknown:
185 case flutter::Rasterizer::ScreenshotFormat::kR8G8B8A8UNormInt:
188 case flutter::Rasterizer::ScreenshotFormat::kB8G8R8A8UNormInt:
191 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedFirst) |
192 static_cast<uint32_t
>(kCGBitmapByteOrder32Little));
194 case flutter::Rasterizer::ScreenshotFormat::kR16G16B16A16Float:
195 bits_per_component = 16u;
196 bits_per_pixel = 64u;
197 bytes_per_row_multiplier = 8u;
199 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedLast) |
200 static_cast<uint32_t
>(kCGBitmapFloatComponents) |
201 static_cast<uint32_t
>(kCGBitmapByteOrder16Little));
205 fml::CFRef<CGImageRef> image(CGImageCreate(
206 screenshot.frame_size.width(),
207 screenshot.frame_size.height(),
210 bytes_per_row_multiplier * screenshot.frame_size.width(),
216 kCGRenderingIntentDefault
219 const CGRect frame_rect =
220 CGRectMake(0.0, 0.0, screenshot.frame_size.width(), screenshot.frame_size.height());
221 CGContextSaveGState(context);
223 CGFloat height = CGBitmapContextGetHeight(context);
225 height = CGFloat(screenshot.frame_size.height());
227 CGContextTranslateCTM(context, 0.0, height);
228 CGContextScaleCTM(context, 1.0, -1.0);
229 CGContextDrawImage(context, frame_rect, image);
230 CGContextRestoreGState(context);
233 - (BOOL)isAccessibilityElement {
242 [_delegate flutterViewAccessibilityDidCall];