Skip to content

Commit 0ccb26e

Browse files
Chris Yangchaselatta
authored andcommitted
PlatformViewsController: clear composition_order_ in the beginning of each frame. (flutter#22574)
1 parent 9a49f70 commit 0ccb26e

11 files changed

Lines changed: 193 additions & 31 deletions

File tree

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,13 @@
241241
gesture_recognizers_blocking_policies[idString] = gestureRecognizerBlockingPolicy;
242242
}
243243

244-
void FlutterPlatformViewsController::SetFrameSize(SkISize frame_size) {
244+
void FlutterPlatformViewsController::BeginFrame(SkISize frame_size) {
245+
ResetFrameState();
245246
frame_size_ = frame_size;
246247
}
247248

248249
void FlutterPlatformViewsController::CancelFrame() {
249-
picture_recorders_.clear();
250-
composition_order_.clear();
250+
ResetFrameState();
251251
}
252252

253253
// TODO(cyanglaz): https://github.com/flutter/flutter/issues/56474
@@ -603,13 +603,6 @@
603603
}
604604
}
605605

606-
void FlutterPlatformViewsController::EndFrame(
607-
bool should_resubmit_frame,
608-
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
609-
// Reset the composition order, so next frame starts empty.
610-
composition_order_.clear();
611-
}
612-
613606
std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLayer(
614607
GrDirectContext* gr_context,
615608
std::shared_ptr<IOSContext> ios_context,
@@ -705,6 +698,11 @@
705698
}
706699
}
707700

701+
void FlutterPlatformViewsController::ResetFrameState() {
702+
picture_recorders_.clear();
703+
composition_order_.clear();
704+
}
705+
708706
} // namespace flutter
709707

710708
// This recognizers delays touch events from being dispatched to the responder chain until it failed

shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,6 @@ - (void)testCanCreatePlatformViewWithoutFlutterView {
204204
result);
205205

206206
XCTAssertNotNil(gMockPlatformView);
207-
208-
flutterPlatformViewsController->Reset();
209207
}
210208

211209
- (void)testChildClippingViewHitTests {
@@ -281,7 +279,6 @@ - (void)testCompositePlatformView {
281279
CGRect platformViewRectInFlutterView = [gMockPlatformView convertRect:gMockPlatformView.bounds
282280
toView:mockFlutterView];
283281
XCTAssertTrue(CGRectEqualToRect(platformViewRectInFlutterView, CGRectMake(100, 100, 300, 300)));
284-
flutterPlatformViewsController->Reset();
285282
}
286283

287284
- (void)testChildClippingViewShouldBeTheBoundingRectOfPlatformView {
@@ -351,8 +348,6 @@ - (void)testChildClippingViewShouldBeTheBoundingRectOfPlatformView {
351348
XCTAssertLessThan(
352349
fabs(platformViewRectInFlutterView.size.height - childClippingView.frame.size.height),
353350
kFloatCompareEpsilon);
354-
355-
flutterPlatformViewsController->Reset();
356351
}
357352

358353
- (void)testClipRect {
@@ -424,7 +419,6 @@ - (void)testClipRect {
424419
}
425420
}
426421
}
427-
flutterPlatformViewsController->Reset();
428422
}
429423

430424
- (void)testClipRRect {
@@ -496,7 +490,6 @@ - (void)testClipRRect {
496490
}
497491
}
498492
}
499-
flutterPlatformViewsController->Reset();
500493
}
501494

502495
- (void)testClipPath {
@@ -569,7 +562,6 @@ - (void)testClipPath {
569562
}
570563
}
571564
}
572-
flutterPlatformViewsController->Reset();
573565
}
574566

