Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 5339297

Browse files
[web:multiview] Only call Renderer.clearFragmentProgramCache on hot restart (#48758)
Previously, we would do this any time a view was disposed, which would clear ALL fragment programs in the app, not just the ones associated with the view. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] 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 [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [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
1 parent c9ef04b commit 5339297

File tree

6 files changed

+81
-46
lines changed

6 files changed

+81
-46
lines changed

lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,7 @@ class HtmlViewEmbedder {
440440
sceneHost.insertBefore(platformViewRoot, elementToInsertBefore);
441441
final RenderCanvas? overlay = _overlays[viewId];
442442
if (overlay != null) {
443-
sceneHost.insertBefore(
444-
overlay.htmlElement, elementToInsertBefore);
443+
sceneHost.insertBefore(overlay.htmlElement, elementToInsertBefore);
445444
}
446445
} else {
447446
final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
@@ -651,6 +650,8 @@ class HtmlViewEmbedder {
651650
}
652651
}
653652
_svgClipDefs.clear();
653+
_svgPathDefs?.remove();
654+
_svgPathDefs = null;
654655
}
655656

656657
static void removeElement(DomElement element) {

lib/web_ui/lib/src/engine/canvaskit/renderer.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class CanvasKitRenderer implements Renderer {
8585
viewManager.onViewDisposed.listen(_onViewDisposed);
8686
_instance = this;
8787
}();
88+
registerHotRestartListener(dispose);
8889
return _initialized;
8990
}
9091

@@ -451,6 +452,7 @@ class CanvasKitRenderer implements Renderer {
451452
rasterizer.dispose();
452453
}
453454
_rasterizers.clear();
455+
clearFragmentProgramCache();
454456
}
455457

456458
@override

lib/web_ui/lib/src/engine/html/renderer.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class HtmlRenderer implements Renderer {
3131
// to make the unpacking happen while we are waiting for network requests.
3232
lineLookup;
3333
});
34+
registerHotRestartListener(clearFragmentProgramCache);
3435

3536
_instance = this;
3637
}

lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ class SkwasmRenderer implements Renderer {
349349
FutureOr<void> initialize() {
350350
surface = SkwasmSurface();
351351
sceneView = EngineSceneView(SkwasmPictureRenderer(surface));
352+
registerHotRestartListener(clearFragmentProgramCache);
352353
}
353354

354355
@override

lib/web_ui/lib/src/engine/window.dart

Lines changed: 66 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:meta/meta.dart';
99
import 'package:ui/ui.dart' as ui;
1010
import 'package:ui/ui_web/src/ui_web.dart' as ui_web;
1111

12-
import '../engine.dart' show DimensionsProvider, registerHotRestartListener, renderer;
12+
import '../engine.dart' show DimensionsProvider, registerHotRestartListener;
1313
import 'browser_detection.dart';
1414
import 'display.dart';
1515
import 'dom.dart';
@@ -59,7 +59,8 @@ base class EngineFlutterView implements ui.FlutterView {
5959
// by the public `EngineFlutterView` constructor).
6060
DomElement? hostElement,
6161
) : embeddingStrategy = EmbeddingStrategy.create(hostElement: hostElement),
62-
dimensionsProvider = DimensionsProvider.create(hostElement: hostElement) {
62+
dimensionsProvider =
63+
DimensionsProvider.create(hostElement: hostElement) {
6364
// The embeddingStrategy will take care of cleaning up the rootElement on
6465
// hot restart.
6566
embeddingStrategy.attachViewRoot(dom.rootElement);
@@ -71,7 +72,8 @@ base class EngineFlutterView implements ui.FlutterView {
7172
static EngineFlutterWindow implicit(
7273
EnginePlatformDispatcher platformDispatcher,
7374
DomElement? hostElement,
74-
) => EngineFlutterWindow._(platformDispatcher, hostElement);
75+
) =>
76+
EngineFlutterWindow._(platformDispatcher, hostElement);
7577

7678
@override
7779
final int viewId;
@@ -101,8 +103,6 @@ base class EngineFlutterView implements ui.FlutterView {
101103
dimensionsProvider.close();
102104
pointerBinding.dispose();
103105
dom.rootElement.remove();
104-
// TODO(harryterkelsen): What should we do about this in multi-view?
105-
renderer.clearFragmentProgramCache();
106106
semantics.reset();
107107
}
108108

@@ -115,7 +115,8 @@ base class EngineFlutterView implements ui.FlutterView {
115115

116116
@override
117117
void updateSemantics(ui.SemanticsUpdate update) {
118-
assert(!isDisposed, 'Trying to update semantics on a disposed EngineFlutterView.');
118+
assert(!isDisposed,
119+
'Trying to update semantics on a disposed EngineFlutterView.');
119120
semantics.updateSemantics(update);
120121
}
121122

@@ -128,7 +129,8 @@ base class EngineFlutterView implements ui.FlutterView {
128129

129130
late final ContextMenu contextMenu = ContextMenu(dom.rootElement);
130131

131-
late final DomManager dom = DomManager(viewId: viewId, devicePixelRatio: devicePixelRatio);
132+
late final DomManager dom =
133+
DomManager(viewId: viewId, devicePixelRatio: devicePixelRatio);
132134

133135
late final PlatformViewMessageHandler platformViewMessageHandler =
134136
PlatformViewMessageHandler(platformViewsContainer: dom.platformViewsHost);
@@ -137,9 +139,11 @@ base class EngineFlutterView implements ui.FlutterView {
137139

138140
// TODO(goderbauer): Provide API to configure constraints. See also TODO in "render".
139141
@override
140-
ViewConstraints get physicalConstraints => ViewConstraints.tight(physicalSize);
142+
ViewConstraints get physicalConstraints =>
143+
ViewConstraints.tight(physicalSize);
141144

142-
late final EngineSemanticsOwner semantics = EngineSemanticsOwner(dom.semanticsHost);
145+
late final EngineSemanticsOwner semantics =
146+
EngineSemanticsOwner(dom.semanticsHost);
143147

144148
@override
145149
ui.Size get physicalSize {
@@ -188,7 +192,8 @@ base class EngineFlutterView implements ui.FlutterView {
188192
ui.GestureSettings get gestureSettings => _viewConfiguration.gestureSettings;
189193

190194
@override
191-
List<ui.DisplayFeature> get displayFeatures => _viewConfiguration.displayFeatures;
195+
List<ui.DisplayFeature> get displayFeatures =>
196+
_viewConfiguration.displayFeatures;
192197

193198
@override
194199
EngineFlutterDisplay get display => EngineFlutterDisplay.instance;
@@ -244,11 +249,14 @@ base class EngineFlutterView implements ui.FlutterView {
244249
// Return false if the previous dimensions are not set.
245250
if (_physicalSize != null) {
246251
// First confirm both height and width are effected.
247-
if (_physicalSize!.height != newPhysicalSize.height && _physicalSize!.width != newPhysicalSize.width) {
252+
if (_physicalSize!.height != newPhysicalSize.height &&
253+
_physicalSize!.width != newPhysicalSize.width) {
248254
// If prior to rotation height is bigger than width it should be the
249255
// opposite after the rotation and vice versa.
250-
if ((_physicalSize!.height > _physicalSize!.width && newPhysicalSize.height < newPhysicalSize.width) ||
251-
(_physicalSize!.width > _physicalSize!.height && newPhysicalSize.width < newPhysicalSize.height)) {
256+
if ((_physicalSize!.height > _physicalSize!.width &&
257+
newPhysicalSize.height < newPhysicalSize.width) ||
258+
(_physicalSize!.width > _physicalSize!.height &&
259+
newPhysicalSize.width < newPhysicalSize.height)) {
252260
// Rotation detected
253261
return true;
254262
}
@@ -273,7 +281,8 @@ final class _EngineFlutterViewImpl extends EngineFlutterView {
273281
}
274282

275283
/// The Web implementation of [ui.SingletonFlutterWindow].
276-
final class EngineFlutterWindow extends EngineFlutterView implements ui.SingletonFlutterWindow {
284+
final class EngineFlutterWindow extends EngineFlutterView
285+
implements ui.SingletonFlutterWindow {
277286
EngineFlutterWindow._(
278287
EnginePlatformDispatcher platformDispatcher,
279288
DomElement? hostElement,
@@ -320,7 +329,8 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
320329
double get textScaleFactor => platformDispatcher.textScaleFactor;
321330

322331
@override
323-
bool get nativeSpellCheckServiceDefined => platformDispatcher.nativeSpellCheckServiceDefined;
332+
bool get nativeSpellCheckServiceDefined =>
333+
platformDispatcher.nativeSpellCheckServiceDefined;
324334

325335
@override
326336
bool get brieflyShowPassword => platformDispatcher.brieflyShowPassword;
@@ -329,7 +339,8 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
329339
bool get alwaysUse24HourFormat => platformDispatcher.alwaysUse24HourFormat;
330340

331341
@override
332-
ui.VoidCallback? get onTextScaleFactorChanged => platformDispatcher.onTextScaleFactorChanged;
342+
ui.VoidCallback? get onTextScaleFactorChanged =>
343+
platformDispatcher.onTextScaleFactorChanged;
333344
@override
334345
set onTextScaleFactorChanged(ui.VoidCallback? callback) {
335346
platformDispatcher.onTextScaleFactorChanged = callback;
@@ -339,7 +350,8 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
339350
ui.Brightness get platformBrightness => platformDispatcher.platformBrightness;
340351

341352
@override
342-
ui.VoidCallback? get onPlatformBrightnessChanged => platformDispatcher.onPlatformBrightnessChanged;
353+
ui.VoidCallback? get onPlatformBrightnessChanged =>
354+
platformDispatcher.onPlatformBrightnessChanged;
343355
@override
344356
set onPlatformBrightnessChanged(ui.VoidCallback? callback) {
345357
platformDispatcher.onPlatformBrightnessChanged = callback;
@@ -349,7 +361,8 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
349361
String? get systemFontFamily => platformDispatcher.systemFontFamily;
350362

351363
@override
352-
ui.VoidCallback? get onSystemFontFamilyChanged => platformDispatcher.onSystemFontFamilyChanged;
364+
ui.VoidCallback? get onSystemFontFamilyChanged =>
365+
platformDispatcher.onSystemFontFamilyChanged;
353366
@override
354367
set onSystemFontFamilyChanged(ui.VoidCallback? callback) {
355368
platformDispatcher.onSystemFontFamilyChanged = callback;
@@ -377,7 +390,8 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
377390
}
378391

379392
@override
380-
ui.PointerDataPacketCallback? get onPointerDataPacket => platformDispatcher.onPointerDataPacket;
393+
ui.PointerDataPacketCallback? get onPointerDataPacket =>
394+
platformDispatcher.onPointerDataPacket;
381395
@override
382396
set onPointerDataPacket(ui.PointerDataPacketCallback? callback) {
383397
platformDispatcher.onPointerDataPacket = callback;
@@ -400,7 +414,8 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
400414
bool get semanticsEnabled => platformDispatcher.semanticsEnabled;
401415

402416
@override
403-
ui.VoidCallback? get onSemanticsEnabledChanged => platformDispatcher.onSemanticsEnabledChanged;
417+
ui.VoidCallback? get onSemanticsEnabledChanged =>
418+
platformDispatcher.onSemanticsEnabledChanged;
404419
@override
405420
set onSemanticsEnabledChanged(ui.VoidCallback? callback) {
406421
platformDispatcher.onSemanticsEnabledChanged = callback;
@@ -415,7 +430,8 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
415430
set onFrameDataChanged(ui.VoidCallback? callback) {}
416431

417432
@override
418-
ui.AccessibilityFeatures get accessibilityFeatures => platformDispatcher.accessibilityFeatures;
433+
ui.AccessibilityFeatures get accessibilityFeatures =>
434+
platformDispatcher.accessibilityFeatures;
419435

420436
@override
421437
ui.VoidCallback? get onAccessibilityFeaturesChanged =>
@@ -435,14 +451,16 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
435451
}
436452

437453
@override
438-
ui.PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage;
454+
ui.PlatformMessageCallback? get onPlatformMessage =>
455+
platformDispatcher.onPlatformMessage;
439456
@override
440457
set onPlatformMessage(ui.PlatformMessageCallback? callback) {
441458
platformDispatcher.onPlatformMessage = callback;
442459
}
443460

444461
@override
445-
void setIsolateDebugName(String name) => ui.PlatformDispatcher.instance.setIsolateDebugName(name);
462+
void setIsolateDebugName(String name) =>
463+
ui.PlatformDispatcher.instance.setIsolateDebugName(name);
446464

447465
/// Handles the browser history integration to allow users to use the back
448466
/// button, etc.
@@ -548,7 +566,8 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
548566
Future<bool> handleNavigationMessage(ByteData? data) async {
549567
return _waitInTheLine(() async {
550568
final MethodCall decoded = const JSONMethodCodec().decodeMethodCall(data);
551-
final Map<String, dynamic>? arguments = decoded.arguments as Map<String, dynamic>?;
569+
final Map<String, dynamic>? arguments =
570+
decoded.arguments as Map<String, dynamic>?;
552571
switch (decoded.method) {
553572
case 'selectMultiEntryHistory':
554573
await _useMultiEntryBrowserHistory();
@@ -572,7 +591,9 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
572591
path = Uri.decodeComponent(
573592
Uri(
574593
path: uri.path.isEmpty ? '/' : uri.path,
575-
queryParameters: uri.queryParametersAll.isEmpty ? null : uri.queryParametersAll,
594+
queryParameters: uri.queryParametersAll.isEmpty
595+
? null
596+
: uri.queryParametersAll,
576597
fragment: uri.fragment.isEmpty ? null : uri.fragment,
577598
).toString(),
578599
);
@@ -648,6 +669,7 @@ EngineFlutterWindow get window {
648669
);
649670
return _window!;
650671
}
672+
651673
EngineFlutterWindow? _window;
652674

653675
/// Initializes the [window] (aka the implicit view), if it's not already
@@ -693,10 +715,10 @@ class ViewConstraints implements ui.ViewConstraints {
693715
});
694716

695717
ViewConstraints.tight(ui.Size size)
696-
: minWidth = size.width,
697-
maxWidth = size.width,
698-
minHeight = size.height,
699-
maxHeight = size.height;
718+
: minWidth = size.width,
719+
maxWidth = size.width,
720+
minHeight = size.height,
721+
maxHeight = size.height;
700722

701723
@override
702724
final double minWidth;
@@ -709,15 +731,17 @@ class ViewConstraints implements ui.ViewConstraints {
709731

710732
@override
711733
bool isSatisfiedBy(ui.Size size) {
712-
return (minWidth <= size.width) && (size.width <= maxWidth) &&
713-
(minHeight <= size.height) && (size.height <= maxHeight);
734+
return (minWidth <= size.width) &&
735+
(size.width <= maxWidth) &&
736+
(minHeight <= size.height) &&
737+
(size.height <= maxHeight);
714738
}
715739

716740
@override
717741
bool get isTight => minWidth >= maxWidth && minHeight >= maxHeight;
718742

719743
@override
720-
ViewConstraints operator/(double factor) {
744+
ViewConstraints operator /(double factor) {
721745
return ViewConstraints(
722746
minWidth: minWidth / factor,
723747
maxWidth: maxWidth / factor,
@@ -734,11 +758,11 @@ class ViewConstraints implements ui.ViewConstraints {
734758
if (other.runtimeType != runtimeType) {
735759
return false;
736760
}
737-
return other is ViewConstraints
738-
&& other.minWidth == minWidth
739-
&& other.maxWidth == maxWidth
740-
&& other.minHeight == minHeight
741-
&& other.maxHeight == maxHeight;
761+
return other is ViewConstraints &&
762+
other.minWidth == minWidth &&
763+
other.maxWidth == maxWidth &&
764+
other.minHeight == minHeight &&
765+
other.maxHeight == maxHeight;
742766
}
743767

744768
@override
@@ -749,8 +773,10 @@ class ViewConstraints implements ui.ViewConstraints {
749773
if (minWidth == double.infinity && minHeight == double.infinity) {
750774
return 'ViewConstraints(biggest)';
751775
}
752-
if (minWidth == 0 && maxWidth == double.infinity &&
753-
minHeight == 0 && maxHeight == double.infinity) {
776+
if (minWidth == 0 &&
777+
maxWidth == double.infinity &&
778+
minHeight == 0 &&
779+
maxHeight == double.infinity) {
754780
return 'ViewConstraints(unconstrained)';
755781
}
756782
String describe(double min, double max, String dim) {
@@ -759,6 +785,7 @@ class ViewConstraints implements ui.ViewConstraints {
759785
}
760786
return '${min.toStringAsFixed(1)}<=$dim<=${max.toStringAsFixed(1)}';
761787
}
788+
762789
final String width = describe(minWidth, maxWidth, 'w');
763790
final String height = describe(minHeight, maxHeight, 'h');
764791
return 'ViewConstraints($width, $height)';

lib/web_ui/test/canvaskit/embedded_views_test.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -731,12 +731,15 @@ void testMain() {
731731
await renderScene(sb.build());
732732
}
733733

734-
final DomNode skPathDefs = sceneHost.querySelector('#sk_path_defs')!;
735-
736-
expect(skPathDefs.childNodes, hasLength(0));
737-
738734
await renderTestScene();
739-
expect(skPathDefs.childNodes, hasLength(1));
735+
736+
final DomElement? skPathDefs = sceneHost.querySelector('#sk_path_defs');
737+
expect(
738+
skPathDefs,
739+
isNotNull,
740+
reason: 'Should have created SVG paths after rendering the scene',
741+
);
742+
expect(skPathDefs!.childNodes, hasLength(1));
740743

741744
await renderTestScene();
742745
expect(skPathDefs.childNodes, hasLength(1));

0 commit comments

Comments
 (0)