[iOS] Avoid crash when backdrop filter is null for PlatformViews (flutter/engine#43150)

During certain partial repaint logic, the backdrop filter layer is present but the filter itself is null. We need to account for it when deciding whether to add such filter to the mutator stack.

Fixes https://github.com/flutter/flutter/issues/127095

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
Chris Yang
2023-07-05 11:14:14 -07:00
committed by GitHub
parent 79725221e8
commit 5c27bcf072
8 changed files with 90 additions and 3 deletions

View File

@@ -42,7 +42,7 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
void BackdropFilterLayer::Preroll(PrerollContext* context) {
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context, true, bool(filter_));
if (context->view_embedder != nullptr) {
if (filter_ && context->view_embedder != nullptr) {
context->view_embedder->PushFilterToVisitedPlatformViews(
filter_, context->state_stack.device_cull_rect());
}

View File

@@ -62,6 +62,7 @@
6860CE272A01B2FF00B68EC5 /* golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6860CE242A01B2FF00B68EC5 /* golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png */; };
68A5B63423EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68A5B63323EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m */; };
68D4017D2564859300ECD91A /* ContinuousTexture.m in Sources */ = {isa = PBXBuildFile; fileRef = 68D4017C2564859300ECD91A /* ContinuousTexture.m */; };
68D93AEE2A46097E0054AB6D /* golden_platform_view_with_negative_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 68D93AED2A46097E0054AB6D /* golden_platform_view_with_negative_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png */; };
F26F15B8268B6B5600EC54D3 /* iPadGestureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F26F15B7268B6B5500EC54D3 /* iPadGestureTests.m */; };
/* End PBXBuildFile section */
@@ -183,6 +184,7 @@
68A5B63323EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformViewGestureRecognizerTests.m; sourceTree = "<group>"; };
68D4017B2564859300ECD91A /* ContinuousTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContinuousTexture.h; sourceTree = "<group>"; };
68D4017C2564859300ECD91A /* ContinuousTexture.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContinuousTexture.m; sourceTree = "<group>"; };
68D93AED2A46097E0054AB6D /* golden_platform_view_with_negative_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_with_negative_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png"; sourceTree = "<group>"; };
F26F15B7268B6B5500EC54D3 /* iPadGestureTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iPadGestureTests.m; sourceTree = "<group>"; };
F72114B628EF99F500184A2D /* Info_Impeller.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info_Impeller.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -308,6 +310,7 @@
F7B464DC2759D02B00079189 /* Goldens */ = {
isa = PBXGroup;
children = (
68D93AED2A46097E0054AB6D /* golden_platform_view_with_negative_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png */,
6860CE242A01B2FF00B68EC5 /* golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png */,
6860CE232A01B2FF00B68EC5 /* golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png */,
6860CE222A01B2FF00B68EC5 /* golden_two_platform_view_clip_rrect_iPhone SE (3rd generation)_16.2_simulator.png */,
@@ -477,6 +480,7 @@
684FFF8629F9C10700281002 /* golden_bogus_font_text_iPhone SE (3rd generation)_16.2_simulator.png in Resources */,
684FFF7E29F9C10700281002 /* golden_platform_view_opacity_iPhone SE (3rd generation)_16.2_simulator.png in Resources */,
684FFF8729F9C10700281002 /* golden_platform_view_multiple_iPhone SE (3rd generation)_16.2_simulator.png in Resources */,
68D93AEE2A46097E0054AB6D /* golden_platform_view_with_negative_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png in Resources */,
684FFF8D29F9C10700281002 /* golden_platform_view_large_cliprrect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */,
684FFF8329F9C10700281002 /* golden_platform_view_transform_iPhone SE (3rd generation)_16.2_simulator.png in Resources */,
684FFF8B29F9C10700281002 /* golden_platform_view_clippath_iPhone SE (3rd generation)_16.2_simulator.png in Resources */,

View File

@@ -55,6 +55,8 @@
@"--platform-view-with-other-backdrop-filter" : @"platform_view_with_other_backdrop_filter",
@"--two-platform-views-with-other-backdrop-filter" :
@"two_platform_views_with_other_backdrop_filter",
@"--platform-view-with-negative-backdrop-filter" :
@"platform_view_with_negative_backdrop_filter",
@"--platform-view-rotate" : @"platform_view_rotate",
@"--non-full-screen-flutter-view-platform-view" : @"non_full_screen_flutter_view_platform_view",
@"--gesture-reject-after-touches-ended" : @"platform_view_gesture_reject_after_touches_ended",

View File

@@ -41,6 +41,8 @@ NSDictionary* launchArgsMap;
@"--platform-view-with-other-backdrop-filter" : @"platform_view_with_other_backdrop_filter",
@"--two-platform-views-with-other-backdrop-filter" :
@"two_platform_views_with_other_backdrop_filter",
@"--platform-view-with-negative-backdrop-filter" :
@"platform_view_with_negative_backdrop_filter",
@"--platform-view-rotate" : @"platform_view_rotate",
@"--non-full-screen-flutter-view-platform-view" :
@"non_full_screen_flutter_view_platform_view",

View File

@@ -380,6 +380,24 @@ static const NSInteger kSecondsToWaitForPlatformView = 30;
@end
@interface PlatformViewWithNegativeOtherBackDropFilterTests : GoldenPlatformViewTests
@end
@implementation PlatformViewWithNegativeOtherBackDropFilterTests
- (instancetype)initWithInvocation:(NSInvocation*)invocation {
GoldenTestManager* manager = [[GoldenTestManager alloc]
initWithLaunchArg:@"--platform-view-with-negative-backdrop-filter"];
return [super initWithManager:manager invocation:invocation];
}
- (void)testPlatformView {
[self checkPlatformViewGolden];
}
@end
@interface PlatformViewRotation : GoldenPlatformViewTests
@end

View File

@@ -1443,8 +1443,6 @@ class PlatformViewWithOtherBackDropFilter extends PlatformViewScenario {
/// A simple platform view for testing backDropFilter with a platform view in the scene.
///
/// The stack would look like: picture 1 -> pv1 -> picture 2 -> filter -> pv2 - > picture 3.
/// Because backdrop filter on platform views has not been implemented(see: https://github.com/flutter/flutter/issues/43902),
/// the result will not including a filtered pv1.
class TwoPlatformViewsWithOtherBackDropFilter extends Scenario
with _BasePlatformViewScenarioMixin {
/// Constructs the scenario.
@@ -1533,6 +1531,68 @@ class TwoPlatformViewsWithOtherBackDropFilter extends Scenario
}
}
/// A simple platform view for testing backDropFilter with a platform view in the scene.
///
/// The backdrop filter sigma value is negative, which tries to reproduce a crash, see:
/// https://github.com/flutter/flutter/issues/127095
class PlatformViewWithNegativeBackDropFilter extends Scenario
with _BasePlatformViewScenarioMixin {
/// Constructs the scenario.
PlatformViewWithNegativeBackDropFilter(
super.view, {
required int id,
}) : _id = id;
final int _id;
@override
void onBeginFrame(Duration duration) {
final SceneBuilder builder = SceneBuilder();
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
// This is just a background picture to make the result more viewable.
canvas.drawRect(
const Rect.fromLTRB(0, 0, 600, 1000),
Paint()..color = const Color(0xFFFF0000),
);
canvas.drawRect(
const Rect.fromLTRB(0, 0, 300, 300),
Paint()..color = const Color(0xFF00FF00),
);
final Picture picture1 = recorder.endRecording();
builder.addPicture(Offset.zero, picture1);
builder.pushOffset(0, 200);
addPlatformView(
_id,
dispatcher: view.platformDispatcher,
sceneBuilder: builder,
width: 100,
height: 100,
text: 'platform view 1'
);
final PictureRecorder recorder2 = PictureRecorder();
final Canvas canvas2 = Canvas(recorder2);
canvas2.drawCircle(
const Offset(200, 100),
50,
Paint()..color = const Color(0xFF0000EF),
);
final Picture picture2 = recorder2.endRecording();
builder.addPicture(const Offset(100, 100), picture2);
final ImageFilter filter = ImageFilter.blur(sigmaX: -8, sigmaY: 8);
builder.pushBackdropFilter(filter);
final Scene scene = builder.build();
view.render(scene);
scene.dispose();
}
}
/// Builds a scenario where many platform views are scrolling and pass under a picture.
class PlatformViewScrollingUnderWidget extends Scenario
with _BasePlatformViewScenarioMixin {

View File

@@ -43,6 +43,7 @@ Map<String, _ScenarioFactory> _scenarios = <String, _ScenarioFactory>{
'platform_view_opacity': (FlutterView view) => PlatformViewOpacityScenario(view, id: _viewId++),
'platform_view_with_other_backdrop_filter': (FlutterView view) => PlatformViewWithOtherBackDropFilter(view, id: _viewId++),
'two_platform_views_with_other_backdrop_filter': (FlutterView view) => TwoPlatformViewsWithOtherBackDropFilter(view, firstId: _viewId++, secondId: _viewId++),
'platform_view_with_negative_backdrop_filter': (FlutterView view) => PlatformViewWithNegativeBackDropFilter(view, id: _viewId++),
'platform_view_multiple': (FlutterView view) => MultiPlatformViewScenario(view, firstId: _viewId++, secondId: _viewId++),
'platform_view_multiple_background_foreground': (FlutterView view) => MultiPlatformViewBackgroundForegroundScenario(view, firstId: _viewId++, secondId: _viewId++),
'non_full_screen_flutter_view_platform_view': (FlutterView view) => NonFullScreenFlutterViewPlatformViewScenario(view, id: _viewId++),