575567
- (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents {
@@ -632,8 +624,6 @@ - (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents {
632624
flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
633625
[forwardGectureRecognizer touchesBegan:touches2 withEvent:event2];
634626
OCMVerify([mockFlutterViewContoller touchesBegan:touches2 withEvent:event2]);
635-
636-
flutterPlatformViewsController->Reset();
637627
}
638628

639629
- (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGesturesToBeHandled {
@@ -884,8 +874,6 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin
884874
gpu_is_disabled->SetSwitch(false);
885875
XCTAssertTrue(flutterPlatformViewsController->SubmitFrame(
886876
nullptr, nullptr, std::move(mock_surface_submit_false), gpu_is_disabled));
887-
888-
flutterPlatformViewsController->Reset();
889877
}
890878

891879
- (void)
@@ -937,6 +925,59 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin
937925
XCTAssertNil(gMockPlatformView);
938926
}
939927

928+
- (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder {
929+
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
930+
auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
931+
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
932+
/*platform=*/thread_task_runner,
933+
/*raster=*/thread_task_runner,
934+
/*ui=*/thread_task_runner,
935+
/*io=*/thread_task_runner);
936+
auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
937+
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
938+
/*delegate=*/mock_delegate,
939+
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
940+
/*platform_views_controller=*/flutterPlatformViewsController,
941+
/*task_runners=*/runners);
942+
943+
UIView* mockFlutterView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)] autorelease];
944+
flutterPlatformViewsController->SetFlutterView(mockFlutterView);
945+
946+
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
947+
[[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease];
948+
flutterPlatformViewsController->RegisterViewFactory(
949+
factory, @"MockFlutterPlatformView",
950+
FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
951+
FlutterResult result = ^(id result) {
952+
};
953+
954+
flutterPlatformViewsController->OnMethodCall(
955+
[FlutterMethodCall
956+
methodCallWithMethodName:@"create"
957+
arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}],
958+
result);
959+
960+
// First frame, |GetCurrentCanvases| is not empty after composite.
961+
flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
962+
flutter::MutatorsStack stack;
963+
SkMatrix finalMatrix;
964+
auto embeddedViewParams1 =
965+
std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
966+
flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1));
967+
flutterPlatformViewsController->CompositeEmbeddedView(0);
968+
XCTAssertEqual(flutterPlatformViewsController->GetCurrentCanvases().size(), 1UL);
969+
970+
// Second frame, |GetCurrentCanvases| should be empty at the start
971+
flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
972+
XCTAssertTrue(flutterPlatformViewsController->GetCurrentCanvases().empty());
973+
974+
auto embeddedViewParams2 =
975+
std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
976+
flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams2));
977+
flutterPlatformViewsController->CompositeEmbeddedView(0);
978+
XCTAssertEqual(flutterPlatformViewsController->GetCurrentCanvases().size(), 1UL);
979+
}
980+
940981
- (int)alphaOfPoint:(CGPoint)point onView:(UIView*)view {
941982
unsigned char pixel[4] = {0};
942983

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ class FlutterPlatformViewsController {
141141
NSString* factoryId,
142142
FlutterPlatformViewGestureRecognizersBlockingPolicy gestureRecognizerBlockingPolicy);
143143

144-
void SetFrameSize(SkISize frame_size);
144+
// Called at the begining of each frame.
145+
void BeginFrame(SkISize frame_size);
145146

146147
// Indicates that we don't compisite any platform views or overlays during this frame.
147148
// Also reverts the composition_order_ to its original state at the begining of the frame.
@@ -175,12 +176,6 @@ class FlutterPlatformViewsController {
175176
std::unique_ptr<SurfaceFrame> frame,
176177
const std::shared_ptr<fml::SyncSwitch>& gpu_disable_sync_switch);
177178

178-
// Invoked at the very end of a frame.
179-
// After invoking this method, nothing should happen on the current TaskRunner during the same
180-
// frame.
181-
void EndFrame(bool should_resubmit_frame,
182-
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger);
183-
184179
void OnMethodCall(FlutterMethodCall* call, FlutterResult& result);
185180

186181
private:
@@ -309,6 +304,9 @@ class FlutterPlatformViewsController {
309304
std::shared_ptr<IOSContext> ios_context,
310305
std::unique_ptr<SurfaceFrame> frame);
311306

307+
// Resets the state of the frame.
308+
void ResetFrameState();
309+
312310
FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController);
313311
};
314312

