7 #include "flutter/fml/platform/darwin/cf_utils.h"
15 @property(nonatomic, weak) id<FlutterViewEngineDelegate> delegate;
16 @property(nonatomic, weak) UIWindowScene* previousScene;
23 BOOL _isWideGamutEnabled;
27 - (instancetype)init {
28 NSAssert(NO,
@"FlutterView must initWithDelegate");
33 NSAssert(NO,
@"FlutterView must initWithDelegate");
38 NSAssert(NO,
@"FlutterView must initWithDelegate");
43 return self.window.windowScene.screen;
52 - (void)setIntrinsicContentSize:(CGSize)size {
53 if (!
self.autoResizable) {
57 UIWindow* window =
self.window;
58 CGFloat scale = window ?
self.window.windowScene.screen.scale :
self.traitCollection.displayScale;
59 CGSize scaledSize = CGSizeMake(size.width / scale, size.height / scale);
61 CGSize roundedScaleSize = CGSizeMake(roundf(scaledSize.width), roundf(scaledSize.height));
62 CGSize roundedIntrinsicSize =
66 if (CGSizeEqualToSize(roundedIntrinsicSize, roundedScaleSize)) {
71 self.translatesAutoresizingMaskIntoConstraints =
false;
74 [
self removeAutoResizeLayoutConstraints];
78 attribute:NSLayoutAttributeWidth
79 relatedBy:NSLayoutRelationEqual
81 attribute:NSLayoutAttributeNotAnAttribute
83 constant:scaledSize.width];
87 attribute:NSLayoutAttributeHeight
88 relatedBy:NSLayoutRelationEqual
90 attribute:NSLayoutAttributeNotAnAttribute
92 constant:scaledSize.height];
94 [NSLayoutConstraint activateConstraints:@[ widthConstraint, heightConstraint ]];
95 [
self setNeedsLayout];
98 - (void)resetIntrinsicContentSize {
99 _intrinsicSize = CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric);
100 [
self removeAutoResizeLayoutConstraints];
103 - (void)removeAutoResizeLayoutConstraints {
104 for (NSLayoutConstraint* constraint in
self.constraints) {
106 constraint.active = NO;
111 - (MTLPixelFormat)pixelFormat {
112 if ([
self.layer isKindOfClass:[CAMetalLayer
class]]) {
115 #pragma clang diagnostic push
116 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
117 CAMetalLayer* layer = (CAMetalLayer*)
self.layer;
118 return layer.pixelFormat;
120 return MTLPixelFormatBGRA8Unorm;
122 - (BOOL)isWideGamutSupported {
123 FML_DCHECK(
self.screen);
134 return self.screen.traitCollection.displayGamut != UIDisplayGamutSRGB;
139 enableWideGamut:(BOOL)isWideGamutEnabled {
140 if (delegate == nil) {
141 NSLog(
@"FlutterView delegate was nil.");
145 self = [
super initWithFrame:CGRectNull];
148 _delegate = delegate;
149 _isWideGamutEnabled = isWideGamutEnabled;
150 self.layer.opaque = opaque;
152 _intrinsicSize = CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric);
158 static void PrintWideGamutWarningOnce() {
159 static BOOL did_print = NO;
163 FML_DLOG(WARNING) <<
"Rendering wide gamut colors is turned on but isn't "
164 "supported, downgrading the color gamut to sRGB.";
168 - (void)layoutSubviews {
169 if ([
self.layer isKindOfClass:[CAMetalLayer
class]]) {
172 #pragma clang diagnostic push
173 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
174 CAMetalLayer* layer = (CAMetalLayer*)
self.layer;
175 #pragma clang diagnostic pop
176 CGFloat screenScale =
self.screen.scale;
177 layer.allowsGroupOpacity = YES;
178 layer.contentsScale = screenScale;
179 layer.rasterizationScale = screenScale;
180 layer.framebufferOnly = flutter::Settings::kSurfaceDataAccessible ? NO : YES;
181 if (_isWideGamutEnabled &&
self.isWideGamutSupported) {
182 fml::CFRef<CGColorSpaceRef> srgb(CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB));
183 layer.colorspace = srgb;
184 layer.pixelFormat = MTLPixelFormatBGRA10_XR;
185 }
else if (_isWideGamutEnabled && !
self.isWideGamutSupported) {
186 PrintWideGamutWarningOnce();
190 [
super layoutSubviews];
193 + (Class)layerClass {
198 - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {
199 TRACE_EVENT0(
"flutter",
"SnapshotFlutterView");
201 if (layer !=
self.layer || context ==
nullptr) {
205 auto screenshot = [_delegate takeScreenshot:flutter::Rasterizer::ScreenshotType::UncompressedImage
208 if (!screenshot.data || screenshot.data->isEmpty() || screenshot.frame_size.IsEmpty()) {
212 NSData* data = [NSData dataWithBytes:const_cast<void*>(screenshot.data->data())
213 length:screenshot.data->size()];
215 fml::CFRef<CGDataProviderRef> image_data_provider(
216 CGDataProviderCreateWithCFData(
reinterpret_cast<CFDataRef
>(data)));
218 fml::CFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
221 size_t bits_per_component = 8u;
222 size_t bits_per_pixel = 32u;
223 size_t bytes_per_row_multiplier = 4u;
224 CGBitmapInfo bitmap_info =
225 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedLast) |
226 static_cast<uint32_t
>(kCGBitmapByteOrder32Big));
228 switch (screenshot.pixel_format) {
229 case flutter::Rasterizer::ScreenshotFormat::kUnknown:
230 case flutter::Rasterizer::ScreenshotFormat::kR8G8B8A8UNormInt:
233 case flutter::Rasterizer::ScreenshotFormat::kB8G8R8A8UNormInt:
236 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedFirst) |
237 static_cast<uint32_t
>(kCGBitmapByteOrder32Little));
239 case flutter::Rasterizer::ScreenshotFormat::kR16G16B16A16Float:
240 bits_per_component = 16u;
241 bits_per_pixel = 64u;
242 bytes_per_row_multiplier = 8u;
244 static_cast<CGBitmapInfo
>(
static_cast<uint32_t
>(kCGImageAlphaPremultipliedLast) |
245 static_cast<uint32_t
>(kCGBitmapFloatComponents) |
246 static_cast<uint32_t
>(kCGBitmapByteOrder16Little));
250 fml::CFRef<CGImageRef> image(CGImageCreate(
251 screenshot.frame_size.width,
252 screenshot.frame_size.height,
255 bytes_per_row_multiplier * screenshot.frame_size.width,
261 kCGRenderingIntentDefault
264 const CGRect frame_rect =
265 CGRectMake(0.0, 0.0, screenshot.frame_size.width, screenshot.frame_size.height);
266 CGContextSaveGState(context);
268 CGFloat height = CGBitmapContextGetHeight(context);
270 height = CGFloat(screenshot.frame_size.height);
272 CGContextTranslateCTM(context, 0.0, height);
273 CGContextScaleCTM(context, 1.0, -1.0);
274 CGContextDrawImage(context, frame_rect, image);
275 CGContextRestoreGState(context);
278 - (BOOL)isAccessibilityElement {
287 [
self.delegate flutterViewAccessibilityDidCall];
301 - (NSArray<id<UIFocusItem>>*)focusItemsInRect:(CGRect)rect {
302 NSObject* rootAccessibilityElement =
303 [
self.accessibilityElements count] > 0 ?
self.accessibilityElements[0] : nil;
305 ? @[ [rootAccessibilityElement accessibilityElementAtIndex:0] ]
309 - (NSArray<id<UIFocusEnvironment>>*)preferredFocusEnvironments {
317 - (void)willMoveToWindow:(UIWindow*)newWindow {
320 UIWindowScene* newScene = newWindow.windowScene;
321 UIWindowScene* currentScene =
self.window.windowScene;
323 if (newScene == currentScene) {
330 if (previousSceneLifeCycleDelegate) {
331 [previousSceneLifeCycleDelegate removeFlutterManagedEngine:(FlutterEngine*)self.delegate];
332 self.previousScene = nil;
339 if (newSceneLifeCycleDelegate) {
340 [newSceneLifeCycleDelegate addFlutterManagedEngine:(FlutterEngine*)self.delegate];
345 self.previousScene = currentScene;
instancetype initWithFrame
instancetype initWithCoder
IOSRenderingAPI GetRenderingAPIForProcess(bool force_software)
Class GetCoreAnimationLayerClassForRenderingAPI(IOSRenderingAPI rendering_api)