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