shell/platform/darwin/ios/ios_external_view_embedder.mm

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
3838
TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::BeginFrame");
3939
FML_CHECK(platform_views_controller_);
40-
platform_views_controller_->SetFrameSize(frame_size);
40+
platform_views_controller_->BeginFrame(frame_size);
4141
}
4242

4343
// |ExternalViewEmbedder|
@@ -88,7 +88,6 @@
8888
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
8989
TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::EndFrame");
9090
FML_CHECK(platform_views_controller_);
91-
return platform_views_controller_->EndFrame(should_resubmit_frame, raster_thread_merger);
9291
}
9392

9493
// |ExternalViewEmbedder|

testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
6816DBAD2318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA82318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png */; };
5858
6816DBAE2318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA92318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png */; };
5959
68A5B63423EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68A5B63323EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m */; };
60+
68D4017D2564859300ECD91A /* ContinuousTexture.m in Sources */ = {isa = PBXBuildFile; fileRef = 68D4017C2564859300ECD91A /* ContinuousTexture.m */; };
6061
/* End PBXBuildFile section */
6162

6263
/* Begin PBXContainerItemProxy section */
@@ -172,6 +173,8 @@
172173
6816DBA82318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprect_iPhone SE_simulator.png"; sourceTree = "<group>"; };
173174
6816DBA92318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprrect_iPhone SE_simulator.png"; sourceTree = "<group>"; };
174175
68A5B63323EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformViewGestureRecognizerTests.m; sourceTree = "<group>"; };
176+
68D4017B2564859300ECD91A /* ContinuousTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContinuousTexture.h; sourceTree = "<group>"; };
177+
68D4017C2564859300ECD91A /* ContinuousTexture.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContinuousTexture.m; sourceTree = "<group>"; };
175178
/* End PBXFileReference section */
176179

177180
/* Begin PBXFrameworksBuildPhase section */
@@ -238,6 +241,8 @@
238241
0A57B3BC2323C4BD00DD9521 /* ScreenBeforeFlutter.m */,
239242
0A57B3BE2323C74200DD9521 /* FlutterEngine+ScenariosTest.m */,
240243
0A57B3C02323C74D00DD9521 /* FlutterEngine+ScenariosTest.h */,
244+
68D4017B2564859300ECD91A /* ContinuousTexture.h */,
245+
68D4017C2564859300ECD91A /* ContinuousTexture.m */,
241246
);
242247
path = Scenarios;
243248
sourceTree = "<group>";
@@ -462,6 +467,7 @@
462467
buildActionMask = 2147483647;
463468
files = (
464469
248D76DA22E388380012F0C1 /* main.m in Sources */,
470+
68D4017D2564859300ECD91A /* ContinuousTexture.m in Sources */,
465471
24F1FB89230B4579005ACE7C /* TextPlatformView.m in Sources */,
466472
248D76CC22E388370012F0C1 /* AppDelegate.m in Sources */,
467473
0A57B3BF2323C74200DD9521 /* FlutterEngine+ScenariosTest.m in Sources */,

testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#import "AppDelegate.h"
66

7+
#import "ContinuousTexture.h"
78
#import "FlutterEngine+ScenariosTest.h"
89
#import "ScreenBeforeFlutter.h"
910
#import "TextPlatformView.h"
@@ -52,6 +53,7 @@ - (BOOL)application:(UIApplication*)application
5253
@"--tap-status-bar" : @"tap_status_bar",
5354
@"--text-semantics-focus" : @"text_semantics_focus",
5455
@"--animated-color-square" : @"animated_color_square",
56+
@"--platform-view-with-continuous-texture" : @"platform_view_with_continuous_texture"
5557
};
5658
__block NSString* flutterViewControllerTestName = nil;
5759
[launchArgsMap
@@ -70,6 +72,10 @@ - (BOOL)application:(UIApplication*)application
7072
}
7173

