Flutter 1.20.3 engine cherrypicks (#20838)
* Update 1.20 engine to use Dart 2.9.2
* update license goldens
* Fix EGL_BAD_SURFACE when app is paused (#20735)
* The `ForwardingGestureRecognizers` to have back reference to the `PlatformViewsController` so it can access `FlutterViewController` when its available (#20708)
* cherry-pick e09af86a26df0fc05ec727d72deb7ae9fc89f446
* skip linting since this was enabled in CI after this release branch cut commit.
Co-authored-by: Emmanuel Garcia <egarciad@google.com>
Co-authored-by: Chris Yang <ychris@google.com>
diff --git a/DEPS b/DEPS
index 09e6e35..25f8227 100644
--- a/DEPS
+++ b/DEPS
@@ -34,7 +34,7 @@
# Dart is: https://github.com/dart-lang/sdk/blob/master/DEPS.
# You can use //tools/dart/create_updated_flutter_deps.py to produce
# updated revision list of existing dependencies.
- 'dart_revision': 'e940ff7819053ed8a4c04a4dfcda7df12e969331',
+ 'dart_revision': 'b07da893600eadc4efafc5a54b8f9533e43c0034',
# WARNING: DO NOT EDIT MANUALLY
# The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py
diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party
index ea5d6a3..5e03e89 100644
--- a/ci/licenses_golden/licenses_third_party
+++ b/ci/licenses_golden/licenses_third_party
@@ -1,4 +1,4 @@
-Signature: 3d3cc897eb78f9e41161745c866094e3
+Signature: 5a1ec57ea6d353e70a74264709f60d08
UNUSED LICENSES:
diff --git a/ci/lint.sh b/ci/lint.sh
index 023d982..c62bdd5 100755
--- a/ci/lint.sh
+++ b/ci/lint.sh
@@ -7,4 +7,6 @@
./flutter/tools/gn
fi
-dart flutter/ci/lint.dart $COMPILE_COMMANDS flutter/
+exit 0
+# This CI step was added after 1.20.x was cut
+#dart flutter/ci/lint.dart $COMPILE_COMMANDS flutter/
diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc
index d3d0845..16e39ed 100644
--- a/lib/ui/painting/canvas.cc
+++ b/lib/ui/painting/canvas.cc
@@ -292,10 +292,11 @@
const PaintData& paint_data) {
if (!canvas_)
return;
- if (!image)
+ if (!image) {
Dart_ThrowException(
ToDart("Canvas.drawImage called with non-genuine Image."));
- external_allocation_size_ += image->GetAllocationSize();
+ return;
+ }
canvas_->drawImage(image->image(), x, y, paint.paint());
}
@@ -317,7 +318,6 @@
ToDart("Canvas.drawImageRect called with non-genuine Image."));
SkRect src = SkRect::MakeLTRB(src_left, src_top, src_right, src_bottom);
SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
- external_allocation_size_ += image->GetAllocationSize();
canvas_->drawImageRect(image->image(), src, dst, paint.paint(),
SkCanvas::kFast_SrcRectConstraint);
}
@@ -343,7 +343,6 @@
SkIRect icenter;
center.round(&icenter);
SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
- external_allocation_size_ += image->GetAllocationSize();
canvas_->drawImageNine(image->image(), icenter, dst, paint.paint());
}
diff --git a/shell/platform/android/android_surface_gl.cc b/shell/platform/android/android_surface_gl.cc
index c8cc3d2..2f93033 100644
--- a/shell/platform/android/android_surface_gl.cc
+++ b/shell/platform/android/android_surface_gl.cc
@@ -35,7 +35,11 @@
AndroidSurfaceGL::~AndroidSurfaceGL() = default;
void AndroidSurfaceGL::TeardownOnScreenContext() {
+ // When the onscreen surface is destroyed, the context and the surface
+ // instance should be deleted. Issue:
+ // https://github.com/flutter/flutter/issues/64414
android_context_->ClearCurrent();
+ onscreen_surface_ = nullptr;
}
bool AndroidSurfaceGL::IsValid() const {
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
index e49e0fa..fdfcd6f 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
@@ -107,6 +107,10 @@
flutter_view_controller_.reset([flutter_view_controller retain]);
}
+UIViewController* FlutterPlatformViewsController::getFlutterViewController() {
+ return flutter_view_controller_.get();
+}
+
void FlutterPlatformViewsController::OnMethodCall(FlutterMethodCall* call, FlutterResult& result) {
if ([[call method] isEqualToString:@"create"]) {
OnCreate(call, result);
@@ -161,7 +165,7 @@
FlutterTouchInterceptingView* touch_interceptor = [[[FlutterTouchInterceptingView alloc]
initWithEmbeddedView:embedded_view.view
- flutterViewController:flutter_view_controller_.get()
+ platformViewsController:GetWeakPtr()
gestureRecognizersBlockingPolicy:gesture_recognizers_blocking_policies[viewType]]
autorelease];
@@ -701,7 +705,8 @@
// directly to the FlutterView.
@interface ForwardingGestureRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate>
- (instancetype)initWithTarget:(id)target
- flutterViewController:(UIViewController*)flutterViewController;
+ platformViewsController:
+ (fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController;
@end
@implementation FlutterTouchInterceptingView {
@@ -709,7 +714,8 @@
FlutterPlatformViewGestureRecognizersBlockingPolicy _blockingPolicy;
}
- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
- flutterViewController:(UIViewController*)flutterViewController
+ platformViewsController:
+ (fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController
gestureRecognizersBlockingPolicy:
(FlutterPlatformViewGestureRecognizersBlockingPolicy)blockingPolicy {
self = [super initWithFrame:embeddedView.frame];
@@ -720,9 +726,9 @@
[self addSubview:embeddedView];
- ForwardingGestureRecognizer* forwardingRecognizer =
- [[[ForwardingGestureRecognizer alloc] initWithTarget:self
- flutterViewController:flutterViewController] autorelease];
+ ForwardingGestureRecognizer* forwardingRecognizer = [[[ForwardingGestureRecognizer alloc]
+ initWithTarget:self
+ platformViewsController:std::move(platformViewsController)] autorelease];
_delayingRecognizer.reset([[DelayingGestureRecognizer alloc]
initWithTarget:self
@@ -833,39 +839,42 @@
@end
@implementation ForwardingGestureRecognizer {
- // We can't dispatch events to the framework without this back pointer.
- // This is a weak reference, the ForwardingGestureRecognizer is owned by the
- // FlutterTouchInterceptingView which is strong referenced only by the FlutterView,
- // which is strongly referenced by the FlutterViewController.
- // So this is safe as when FlutterView is deallocated the reference to ForwardingGestureRecognizer
- // will go away.
- UIViewController* _flutterViewController;
+ // Weak reference to FlutterPlatformViewsController. The FlutterPlatformViewsController has
+ // a reference to the FlutterViewController, where we can dispatch pointer events to.
+ //
+ // The lifecycle of FlutterPlatformViewsController is bind to FlutterEngine, which should always
+ // outlives the FlutterViewController. And ForwardingGestureRecognizer is owned by a subview of
+ // FlutterView, so the ForwardingGestureRecognizer never out lives FlutterViewController.
+ // Therefore, `_platformViewsController` should never be nullptr.
+ fml::WeakPtr<flutter::FlutterPlatformViewsController> _platformViewsController;
// Counting the pointers that has started in one touch sequence.
NSInteger _currentTouchPointersCount;
}
- (instancetype)initWithTarget:(id)target
- flutterViewController:(UIViewController*)flutterViewController {
+ platformViewsController:
+ (fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController {
self = [super initWithTarget:target action:nil];
if (self) {
self.delegate = self;
- _flutterViewController = flutterViewController;
+ FML_DCHECK(platformViewsController.get() != nullptr);
+ _platformViewsController = std::move(platformViewsController);
_currentTouchPointersCount = 0;
}
return self;
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
- [_flutterViewController touchesBegan:touches withEvent:event];
+ [_platformViewsController.get()->getFlutterViewController() touchesBegan:touches withEvent:event];
_currentTouchPointersCount += touches.count;
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
- [_flutterViewController touchesMoved:touches withEvent:event];
+ [_platformViewsController.get()->getFlutterViewController() touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
- [_flutterViewController touchesEnded:touches withEvent:event];
+ [_platformViewsController.get()->getFlutterViewController() touchesEnded:touches withEvent:event];
_currentTouchPointersCount -= touches.count;
// Touches in one touch sequence are sent to the touchesEnded method separately if different
// fingers stop touching the screen at different time. So one touchesEnded method triggering does
@@ -877,7 +886,8 @@
}
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
- [_flutterViewController touchesCancelled:touches withEvent:event];
+ [_platformViewsController.get()->getFlutterViewController() touchesCancelled:touches
+ withEvent:event];
_currentTouchPointersCount = 0;
self.state = UIGestureRecognizerStateFailed;
}
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm
index 0e8397e..39d6b98 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm
@@ -7,7 +7,9 @@
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h"
+#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
+#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
#import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
#import "third_party/ocmock/Source/OCMock/OCMock.h"
@@ -508,6 +510,70 @@
flutterPlatformViewsController->Reset();
}
+- (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents {
+ flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
+ auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
+ flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
+ /*platform=*/thread_task_runner,
+ /*raster=*/thread_task_runner,
+ /*ui=*/thread_task_runner,
+ /*io=*/thread_task_runner);
+ auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
+ /*delegate=*/mock_delegate,
+ /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
+ /*task_runners=*/runners);
+
+ auto flutterPlatformViewsController = std::make_unique<flutter::FlutterPlatformViewsController>();
+
+ FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
+ [[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease];
+ flutterPlatformViewsController->RegisterViewFactory(
+ factory, @"MockFlutterPlatformView",
+ FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
+ FlutterResult result = ^(id result) {
+ };
+ flutterPlatformViewsController->OnMethodCall(
+ [FlutterMethodCall
+ methodCallWithMethodName:@"create"
+ arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
+ result);
+
+ XCTAssertNotNil(gMockPlatformView);
+
+ // Find touch inteceptor view
+ UIView* touchInteceptorView = gMockPlatformView;
+ while (touchInteceptorView != nil &&
+ ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
+ touchInteceptorView = touchInteceptorView.superview;
+ }
+ XCTAssertNotNil(touchInteceptorView);
+
+ // Find ForwardGestureRecognizer
+ UIGestureRecognizer* forwardGectureRecognizer = nil;
+ for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) {
+ if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) {
+ forwardGectureRecognizer = gestureRecognizer;
+ break;
+ }
+ }
+
+ // Before setting flutter view controller, events are not dispatched.
+ NSSet* touches1 = OCMClassMock([NSSet class]);
+ UIEvent* event1 = OCMClassMock([UIEvent class]);
+ UIViewController* mockFlutterViewContoller = OCMClassMock([UIViewController class]);
+ [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
+ OCMReject([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]);
+
+ // Set flutter view controller allows events to be dispatched.
+ NSSet* touches2 = OCMClassMock([NSSet class]);
+ UIEvent* event2 = OCMClassMock([UIEvent class]);
+ flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
+ [forwardGectureRecognizer touchesBegan:touches2 withEvent:event2];
+ OCMVerify([mockFlutterViewContoller touchesBegan:touches2 withEvent:event2]);
+
+ flutterPlatformViewsController->Reset();
+}
+
- (int)alphaOfPoint:(CGPoint)point onView:(UIView*)view {
unsigned char pixel[4] = {0};
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h
index 796d1e5..2364da2 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h
@@ -16,6 +16,8 @@
#include "flutter/shell/platform/darwin/ios/ios_context.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
+@class FlutterTouchInterceptingView;
+
// A UIView that acts as a clipping mask for the |ChildClippingView|.
//
// On the [UIView drawRect:] method, this view performs a series of clipping operations and sets the
@@ -43,24 +45,6 @@
@end
-// A UIView that is used as the parent for embedded UIViews.
-//
-// This view has 2 roles:
-// 1. Delay or prevent touch events from arriving the embedded view.
-// 2. Dispatching all events that are hittested to the embedded view to the FlutterView.
-@interface FlutterTouchInterceptingView : UIView
-- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
- flutterViewController:(UIViewController*)flutterViewController
- gestureRecognizersBlockingPolicy:
- (FlutterPlatformViewGestureRecognizersBlockingPolicy)blockingPolicy;
-
-// Stop delaying any active touch sequence (and let it arrive the embedded view).
-- (void)releaseGesture;
-
-// Prevent the touch sequence from ever arriving to the embedded view.
-- (void)blockGesture;
-@end
-
// The parent view handles clipping to its subviews.
@interface ChildClippingView : UIView
@@ -143,10 +127,14 @@
~FlutterPlatformViewsController();
+ fml::WeakPtr<flutter::FlutterPlatformViewsController> GetWeakPtr();
+
void SetFlutterView(UIView* flutter_view);
void SetFlutterViewController(UIViewController* flutter_view_controller);
+ UIViewController* getFlutterViewController();
+
void RegisterViewFactory(
NSObject<FlutterPlatformViewFactory>* factory,
NSString* factoryId,
@@ -255,6 +243,8 @@
std::map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>
gesture_recognizers_blocking_policies;
+ std::unique_ptr<fml::WeakPtrFactory<FlutterPlatformViewsController>> weak_factory_;
+
void OnCreate(FlutterMethodCall* call, FlutterResult& result);
void OnDispose(FlutterMethodCall* call, FlutterResult& result);
void OnAcceptGesture(FlutterMethodCall* call, FlutterResult& result);
@@ -313,4 +303,23 @@
} // namespace flutter
+// A UIView that is used as the parent for embedded UIViews.
+//
+// This view has 2 roles:
+// 1. Delay or prevent touch events from arriving the embedded view.
+// 2. Dispatching all events that are hittested to the embedded view to the FlutterView.
+@interface FlutterTouchInterceptingView : UIView
+- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
+ platformViewsController:
+ (fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController
+ gestureRecognizersBlockingPolicy:
+ (FlutterPlatformViewGestureRecognizersBlockingPolicy)blockingPolicy;
+
+// Stop delaying any active touch sequence (and let it arrive the embedded view).
+- (void)releaseGesture;
+
+// Prevent the touch sequence from ever arriving to the embedded view.
+- (void)blockGesture;
+@end
+
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm
index 5e9ed80..0179deb 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm
@@ -24,10 +24,15 @@
FlutterPlatformViewLayer::~FlutterPlatformViewLayer() = default;
FlutterPlatformViewsController::FlutterPlatformViewsController()
- : layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()){};
+ : layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()),
+ weak_factory_(std::make_unique<fml::WeakPtrFactory<FlutterPlatformViewsController>>(this)){};
FlutterPlatformViewsController::~FlutterPlatformViewsController() = default;
+fml::WeakPtr<flutter::FlutterPlatformViewsController> FlutterPlatformViewsController::GetWeakPtr() {
+ return weak_factory_->GetWeakPtr();
+}
+
CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix) {
// Skia only supports 2D transform so we don't map z.
CATransform3D transform = CATransform3DIdentity;
diff --git a/testing/dart/canvas_test.dart b/testing/dart/canvas_test.dart
index 7bf5072..57ad280 100644
--- a/testing/dart/canvas_test.dart
+++ b/testing/dart/canvas_test.dart
@@ -218,34 +218,6 @@
expect(areEqual, true);
}, skip: !Platform.isLinux); // https://github.com/flutter/flutter/issues/53784
- test('Image size reflected in picture size for image*, drawAtlas, and drawPicture methods', () async {
- final Image image = await createImage(100, 100);
- final PictureRecorder recorder = PictureRecorder();
- final Canvas canvas = Canvas(recorder);
- const Rect rect = Rect.fromLTWH(0, 0, 100, 100);
- canvas.drawImage(image, Offset.zero, Paint());
- canvas.drawImageRect(image, rect, rect, Paint());
- canvas.drawImageNine(image, rect, rect, Paint());
- canvas.drawAtlas(image, <RSTransform>[], <Rect>[], <Color>[], BlendMode.src, rect, Paint());
- final Picture picture = recorder.endRecording();
-
- // Some of the numbers here appear to utilize sharing/reuse of common items,
- // e.g. of the Paint() or same `Rect` usage, etc.
- // The raw utilization of a 100x100 picture here should be 53333:
- // 100 * 100 * 4 * (4/3) = 53333.333333....
- // To avoid platform specific idiosyncrasies and brittleness against changes
- // to Skia, we just assert this is _at least_ 4x the image size.
- const int minimumExpected = 53333 * 4;
- expect(picture.approximateBytesUsed, greaterThan(minimumExpected));
-
- final PictureRecorder recorder2 = PictureRecorder();
- final Canvas canvas2 = Canvas(recorder2);
- canvas2.drawPicture(picture);
- final Picture picture2 = recorder2.endRecording();
-
- expect(picture2.approximateBytesUsed, greaterThan(minimumExpected));
- });
-
test('Vertex buffer size reflected in picture size for drawVertices', () async {
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);