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

Commit 84962dc

Browse files
authored
[web] DomRenderer becomes FlutterViewEmbedder (#29994)
* [web] move useful utilities out DomRenderer * [web] rename DomRenderer to FlutterViewEmbedder
1 parent 68f9f3c commit 84962dc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+368
-446
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/viewport_metrics.dart
515515
FILE: ../../../flutter/lib/web_ui/lib/src/engine/clipboard.dart
516516
FILE: ../../../flutter/lib/web_ui/lib/src/engine/color_filter.dart
517517
FILE: ../../../flutter/lib/web_ui/lib/src/engine/configuration.dart
518-
FILE: ../../../flutter/lib/web_ui/lib/src/engine/dom_renderer.dart
518+
FILE: ../../../flutter/lib/web_ui/lib/src/engine/embedder.dart
519519
FILE: ../../../flutter/lib/web_ui/lib/src/engine/engine_canvas.dart
520520
FILE: ../../../flutter/lib/web_ui/lib/src/engine/font_change_util.dart
521521
FILE: ../../../flutter/lib/web_ui/lib/src/engine/frame_reference.dart
@@ -638,7 +638,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/ui/path_metrics.dart
638638
FILE: ../../../flutter/lib/web_ui/lib/src/ui/platform_dispatcher.dart
639639
FILE: ../../../flutter/lib/web_ui/lib/src/ui/pointer.dart
640640
FILE: ../../../flutter/lib/web_ui/lib/src/ui/semantics.dart
641-
FILE: ../../../flutter/lib/web_ui/lib/src/ui/test_embedding.dart
642641
FILE: ../../../flutter/lib/web_ui/lib/src/ui/text.dart
643642
FILE: ../../../flutter/lib/web_ui/lib/src/ui/tile_mode.dart
644643
FILE: ../../../flutter/lib/web_ui/lib/src/ui/window.dart

lib/web_ui/lib/src/engine.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import '../ui.dart' as ui;
4141

4242
// ignore: unused_import
4343
import 'engine/configuration.dart';
44-
import 'engine/dom_renderer.dart';
44+
import 'engine/embedder.dart';
4545
import 'engine/keyboard.dart';
4646
import 'engine/mouse_cursor.dart';
4747
import 'engine/navigation/js_url_strategy.dart';
@@ -130,7 +130,7 @@ export 'engine/color_filter.dart';
130130

131131
export 'engine/configuration.dart';
132132

133-
export 'engine/dom_renderer.dart';
133+
export 'engine/embedder.dart';
134134

135135
export 'engine/engine_canvas.dart';
136136

@@ -413,8 +413,8 @@ void initializeEngine() {
413413

414414
_engineInitialized = true;
415415

416-
// Initialize the DomRenderer before initializing framework bindings.
417-
ensureDomRendererInitialized();
416+
// Initialize the FlutterViewEmbedder before initializing framework bindings.
417+
ensureFlutterViewEmbedderInitialized();
418418

419419
WebExperiments.ensureInitialized();
420420

lib/web_ui/lib/src/engine/canvas_pool.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import 'package:meta/meta.dart';
1111
import 'package:ui/ui.dart' as ui;
1212

1313
import 'browser_detection.dart';
14-
import 'dom_renderer.dart';
1514
import 'engine_canvas.dart';
1615
import 'html/bitmap_canvas.dart';
1716
import 'html/painting.dart';
@@ -751,7 +750,7 @@ class CanvasPool extends _SaveStackTracking {
751750
rect.center.dx - shaderBounds.left;
752751
final double cy = shaderBounds == null ? rect.center.dy :
753752
rect.center.dy - shaderBounds.top;
754-
DomRenderer.ellipse(context, cx, cy, rect.width / 2,
753+
drawEllipse(context, cx, cy, rect.width / 2,
755754
rect.height / 2, 0, 0, 2.0 * math.pi, false);
756755
contextHandle.paint(style);
757756
}
@@ -762,7 +761,7 @@ class CanvasPool extends _SaveStackTracking {
762761
final ui.Rect? shaderBounds = contextHandle._shaderBounds;
763762
final double cx = shaderBounds == null ? c.dx : c.dx - shaderBounds.left;
764763
final double cy = shaderBounds == null ? c.dy : c.dy - shaderBounds.top;
765-
DomRenderer.ellipse(context, cx, cy, radius, radius, 0, 0, 2.0 * math.pi, false);
764+
drawEllipse(context, cx, cy, radius, radius, 0, 0, 2.0 * math.pi, false);
766765
contextHandle.paint(style);
767766
}
768767

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import 'package:js/js.dart';
1313
import '../../engine.dart' show kProfileMode;
1414
import '../browser_detection.dart';
1515
import '../configuration.dart';
16-
import '../dom_renderer.dart';
16+
import '../embedder.dart';
1717
import 'canvaskit_api.dart';
1818
import 'fonts.dart';
1919

@@ -78,7 +78,7 @@ Future<void> initializeCanvasKit({String? canvasKitBase}) {
7878

7979
/// Add a Skia scene host.
8080
skiaSceneHost = html.Element.tag('flt-scene');
81-
domRenderer.renderScene(skiaSceneHost);
81+
flutterViewEmbedder.renderScene(skiaSceneHost);
8282
return canvasKitCompleter.future;
8383
}
8484

lib/web_ui/lib/src/engine/dom_renderer.dart renamed to lib/web_ui/lib/src/engine/embedder.dart

Lines changed: 29 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,29 @@ import 'text_editing/text_editing.dart';
2121
import 'util.dart';
2222
import 'window.dart';
2323

24-
class DomRenderer {
25-
DomRenderer() {
26-
if (assertionsEnabled) {
27-
_debugFrameStatistics = DebugDomRendererFrameStatistics();
28-
}
29-
24+
/// Controls the placement and lifecycle of a Flutter view on the web page.
25+
///
26+
/// Manages several top-level elements that host Flutter-generated content,
27+
/// including:
28+
///
29+
/// - [glassPaneElement], the root element of a Flutter view.
30+
/// - [glassPaneShadow], the shadow root used to isolate Flutter-rendered
31+
/// content from the surrounding page content, including from the platform
32+
/// views.
33+
/// - [sceneElement], the element that hosts Flutter layers and pictures, and
34+
/// projects platform views.
35+
/// - [sceneHostElement], the anchor that provides a stable location in the DOM
36+
/// tree for the [sceneElement].
37+
/// - [semanticsHostElement], hosts the ARIA-annotated semantics tree.
38+
class FlutterViewEmbedder {
39+
FlutterViewEmbedder() {
3040
reset();
31-
3241
assert(() {
3342
_setupHotRestart();
3443
return true;
3544
}());
3645
}
3746

38-
static const int vibrateLongPress = 50;
39-
static const int vibrateLightImpact = 10;
40-
static const int vibrateMediumImpact = 20;
41-
static const int vibrateHeavyImpact = 30;
42-
static const int vibrateSelectionClick = 10;
43-
4447
// The tag name for the root view of the flutter app (glass-pane)
4548
static const String _glassPaneTagName = 'flt-glass-pane';
4649

@@ -175,52 +178,6 @@ class DomRenderer {
175178

176179
final html.Element rootElement = html.document.body!;
177180

178-
html.Element createElement(String tagName, {html.Element? parent}) {
179-
final html.Element element = html.document.createElement(tagName);
180-
parent?.append(element);
181-
return element;
182-
}
183-
184-
void appendText(html.Element parent, String text) {
185-
parent.appendText(text);
186-
}
187-
188-
static void setElementStyle(
189-
html.Element element, String name, String? value) {
190-
if (value == null) {
191-
element.style.removeProperty(name);
192-
} else {
193-
element.style.setProperty(name, value);
194-
}
195-
}
196-
197-
static void setClipPath(html.Element element, String? value) {
198-
if (browserEngine == BrowserEngine.webkit) {
199-
if (value == null) {
200-
element.style.removeProperty('-webkit-clip-path');
201-
} else {
202-
element.style.setProperty('-webkit-clip-path', value);
203-
}
204-
}
205-
if (value == null) {
206-
element.style.removeProperty('clip-path');
207-
} else {
208-
element.style.setProperty('clip-path', value);
209-
}
210-
}
211-
212-
void setThemeColor(ui.Color color) {
213-
html.MetaElement? theme =
214-
html.document.querySelector('#flutterweb-theme') as html.MetaElement?;
215-
if (theme == null) {
216-
theme = html.MetaElement()
217-
..id = 'flutterweb-theme'
218-
..name = 'theme-color';
219-
html.document.head!.append(theme);
220-
}
221-
theme.content = colorToCssString(color)!;
222-
}
223-
224181
static const String defaultFontStyle = 'normal';
225182
static const String defaultFontWeight = 'normal';
226183
static const double defaultFontSize = 14;
@@ -313,7 +270,7 @@ class DomRenderer {
313270
// IMPORTANT: the glass pane element must come after the scene element in the DOM node list so
314271
// it can intercept input events.
315272
_glassPaneElement?.remove();
316-
final html.Element glassPaneElement = createElement(_glassPaneTagName);
273+
final html.Element glassPaneElement = html.document.createElement(_glassPaneTagName);
317274
_glassPaneElement = glassPaneElement;
318275
glassPaneElement.style
319276
..position = 'absolute'
@@ -331,11 +288,11 @@ class DomRenderer {
331288
_glassPaneShadow = glassPaneElementHostNode;
332289

333290
// Don't allow the scene to receive pointer events.
334-
_sceneHostElement = createElement('flt-scene-host')
291+
_sceneHostElement = html.document.createElement('flt-scene-host')
335292
..style.pointerEvents = 'none';
336293

337294
final html.Element semanticsHostElement =
338-
createElement('flt-semantics-host');
295+
html.document.createElement('flt-semantics-host');
339296
semanticsHostElement.style
340297
..position = 'absolute'
341298
..transformOrigin = '0 0 0';
@@ -456,41 +413,6 @@ class DomRenderer {
456413
}
457414
}
458415

459-
/// Removes all children of a DOM node.
460-
void removeAllChildren(html.Node node) {
461-
while (node.lastChild != null) {
462-
node.lastChild!.remove();
463-
}
464-
}
465-
466-
static bool? _ellipseFeatureDetected;
467-
468-
/// Draws CanvasElement ellipse with fallback.
469-
static void ellipse(
470-
html.CanvasRenderingContext2D context,
471-
double centerX,
472-
double centerY,
473-
double radiusX,
474-
double radiusY,
475-
double rotation,
476-
double startAngle,
477-
double endAngle,
478-
bool antiClockwise) {
479-
// ignore: implicit_dynamic_function
480-
_ellipseFeatureDetected ??= js_util.getProperty(context, 'ellipse') != null;
481-
if (_ellipseFeatureDetected!) {
482-
context.ellipse(centerX, centerY, radiusX, radiusY, rotation, startAngle,
483-
endAngle, antiClockwise);
484-
} else {
485-
context.save();
486-
context.translate(centerX, centerY);
487-
context.rotate(rotation);
488-
context.scale(radiusX, radiusY);
489-
context.arc(0, 0, 1, startAngle, endAngle, antiClockwise);
490-
context.restore();
491-
}
492-
}
493-
494416
static const String orientationLockTypeAny = 'any';
495417
static const String orientationLockTypeNatural = 'natural';
496418
static const String orientationLockTypeLandscape = 'landscape';
@@ -596,44 +518,22 @@ class DomRenderer {
596518

597519
/// Removes a global resource element.
598520
void removeResource(html.Element? element) {
599-
element?.remove();
600-
}
601-
602-
/// Provides haptic feedback.
603-
void vibrate(int durationMs) {
604-
final html.Navigator navigator = html.window.navigator;
605-
if (js_util.hasProperty(navigator, 'vibrate')) {
606-
// ignore: implicit_dynamic_function
607-
js_util.callMethod(navigator, 'vibrate', <num>[durationMs]);
521+
if (element == null) {
522+
return;
608523
}
524+
assert(element.parent == _resourcesHost);
525+
element.remove();
609526
}
610527

611528
String get currentHtml => _rootApplicationElement?.outerHtml ?? '';
612-
613-
DebugDomRendererFrameStatistics? _debugFrameStatistics;
614-
615-
DebugDomRendererFrameStatistics? debugFlushFrameStatistics() {
616-
if (!assertionsEnabled) {
617-
throw Exception('This code should not be reachable in production.');
618-
}
619-
final DebugDomRendererFrameStatistics? current = _debugFrameStatistics;
620-
_debugFrameStatistics = DebugDomRendererFrameStatistics();
621-
return current;
622-
}
623-
624-
void debugRulerCacheHit() => _debugFrameStatistics!.paragraphRulerCacheHits++;
625-
void debugRulerCacheMiss() =>
626-
_debugFrameStatistics!.paragraphRulerCacheMisses++;
627-
void debugRichTextLayout() => _debugFrameStatistics!.richTextLayouts++;
628-
void debugPlainTextLayout() => _debugFrameStatistics!.plainTextLayouts++;
629529
}
630530

631531
// Applies the required global CSS to an incoming [html.CssStyleSheet] `sheet`.
632532
void applyGlobalCssRulesToSheet(
633533
html.CssStyleSheet sheet, {
634534
required BrowserEngine browserEngine,
635535
required bool hasAutofillOverlay,
636-
String glassPaneTagName = DomRenderer._glassPaneTagName,
536+
String glassPaneTagName = FlutterViewEmbedder._glassPaneTagName,
637537
}) {
638538
final bool isWebKit = browserEngine == BrowserEngine.webkit;
639539
final bool isFirefox = browserEngine == BrowserEngine.firefox;
@@ -752,48 +652,9 @@ void applyGlobalCssRulesToSheet(
752652
}
753653
}
754654

755-
/// Miscellaneous statistics collecting during a single frame's execution.
756-
///
757-
/// This is useful when profiling the app. This class should only be used when
758-
/// assertions are enabled and therefore is not suitable for collecting any
759-
/// time measurements. It is mostly useful for counting certain events.
760-
class DebugDomRendererFrameStatistics {
761-
/// The number of times we reused a previously initialized paragraph ruler to
762-
/// measure a paragraph of text.
763-
int paragraphRulerCacheHits = 0;
764-
765-
/// The number of times we had to create a new paragraph ruler to measure a
766-
/// paragraph of text.
767-
int paragraphRulerCacheMisses = 0;
768-
769-
/// The number of times we used a paragraph ruler to measure a paragraph of
770-
/// text.
771-
int get totalParagraphRulerAccesses =>
772-
paragraphRulerCacheHits + paragraphRulerCacheMisses;
773-
774-
/// The number of times a paragraph of rich text was laid out this frame.
775-
int richTextLayouts = 0;
776-
777-
/// The number of times a paragraph of plain text was laid out this frame.
778-
int plainTextLayouts = 0;
779-
780-
@override
781-
String toString() {
782-
return '''
783-
Frame statistics:
784-
Paragraph ruler cache hits: $paragraphRulerCacheHits
785-
Paragraph ruler cache misses: $paragraphRulerCacheMisses
786-
Paragraph ruler accesses: $totalParagraphRulerAccesses
787-
Rich text layouts: $richTextLayouts
788-
Plain text layouts: $plainTextLayouts
789-
'''
790-
.trim();
791-
}
792-
}
793-
794-
/// Singleton DOM renderer.
795-
DomRenderer get domRenderer => ensureDomRendererInitialized();
655+
/// The embedder singleton.
656+
FlutterViewEmbedder get flutterViewEmbedder => ensureFlutterViewEmbedderInitialized();
796657

797-
/// Initializes the [DomRenderer], if it's not already initialized.
798-
DomRenderer ensureDomRendererInitialized() => _domRenderer ??= DomRenderer();
799-
DomRenderer? _domRenderer;
658+
/// Initializes the [FlutterViewEmbedder], if it's not already initialized.
659+
FlutterViewEmbedder ensureFlutterViewEmbedderInitialized() => _flutterViewEmbedder ??= FlutterViewEmbedder();
660+
FlutterViewEmbedder? _flutterViewEmbedder;

lib/web_ui/lib/src/engine/host_node.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import 'dart:html' as html;
66

77
import 'browser_detection.dart';
8-
import 'dom_renderer.dart';
8+
import 'embedder.dart';
99
import 'text_editing/text_editing.dart';
1010

1111
/// The interface required to host a flutter app in the DOM, and its tests.

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'dart:html' as html;
77
import 'package:ui/ui.dart' as ui;
88

99
import '../browser_detection.dart';
10-
import '../dom_renderer.dart';
1110
import '../util.dart';
1211
import '../vector_math.dart';
1312
import 'shaders/shader.dart';
@@ -122,10 +121,10 @@ class PersistedBackdropFilter extends PersistedContainerSurface
122121
// Gaussian blur with standard deviation (normal distribution),
123122
// the blur will fall within 2 * sigma pixels.
124123
if (browserEngine == BrowserEngine.webkit) {
125-
DomRenderer.setElementStyle(_filterElement!, '-webkit-backdrop-filter',
124+
setElementStyle(_filterElement!, '-webkit-backdrop-filter',
126125
filter.filterAttribute);
127126
}
128-
DomRenderer.setElementStyle(_filterElement!, 'backdrop-filter', filter.filterAttribute);
127+
setElementStyle(_filterElement!, 'backdrop-filter', filter.filterAttribute);
129128
}
130129
}
131130

0 commit comments

Comments
 (0)