7 #include "flutter/fml/platform/darwin/cf_utils.h"
15 @property(nonatomic, weak) id<FlutterViewEngineDelegate> delegate;
16 @property(nonatomic, weak) UIWindowScene* previousScene;
20 BOOL _isWideGamutEnabled;
23 - (instancetype)init {
24 NSAssert(NO,
@"FlutterView must initWithDelegate");
29 NSAssert(NO,
@"FlutterView must initWithDelegate");
34 NSAssert(NO,
@"FlutterView must initWithDelegate");
39 return self.window.windowScene.screen;
42 - (MTLPixelFormat)pixelFormat {
43 if ([
self.layer isKindOfClass:[CAMetalLayer
class]]) {
46 #pragma clang diagnostic push
47 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
48 CAMetalLayer* layer = (CAMetalLayer*)
self.layer;
49 return layer.pixelFormat;
51 return MTLPixelFormatBGRA8Unorm;
53 - (BOOL)isWideGamutSupported {
54 FML_DCHECK(
self.screen);
65 return self.screen.traitCollection.displayGamut != UIDisplayGamutSRGB;
70 enableWideGamut:(BOOL)isWideGamutEnabled {
71 if (delegate == nil) {
72 NSLog(
@"FlutterView delegate was nil.");
76 self = [
super initWithFrame:CGRectNull];
80 _isWideGamutEnabled = isWideGamutEnabled;
81 self.layer.opaque = opaque;
87 static void PrintWideGamutWarningOnce() {
88 static BOOL did_print = NO;
92 FML_DLOG(WARNING) <<
"Rendering wide gamut colors is turned on but isn't "
93 "supported, downgrading the color gamut to sRGB.";
97 - (void)layoutSubviews {
98 if ([
self.layer isKindOfClass:[CAMetalLayer
class]]) {
101 #pragma clang diagnostic push
102 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
103 CAMetalLayer* layer = (CAMetalLayer*)
self.layer;
104 #pragma clang diagnostic pop
105 CGFloat screenScale =
self.screen.scale;
106 layer.allowsGroupOpacity = YES;
107 layer.contentsScale = screenScale;
108 layer.rasterizationScale = screenScale;
109 layer.framebufferOnly = flutter::Settings::kSurfaceDataAccessible ? NO : YES;
110 if (_isWideGamutEnabled &&
self.isWideGamutSupported) {
111 fml::CFRef<CGColorSpaceRef> srgb(CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB));
112 layer.colorspace = srgb;
113 layer.pixelFormat = MTLPixelFormatBGRA10_XR;
114 }
else if (_isWideGamutEnabled && !
self.isWideGamutSupported) {
115 PrintWideGamutWarningOnce();
119 [
super layoutSubviews];
122 + (Class)layerClass {
127 - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {
128 TRACE_EVENT0(
"flutter",
"SnapshotFlutterView");
130 if (layer !=
self.layer || context ==
nullptr) {
134 auto screenshot = [_delegate takeScreenshot:flutter::Rasterizer::ScreenshotType::UncompressedImage
137 if (!screenshot.data || screenshot.data->isEmpty() || screenshot.frame_size.IsEmpty()) {
141 NSData* data = [NSData dataWithBytes:const_cast<void*>(screenshot.data->data())
142 length:screenshot.data->size()];
144 fml::CFRef<CGDataProviderRef> image_data_provider(
145 CGDataProviderCreateWithCFData(
reinterpret_cast<CFDataRef
>(data)));
147 fml::CFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
150 size_t bits_per_component = 8u;
151 size_t bits_per_pixel = 32u;
152 size_t bytes_per_row_multiplier = 4u;
153 CGBitmapInfo bitmap_info =
154 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedLast) |
155 static_cast<uint32_t
>(kCGBitmapByteOrder32Big));
157 switch (screenshot.pixel_format) {
158 case flutter::Rasterizer::ScreenshotFormat::kUnknown:
159 case flutter::Rasterizer::ScreenshotFormat::kR8G8B8A8UNormInt:
162 case flutter::Rasterizer::ScreenshotFormat::kB8G8R8A8UNormInt:
165 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedFirst) |
166 static_cast<uint32_t
>(kCGBitmapByteOrder32Little));
168 case flutter::Rasterizer::ScreenshotFormat::kR16G16B16A16Float:
169 bits_per_component = 16u;
170 bits_per_pixel = 64u;
171 bytes_per_row_multiplier = 8u;
173 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedLast) |
174 static_cast<uint32_t
>(kCGBitmapFloatComponents) |
175 static_cast<uint32_t
>(kCGBitmapByteOrder16Little));
179 fml::CFRef<CGImageRef> image(CGImageCreate(
180 screenshot.frame_size.width,
181 screenshot.frame_size.height,
184 bytes_per_row_multiplier * screenshot.frame_size.width,
190 kCGRenderingIntentDefault
193 const CGRect frame_rect =
194 CGRectMake(0.0, 0.0, screenshot.frame_size.width, screenshot.frame_size.height);
195 CGContextSaveGState(context);
197 CGFloat height = CGBitmapContextGetHeight(context);
199 height = CGFloat(screenshot.frame_size.height);
201 CGContextTranslateCTM(context, 0.0, height);
202 CGContextScaleCTM(context, 1.0, -1.0);
203 CGContextDrawImage(context, frame_rect, image);
204 CGContextRestoreGState(context);
207 - (BOOL)isAccessibilityElement {
216 [
self.delegate flutterViewAccessibilityDidCall];
230 - (NSArray<id<UIFocusItem>>*)focusItemsInRect:(CGRect)rect {
231 NSObject* rootAccessibilityElement =
232 [
self.accessibilityElements count] > 0 ?
self.accessibilityElements[0] : nil;
234 ? @[ [rootAccessibilityElement accessibilityElementAtIndex:0] ]
238 - (NSArray<id<UIFocusEnvironment>>*)preferredFocusEnvironments {
246 - (void)willMoveToWindow:(UIWindow*)newWindow {
249 UIWindowScene* newScene = newWindow.windowScene;
250 UIWindowScene* currentScene =
self.window.windowScene;
252 if (newScene == currentScene) {
259 if (previousSceneLifeCycleDelegate) {
260 [previousSceneLifeCycleDelegate removeFlutterManagedEngine:(FlutterEngine*)self.delegate];
261 self.previousScene = nil;
268 if (newSceneLifeCycleDelegate) {
269 [newSceneLifeCycleDelegate addFlutterManagedEngine:(FlutterEngine*)self.delegate];
274 self.previousScene = currentScene;
instancetype initWithFrame
instancetype initWithCoder
IOSRenderingAPI GetRenderingAPIForProcess(bool force_software)
Class GetCoreAnimationLayerClassForRenderingAPI(IOSRenderingAPI rendering_api)