Flutter Engine
The Flutter Engine
FlutterView.mm
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
6
7#include "flutter/fml/platform/darwin/cf_utils.h"
8
10
11@interface FlutterView ()
12@property(nonatomic, weak) id<FlutterViewEngineDelegate> delegate;
13@end
14
15@implementation FlutterView {
16 BOOL _isWideGamutEnabled;
17}
18
19- (instancetype)init {
20 NSAssert(NO, @"FlutterView must initWithDelegate");
21 return nil;
22}
23
24- (instancetype)initWithFrame:(CGRect)frame {
25 NSAssert(NO, @"FlutterView must initWithDelegate");
26 return nil;
27}
28
29- (instancetype)initWithCoder:(NSCoder*)aDecoder {
30 NSAssert(NO, @"FlutterView must initWithDelegate");
31 return nil;
32}
33
34- (UIScreen*)screen {
35 if (@available(iOS 13.0, *)) {
36 return self.window.windowScene.screen;
37 }
38 return UIScreen.mainScreen;
39}
40
41- (MTLPixelFormat)pixelFormat {
42 if ([self.layer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) {
43// It is a known Apple bug that CAMetalLayer incorrectly reports its supported
44// SDKs. It is, in fact, available since iOS 8.
45#pragma clang diagnostic push
46#pragma clang diagnostic ignored "-Wunguarded-availability-new"
47 CAMetalLayer* layer = (CAMetalLayer*)self.layer;
48 return layer.pixelFormat;
49 }
50 return MTLPixelFormatBGRA8Unorm;
51}
52- (BOOL)isWideGamutSupported {
53 if (!self.delegate.isUsingImpeller) {
54 return NO;
55 }
56
57 FML_DCHECK(self.screen);
58
59 // This predicates the decision on the capabilities of the iOS device's
60 // display. This means external displays will not support wide gamut if the
61 // device's display doesn't support it. It practice that should be never.
62 return self.screen.traitCollection.displayGamut != UIDisplayGamutSRGB;
63}
64
65- (instancetype)initWithDelegate:(id<FlutterViewEngineDelegate>)delegate
66 opaque:(BOOL)opaque
67 enableWideGamut:(BOOL)isWideGamutEnabled {
68 if (delegate == nil) {
69 NSLog(@"FlutterView delegate was nil.");
70 return nil;
71 }
72
73 self = [super initWithFrame:CGRectNull];
74
75 if (self) {
76 _delegate = delegate;
77 _isWideGamutEnabled = isWideGamutEnabled;
78 self.layer.opaque = opaque;
79
80 // This line is necessary. CoreAnimation(or UIKit) may take this to do
81 // something to compute the final frame presented on screen, if we don't set this,
82 // it will make it take long time for us to take next CAMetalDrawable and will
83 // cause constant junk during rendering.
84 self.backgroundColor = UIColor.clearColor;
85 }
86
87 return self;
88}
89
90static void PrintWideGamutWarningOnce() {
91 static BOOL did_print = NO;
92 if (did_print) {
93 return;
94 }
95 FML_DLOG(WARNING) << "Rendering wide gamut colors is turned on but isn't "
96 "supported, downgrading the color gamut to sRGB.";
97 did_print = YES;
98}
99
100- (void)layoutSubviews {
101 if ([self.layer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) {
102// It is a known Apple bug that CAMetalLayer incorrectly reports its supported
103// SDKs. It is, in fact, available since iOS 8.
104#pragma clang diagnostic push
105#pragma clang diagnostic ignored "-Wunguarded-availability-new"
106 CAMetalLayer* layer = (CAMetalLayer*)self.layer;
107#pragma clang diagnostic pop
108 CGFloat screenScale = self.screen.scale;
109 layer.allowsGroupOpacity = YES;
110 layer.contentsScale = screenScale;
111 layer.rasterizationScale = screenScale;
112 layer.framebufferOnly = flutter::Settings::kSurfaceDataAccessible ? NO : YES;
113 BOOL isWideGamutSupported = self.isWideGamutSupported;
114 if (_isWideGamutEnabled && isWideGamutSupported) {
115 CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB);
116 layer.colorspace = srgb;
117 CFRelease(srgb);
118 layer.pixelFormat = MTLPixelFormatBGRA10_XR;
119 } else if (_isWideGamutEnabled && !isWideGamutSupported) {
120 PrintWideGamutWarningOnce();
121 }
122 }
123
124 [super layoutSubviews];
125}
126
128
129+ (BOOL)forceSoftwareRendering {
131}
132
133+ (void)setForceSoftwareRendering:(BOOL)forceSoftwareRendering {
134 _forceSoftwareRendering = forceSoftwareRendering;
135}
136
137+ (Class)layerClass {
140}
141
142- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {
143 TRACE_EVENT0("flutter", "SnapshotFlutterView");
144
145 if (layer != self.layer || context == nullptr) {
146 return;
147 }
148
149 auto screenshot = [_delegate takeScreenshot:flutter::Rasterizer::ScreenshotType::UncompressedImage
150 asBase64Encoded:NO];
151
152 if (!screenshot.data || screenshot.data->isEmpty() || screenshot.frame_size.isEmpty()) {
153 return;
154 }
155
156 NSData* data = [NSData dataWithBytes:const_cast<void*>(screenshot.data->data())
157 length:screenshot.data->size()];
158
159 fml::CFRef<CGDataProviderRef> image_data_provider(
160 CGDataProviderCreateWithCFData(reinterpret_cast<CFDataRef>(data)));
161
162 fml::CFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
163
164 // Defaults for RGBA8888.
165 size_t bits_per_component = 8u;
166 size_t bits_per_pixel = 32u;
167 size_t bytes_per_row_multiplier = 4u;
168 CGBitmapInfo bitmap_info =
169 static_cast<CGBitmapInfo>(static_cast<uint32_t>(kCGImageAlphaPremultipliedLast) |
170 static_cast<uint32_t>(kCGBitmapByteOrder32Big));
171
172 switch (screenshot.pixel_format) {
175 // Assume unknown is Skia and is RGBA8888. Keep defaults.
176 break;
178 // Treat this as little endian with the alpha first so that it's read backwards.
179 bitmap_info =
180 static_cast<CGBitmapInfo>(static_cast<uint32_t>(kCGImageAlphaPremultipliedFirst) |
181 static_cast<uint32_t>(kCGBitmapByteOrder32Little));
182 break;
184 bits_per_component = 16u;
185 bits_per_pixel = 64u;
186 bytes_per_row_multiplier = 8u;
187 bitmap_info =
188 static_cast<CGBitmapInfo>(static_cast<uint32_t>(kCGImageAlphaPremultipliedLast) |
189 static_cast<uint32_t>(kCGBitmapFloatComponents) |
190 static_cast<uint32_t>(kCGBitmapByteOrder16Little));
191 break;
192 }
193
194 fml::CFRef<CGImageRef> image(CGImageCreate(
195 screenshot.frame_size.width(), // size_t width
196 screenshot.frame_size.height(), // size_t height
197 bits_per_component, // size_t bitsPerComponent
198 bits_per_pixel, // size_t bitsPerPixel,
199 bytes_per_row_multiplier * screenshot.frame_size.width(), // size_t bytesPerRow
200 colorspace, // CGColorSpaceRef space
201 bitmap_info, // CGBitmapInfo bitmapInfo
202 image_data_provider, // CGDataProviderRef provider
203 nullptr, // const CGFloat* decode
204 false, // bool shouldInterpolate
205 kCGRenderingIntentDefault // CGColorRenderingIntent intent
206 ));
207
208 const CGRect frame_rect =
209 CGRectMake(0.0, 0.0, screenshot.frame_size.width(), screenshot.frame_size.height());
210 CGContextSaveGState(context);
211 // If the CGContext is not a bitmap based context, this returns zero.
212 CGFloat height = CGBitmapContextGetHeight(context);
213 if (height == 0) {
214 height = CGFloat(screenshot.frame_size.height());
215 }
216 CGContextTranslateCTM(context, 0.0, height);
217 CGContextScaleCTM(context, 1.0, -1.0);
218 CGContextDrawImage(context, frame_rect, image);
219 CGContextRestoreGState(context);
220}
221
222- (BOOL)isAccessibilityElement {
223 // iOS does not provide an API to query whether the voice control
224 // is turned on or off. It is likely at least one of the assitive
225 // technologies is turned on if this method is called. If we do
226 // not catch it in notification center, we will catch it here.
227 //
228 // TODO(chunhtai): Remove this workaround once iOS provides an
229 // API to query whether voice control is enabled.
230 // https://github.com/flutter/flutter/issues/76808.
231 [self.delegate flutterViewAccessibilityDidCall];
232 return NO;
233}
234
235@end
static std::function< void(void)> pop(std::deque< std::function< void(void)> > *list)
Definition: SkExecutor.cpp:62
if(end==-1)
#define FML_DLOG(severity)
Definition: logging.h:102
#define FML_DCHECK(condition)
Definition: logging.h:103
BOOL forceSoftwareRendering
Definition: FlutterView.h:49
id< FlutterViewEngineDelegate > delegate
Definition: FlutterView.mm:12
instancetype initWithFrame
instancetype initWithCoder
static BOOL _forceSoftwareRendering
Definition: FlutterView.mm:127
static bool init()
sk_sp< const SkImage > image
Definition: SkRecords.h:269
IOSRenderingAPI GetRenderingAPIForProcess(bool force_software)
Class GetCoreAnimationLayerClassForRenderingAPI(IOSRenderingAPI rendering_api)
int32_t height
static constexpr bool kSurfaceDataAccessible
Definition: settings.h:113
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131
int BOOL
Definition: windows_types.h:37