7274
[self.window makeKeyAndVisible];
75+
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--with-continuous-texture"]) {
76+
[ContinuousTexture
77+
registerWithRegistrar:[self registrarForPlugin:@"com.constant.firing.texture"]];
78+
}
7379
return [super application:application didFinishLaunchingWithOptions:launchOptions];
7480
}
7581

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2019 The Chromium 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/Flutter.h>
6+
#import <Foundation/Foundation.h>
7+
8+
NS_ASSUME_NONNULL_BEGIN
9+
10+
// A texture plugin that ready textures continuously.
11+
@interface ContinuousTexture : NSObject <FlutterPlugin>
12+
13+
@end
14+
15+
// The testing texture used by |ContinuousTexture|
16+
@interface FlutterScenarioTestTexture : NSObject <FlutterTexture>
17+
18+
@end
19+
20+
NS_ASSUME_NONNULL_END
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2019 The Chromium 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 "ContinuousTexture.h"
6+
7+
@implementation ContinuousTexture
8+
9+
+ (void)registerWithRegistrar:(nonnull NSObject<FlutterPluginRegistrar>*)registrar {
10+
NSObject<FlutterTextureRegistry>* textureRegistry = [registrar textures];
11+
FlutterScenarioTestTexture* texture = [[FlutterScenarioTestTexture alloc] init];
12+
int64_t textureId = [textureRegistry registerTexture:texture];
13+
[NSTimer scheduledTimerWithTimeInterval:0.05
14+
repeats:YES
15+
block:^(NSTimer* _Nonnull timer) {
16+
[textureRegistry textureFrameAvailable:textureId];
17+
}];
18+
}
19+
20+
@end
21+
22+
@implementation FlutterScenarioTestTexture
23+
24+
- (CVPixelBufferRef _Nullable)copyPixelBuffer {
25+
return [self pixelBuffer];
26+
}
27+
28+
- (CVPixelBufferRef)pixelBuffer {
29+
NSDictionary* options = @{
30+
// This key is required to generate SKPicture with CVPixelBufferRef in metal.
31+
(NSString*)kCVPixelBufferMetalCompatibilityKey : @YES
32+
};
33+
CVPixelBufferRef pxbuffer = NULL;
34+
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, 200, 200, kCVPixelFormatType_32BGRA,
35+
(__bridge CFDictionaryRef)options, &pxbuffer);
36+
37+
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
38+
39+
CVPixelBufferLockBaseAddress(pxbuffer, 0);
40+
return pxbuffer;
41+
}
42+
43+
@end

testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#import "GoldenPlatformViewTests.h"
66

7+
static const NSInteger kSecondsToWaitForPlatformView = 30;
8+
79
@interface PlatformViewUITests : GoldenPlatformViewTests
810

911
@end
@@ -170,4 +172,35 @@ - (void)testPlatformView {
170172
XCUIDevice.sharedDevice.orientation = UIDeviceOrientationLandscapeLeft;
171173
[self checkGolden];
172174
}
175+
176+
@end
177+
178+
@interface PlatformViewWithContinuousTexture : XCTestCase
179+
180+
@end
181+
182+
@implementation PlatformViewWithContinuousTexture
183+
184+
- (void)setUp {
185+
self.continueAfterFailure = NO;
186+
}
187+
188+
- (void)testPlatformViewWithContinuousTexture {
189+
XCUIApplication* app = [[XCUIApplication alloc] init];
190+
app.launchArguments =
191+
@[ @"--platform-view-with-continuous-texture", @"--with-continuous-texture" ];
192+
[app launch];
193+
194+
XCUIElement* platformView = app.textViews.firstMatch;
195+
BOOL exists = [platformView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView];
196+
if (!exists) {
197+
XCTFail(@"It took longer than %@ second to find the platform view."
198+
@"There might be issues with the platform view's construction,"
199+
@"or with how the scenario is built.",
200+
@(kSecondsToWaitForPlatformView));
201+
}
202+
203+
XCTAssertNotNil(platformView);
204+
}
205+
173206
@end

0 commit comments

Comments
 (0)