Skip to content

Commit 677ef98

Browse files
harryterkelsenmboetger
authored andcommitted
[web] Refactor renderers to use the same frontend code (flutter#174588)
Refactors the renderer code so both renderers (Skwasm and CanvasKit) use the same SceneBuilder and platform view embedding code. This change is discussed in a design doc here: https://flutter.dev/go/web-renderer-unification Fixes flutter#172311 Fixes flutter#172308 Fixes flutter#142072 ## 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], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent 4a3e3d4 commit 677ef98

39 files changed

+354
-3723
lines changed

engine/src/flutter/lib/web_ui/lib/src/engine.dart

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,18 @@ export 'engine/layer/layer_scene_builder.dart';
7474
export 'engine/layer/layer_tree.dart';
7575
export 'engine/layer/layer_visitor.dart';
7676
export 'engine/layer/n_way_canvas.dart';
77-
export 'engine/layers.dart';
7877
export 'engine/lazy_path.dart';
7978
export 'engine/mouse/context_menu.dart';
8079
export 'engine/mouse/cursor.dart';
8180
export 'engine/mouse/prevent_default.dart';
8281
export 'engine/navigation/history.dart';
8382
export 'engine/noto_font.dart';
8483
export 'engine/noto_font_encoding.dart';
84+
export 'engine/occlusion_map.dart';
8585
export 'engine/onscreen_logging.dart';
8686
export 'engine/platform_dispatcher.dart';
8787
export 'engine/platform_dispatcher/app_lifecycle_state.dart';
8888
export 'engine/platform_dispatcher/view_focus_binding.dart';
89-
export 'engine/platform_views.dart';
9089
export 'engine/platform_views/content_manager.dart';
9190
export 'engine/platform_views/embedder.dart';
9291
export 'engine/platform_views/message_handler.dart';
@@ -99,9 +98,6 @@ export 'engine/profiler.dart';
9998
export 'engine/raw_keyboard.dart';
10099
export 'engine/renderer.dart';
101100
export 'engine/safe_browser_api.dart';
102-
export 'engine/scene_builder.dart';
103-
export 'engine/scene_painting.dart';
104-
export 'engine/scene_view.dart';
105101
export 'engine/semantics/accessibility.dart';
106102
export 'engine/semantics/alert.dart';
107103
export 'engine/semantics/checkable.dart';

engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/image.dart

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -312,17 +312,6 @@ CkImage scaleImage(SkImage image, int? targetWidth, int? targetHeight) {
312312
return ckImage;
313313
}
314314

315-
/// Thrown when the web engine fails to decode an image, either due to a
316-
/// network issue, corrupted image contents, or missing codec.
317-
class ImageCodecException implements Exception {
318-
ImageCodecException(this._message);
319-
320-
final String _message;
321-
322-
@override
323-
String toString() => 'ImageCodecException: $_message';
324-
}
325-
326315
const String _kNetworkImageMessage = 'Failed to load network image.';
327316

328317
/// Instantiates a [ui.Codec] backed by an `SkAnimatedImage` from Skia after

engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'dart:typed_data';
77
import 'package:ui/src/engine.dart';
88
import 'package:ui/ui.dart' as ui;
99

10-
class CkPictureRecorder implements LayerPictureRecorder, ScenePictureRecorder {
10+
class CkPictureRecorder implements LayerPictureRecorder {
1111
SkPictureRecorder? _skRecorder;
1212
CkCanvas? _recordingCanvas;
1313

engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/raster_cache.dart

Lines changed: 0 additions & 52 deletions
This file was deleted.

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

Lines changed: 10 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -428,71 +428,6 @@ class CanvasKitRenderer extends Renderer {
428428
ui.ParagraphBuilder createParagraphBuilder(ui.ParagraphStyle style) =>
429429
isExperimentalWebParagraph ? WebParagraphBuilder(style) : CkParagraphBuilder(style);
430430

431-
// TODO(harryterkelsen): Merge this logic with the async logic in
432-
// [EngineScene], https://github.com/flutter/flutter/issues/142072.
433-
@override
434-
Future<void> renderScene(ui.Scene scene, EngineFlutterView view) async {
435-
assert(
436-
rasterizers.containsKey(view.viewId),
437-
"Unable to render to a view which hasn't been registered",
438-
);
439-
final ViewRasterizer rasterizer = rasterizers[view.viewId]!;
440-
final RenderQueue renderQueue = rasterizer.queue;
441-
final FrameTimingRecorder? recorder = FrameTimingRecorder.frameTimingsEnabled
442-
? FrameTimingRecorder()
443-
: null;
444-
if (renderQueue.current != null) {
445-
// If a scene is already queued up, drop it and queue this one up instead
446-
// so that the scene view always displays the most recently requested scene.
447-
renderQueue.next?.completer.complete();
448-
final Completer<void> completer = Completer<void>();
449-
renderQueue.next = (scene: scene, completer: completer, recorder: recorder);
450-
return completer.future;
451-
}
452-
final Completer<void> completer = Completer<void>();
453-
renderQueue.current = (scene: scene, completer: completer, recorder: recorder);
454-
unawaited(_kickRenderLoop(rasterizer));
455-
return completer.future;
456-
}
457-
458-
Future<void> _kickRenderLoop(ViewRasterizer rasterizer) async {
459-
final RenderQueue renderQueue = rasterizer.queue;
460-
final RenderRequest current = renderQueue.current!;
461-
try {
462-
await _renderScene(current.scene, rasterizer, current.recorder);
463-
current.completer.complete();
464-
} catch (error, stackTrace) {
465-
current.completer.completeError(error, stackTrace);
466-
}
467-
renderQueue.current = renderQueue.next;
468-
renderQueue.next = null;
469-
if (renderQueue.current == null) {
470-
return;
471-
} else {
472-
return _kickRenderLoop(rasterizer);
473-
}
474-
}
475-
476-
Future<void> _renderScene(
477-
ui.Scene scene,
478-
ViewRasterizer rasterizer,
479-
FrameTimingRecorder? recorder,
480-
) async {
481-
// "Build finish" and "raster start" happen back-to-back because we
482-
// render on the same thread, so there's no overhead from hopping to
483-
// another thread.
484-
//
485-
// CanvasKit works differently from the HTML renderer in that in HTML
486-
// we update the DOM in SceneBuilder.build, which is these function calls
487-
// here are CanvasKit-only.
488-
recorder?.recordBuildFinish();
489-
recorder?.recordRasterStart();
490-
491-
await rasterizer.draw((scene as LayerScene).layerTree, null);
492-
recorder?.recordRasterFinish();
493-
recorder?.submitTimings();
494-
}
495-
496431
@override
497432
void clearFragmentProgramCache() {
498433
_programs.clear();
@@ -535,5 +470,14 @@ class CanvasKitRenderer extends Renderer {
535470
);
536471

537472
@override
538-
void dumpDebugInfo() {}
473+
void dumpDebugInfo() {
474+
int i = 0;
475+
for (final viewRasterizer in rasterizers.values) {
476+
final Map<String, dynamic>? debugJson = viewRasterizer.dumpDebugInfo();
477+
if (debugJson != null) {
478+
downloadDebugInfo('flutter-scene$i', debugJson);
479+
i++;
480+
}
481+
}
482+
}
539483
}

engine/src/flutter/lib/web_ui/lib/src/engine/frame_service.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,8 @@ class FrameService {
162162
// In Flutter terminology "building a frame" consists of "beginning
163163
// frame" and "drawing frame".
164164
//
165-
// We do not call `recordBuildFinish` from here because
166-
// part of the rasterization process, particularly in the HTML
167-
// renderer, takes place in the `SceneBuilder.build()`.
165+
// We do not call `recordBuildFinish` from here because part of the
166+
// rasterization process takes place in `SceneBuilder.build()`.
168167
FrameTimingRecorder.recordCurrentFrameBuildStart();
169168

170169
// We have to convert high-resolution time to `int` so we can construct

engine/src/flutter/lib/web_ui/lib/src/engine/image_decoder.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,14 @@ ui.Image scaleImageIfNeeded(
267267
image.dispose();
268268
return finalImage;
269269
}
270+
271+
/// Thrown when the web engine fails to decode an image, either due to a
272+
/// network issue, corrupted image contents, or missing codec.
273+
class ImageCodecException implements Exception {
274+
ImageCodecException(this._message);
275+
276+
final String _message;
277+
278+
@override
279+
String toString() => 'ImageCodecException: $_message';
280+
}

0 commit comments

Comments
 (0)