For consistency with Flutter (and all other platforms), Flutter views in the macOS embedder set `isFlipped` to ensure a co-ordinate system with the origin in the top-left, with y co-ordinates increasing towards the bottom edge of the view.
Previously, we were using a stock NSView as the container, which uses a bottom-left origin by default. Instead we extract the PlatformView container view as its own class with `isFlipped` true.
This doesn't correct the issue of the view anchorpoint/position but does correct rotation direction.
This also applies the transform back to origin prior to other transforms when adjusting the platformview position rather than after.
Issue: https://github.com/flutter/flutter/issues/124490
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
On some Samsung devices Flutter with spell-check enabled will crash when typing/moving near the ">" character.
Stack trace is
```
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.textservice.SentenceSuggestionsInfo.getSuggestionsCount()' on a null object reference
at io.flutter.plugin.editing.SpellCheckPlugin.onGetSentenceSuggestions(SpellCheckPlugin.java:26)
at android.view.textservice.SpellCheckerSession.lambda$handleOnGetSentenceSuggestionsMultiple$1$android-view-textservice-SpellCheckerSession(SpellCheckerSession.java:224)
at android.view.textservice.SpellCheckerSession$$ExternalSyntheticLambda0.run(:4)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8747)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
```
This test sometimes caused assertion failures when running on Windows with ANGLE. The process may be unable to safely clean up global objects if GL commands are pending when the test exits.
Empty SkRect needs to be created with `SkRect::MakeEmpty()` otherwise the default value is undefined (and possibly garbage).
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
## Description
This reverts commit 879917b to re-land #40542 to fix the lint warning which caused the original PR to be reverted (the lint warnings were turned on after the original was landed, which is why it wasn't caught earlier).
This extracts an extra method from `[FlutterMutatorView applyFlutterLayer:]` to perform the final PlatformViewContainer and PlatformView re-nesting in the view stack, then apply transforms, and finally apply the outer axis-aligned master clip rect around the whole thing.
This is a refactoring for readability (primarily clearer parameterisation) and applies no semantic changes to the code. This is the last in a series of refactoring applied to this method.
Issue: https://github.com/flutter/flutter/issues/124490
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Wide gamut is not supported on the iOS simulator, and the iOS platform's FlutterView.isWideGamutSupported checked for this. However, the ImageDecoder decides whether to enable wide gamut based on the engine's settings, so the flag in the settings needs to be modified for the simulator.
This PR adapts `FlutterThreadSynchronizer` to multi-view.
### Problem
The `FlutterThreadSynchronizer` is a macOS engine class to ensure that, if the current window is resized, nothing will not be presented until the layer tree is drawn with the up-to-date size.
This class is not compatible with multiview. A simple way to realize it is: while the class is owned by `FlutterView`, it blocks the _global_ platform thread and rasterizer thread - there is got to be some problems. Indeed, when I was testing with multiple windows (https://github.com/flutter/engine/pull/40399), the app freezes as soon as I resize a window.
The problem is because Flutter only have one rasterizer thread. When I'm resizing window A, A's synchronizer detects that the size mismatches, so it blocks the rasterizer thread to wait for an updated content with the updated size. However, window B is to be rendered next, and B's size matches and will try to rasterize, and will be blocked due to the blocked rasterizer thread, window A's updated content will never arrive, causing a deadlock.
### Changes
This PR removes the single-view assumption of `FlutterThreadSynchronizer` by making it created by `FlutterEngine` and shared by all `FlutterView`s, and that it prevents rasterization for all views if any view has a mismatched size.
The synchronizer is assigned to the view controller in the `attachToEngine:withId` method (now renamed to `setUpWithEngine:viewId:threadSynchronizer:`.
This PR also adds unit tests for `FlutterThreadSynchronizer`, which didn't have any unit tests at all.
* To achieve this, the `beginResizeForView:` method no longer checks whether is called on the main thread, but whether it's called on the main queue. These are equivalent for the real main queue, since the documentation promises that the main queue always executes on the main thread. However, this change allows substituting the queue with a custom one for unit tests.
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This PR removes the methods in `FlutterRenderer` that will never be
used.
These methods allows the engine to get a drawable and present a
drawable, but they will never be called on the macOS embedder. This is
because they go through the `FlutterMetalRendererConfig` struct to
`GPUSurfaceMetalSkia`, which is bypassed if the engine has a non-null
external view embedder, which the macOS always provides.
Removing these methods not only cleans up the code (and the confusion),
but also reduces the methods that might need to be migrated for the
multi-view project.
After this change, `FlutterRenderer` is left with very few
functionalities:
* It hosts `device` and `commandQueue`.
* It creates `FlutterRendererConfig`.
* It implements `FlutterTextureRegistry` and
`FlutterTextureRegistrarDelegate`, linking `FlutterTexture` and
`FlutterTextureRegistrar`.
We might want to refactor this class, but that's for the future.
## Pre-launch Checklist
- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I added new tests to check the change I am making or feature I am
adding, or Hixie said the PR is test-exempt. See [testing the engine]
for instructions on writing and running engine tests.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I signed the [CLA].
- [ ] All existing and new tests are passing.
If you need help, consider asking for advice on the #hackers-new channel
on [Discord].
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[C++, Objective-C, Java style guides]:
https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
[testing the engine]:
https://github.com/flutter/flutter/wiki/Testing-the-engine
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
Many parts of the floating cursor selection feature is pretty tricky. Some took me a while to figure out. So I added some comments to explain a bit for future readers.
*List which issues are fixed by this PR. You must list at least one issue.*
https://github.com/flutter/flutter/issues/30476
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
## Description
This PR updates `BasicMessageChannel.resizeChannelBuffer` implementation. Previous implementation builds a wrong `ByteBuffer` and was not tested so it is difficult to know when it stopped working.
## Related Issue
Fixes https://github.com/flutter/flutter/issues/126632
## Tests
Adds 1 test.
Fixes https://github.com/flutter/flutter/issues/101569
This block of code was originally introduced in https://github.com/flutter/engine/pull/15560 , but removing it does not have any affect on the software text editing controls in GBoard.
Before this change
* shift + arrow right/left selection would collapse after releasing the shift key.
* shift + mouse click to expand selection would collapse after releasing the shift key.
After this change
* shift key up no longer collapses the selection.
Similar to https://github.com/flutter/engine/pull/41733 and
https://github.com/flutter/engine/pull/41782, this causes the macos
embedding to wait until it hears that the scheduler binding has
registered itself before proceeding to send termination requests to the
framework.
This allows applications that don't use the framework (just use
`dart:ui` directly) to exit automatically when the last window is
closed. Without this change, the last window closes, but the app does
not exit.
Depends on framework PR https://github.com/flutter/flutter/pull/126075
landing first.
This change adds a C++ client wrapper to Windows's "force redraw" C API. This API can be used to schedule a frame.
Part of https://github.com/flutter/flutter/issues/119415
## Background
The Windows runner has a race at startup:
1. **Platform thread**: creates a hidden window
2. **Platform thread**: launches the Flutter engine
3. **UI/Raster threads**: renders the first frame
4. **Platform thread**: Registers a callback to show the window once the next frame has been rendered.
Steps 3 and 4 happen in parallel and it is possible for step 3 to complete before step 4 starts. In this scenario, the next frame callback is never called and the window is never shown.
The Windows runner will be updated to call the "force redraw" API after it registers the next frame callback. If step 3 hasn't completed yet, the "force redraw" will no-op as a frame is already scheduled. If step 3 has already completed, the "force redraw" will schedule another frame, which will call the next frame callback and show the window.
See this discussion below on why we cannot avoid changing the Windows runner to fix this issue: https://github.com/flutter/engine/pull/42061#issuecomment-1550080722
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
A mistake was introduced in https://github.com/flutter/engine/pull/39498 where the maskViews are already recycles each frame.
Sometimes a PlatformView does not need to be re-composite: (https://github.com/flutter/engine/blob/main/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm#L398-L401), so the mask view for such PlatformView should not be recycled.
This PR changed the `recycleMaskViews` API to allow individual maskviews to be recycled. `ApplyMutator` then only recycle the maskView for that particular PlatformView.
The MaskViewPool is also reworked to be simpler.
- The pool now contains a single set of mask views, there is no index counter needed.
- When a maskView is needed, try to get it from the pool.
- If pool is empty, create a new view.
- If pool has an available maskview, remove it from the pool.
- When a PlatformView starts to `applyMutator`, it removes current the maskView, insert the maskView to the pool.
- When the above PlatformView needs to a maskView, it grabs one from the pool.
fixes: https://github.com/flutter/flutter/issues/125620
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style