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

Commit ba606b5

Browse files
committed
[web] Migrate Flutter Web DOM usage to JS static interop - 21.
1 parent 86cb4f0 commit ba606b5

File tree

6 files changed

+127
-40
lines changed

6 files changed

+127
-40
lines changed

lib/web_ui/lib/src/engine/dom.dart

+86-2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ extension DomDocumentExtension on DomDocument {
8080
class DomHTMLDocument extends DomDocument {}
8181

8282
extension DomHTMLDocumentExtension on DomHTMLDocument {
83+
external DomFontFaceSet? get fonts;
8384
external DomHTMLHeadElement? get head;
8485
external DomHTMLBodyElement? get body;
8586
}
@@ -168,12 +169,14 @@ extension DomElementExtension on DomElement {
168169
js_util.getProperty<List<Object?>>(this, 'children').cast<DomElement>();
169170
external String get id;
170171
external set id(String id);
172+
external set innerHtml(String? html);
171173
external String? get outerHTML;
172174
external set spellcheck(bool? value);
173175
external String get tagName;
174176
external DomCSSStyleDeclaration get style;
175177
external void append(DomNode node);
176178
external String? getAttribute(String attributeName);
179+
external DomRect getBoundingClientRect();
177180
external void prepend(DomNode node);
178181
external DomElement? querySelector(String selectors);
179182
List<DomElement> querySelectorAll(String selectors) =>
@@ -243,11 +246,14 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
243246
setProperty('background-image', value, '');
244247
set border(String value) => setProperty('border', value, '');
245248
set mixBlendMode(String value) => setProperty('mix-blend-mode', value, '');
246-
set backgroundSize(String value) =>
247-
setProperty('background-size', value, '');
249+
set backgroundSize(String value) => setProperty('background-size', value, '');
248250
set backgroundBlendMode(String value) =>
249251
setProperty('background-blend-mode', value, '');
250252
set transformStyle(String value) => setProperty('transform-style', value, '');
253+
set display(String value) => setProperty('display', value, '');
254+
set flexDirection(String value) => setProperty('flex-direction', value, '');
255+
set alignItems(String value) => setProperty('align-items', value, '');
256+
set margin(String value) => setProperty('margin', value, '');
251257
String get width => getPropertyValue('width');
252258
String get height => getPropertyValue('height');
253259
String get position => getPropertyValue('position');
@@ -298,6 +304,10 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
298304
String get backgroundSize => getPropertyValue('background-size');
299305
String get backgroundBlendMode => getPropertyValue('background-blend-mode');
300306
String get transformStyle => getPropertyValue('transform-style');
307+
String get display => getPropertyValue('display');
308+
String get flexDirection => getPropertyValue('flex-direction');
309+
String get alignItems => getPropertyValue('align-items');
310+
String get margin => getPropertyValue('margin');
301311

302312
external String getPropertyValue(String property);
303313
void setProperty(String propertyName, String value, [String? priority]) {
@@ -313,6 +323,10 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
313323
@staticInterop
314324
class DomHTMLElement extends DomElement {}
315325

326+
extension DomHTMLElementExtension on DomHTMLElement {
327+
int get offsetWidth => js_util.getProperty<num>(this, 'offsetWidth') as int;
328+
}
329+
316330
@JS()
317331
@staticInterop
318332
class DomHTMLMetaElement extends DomHTMLElement {}
@@ -369,6 +383,21 @@ class DomHTMLButtonElement extends DomHTMLElement {}
369383
DomHTMLButtonElement createDomHTMLButtonElement() =>
370384
domDocument.createElement('button') as DomHTMLButtonElement;
371385

386+
@JS()
387+
@staticInterop
388+
class DomHTMLParagraphElement extends DomHTMLElement {}
389+
390+
DomHTMLParagraphElement createDomHTMLParagraphElement() =>
391+
domDocument.createElement('p') as DomHTMLParagraphElement;
392+
393+
@JS()
394+
@staticInterop
395+
class DomHTMLStyleElement extends DomHTMLElement {}
396+
397+
extension DomHTMLStyleElementExtension on DomHTMLStyleElement {
398+
external set type(String? value);
399+
}
400+
372401
@JS()
373402
@staticInterop
374403
class DomPerformance extends DomEventTarget {}
@@ -434,6 +463,7 @@ class DomCanvasRenderingContext2D {}
434463
extension DomCanvasRenderingContext2DExtension on DomCanvasRenderingContext2D {
435464
external Object? get fillStyle;
436465
external set fillStyle(Object? style);
466+
external String get font;
437467
external set font(String value);
438468
external set lineWidth(num? value);
439469
external set strokeStyle(Object? value);
@@ -452,6 +482,7 @@ extension DomCanvasRenderingContext2DExtension on DomCanvasRenderingContext2D {
452482
<Object>[text, x, y, if (maxWidth != null) maxWidth]);
453483
external DomImageData getImageData(int x, int y, int sw, int sh);
454484
external void lineTo(num x, num y);
485+
external DomTextMetrics measureText(String text);
455486
external void moveTo(num x, num y);
456487
external void save();
457488
external void stroke();
@@ -516,6 +547,14 @@ class DomText extends DomCharacterData {}
516547

517548
DomText createDomText(String data) => domDocument.createTextNode(data);
518549

550+
@JS()
551+
@staticInterop
552+
class DomTextMetrics {}
553+
554+
extension DomTextMetricsExtension on DomTextMetrics {
555+
external num? get width;
556+
}
557+
519558
@JS()
520559
@staticInterop
521560
class DomException {
@@ -526,6 +565,51 @@ extension DomExceptionExtension on DomException {
526565
external String get name;
527566
}
528567

568+
@JS()
569+
@staticInterop
570+
class DomRectReadOnly {}
571+
572+
extension DomRectReadOnlyExtension on DomRectReadOnly {
573+
external num get x;
574+
external num get y;
575+
external num get width;
576+
external num get height;
577+
external num get top;
578+
external num get right;
579+
external num get bottom;
580+
external num get left;
581+
}
582+
583+
@JS()
584+
@staticInterop
585+
class DomRect extends DomRectReadOnly {}
586+
587+
@JS()
588+
@staticInterop
589+
class DomFontFace {}
590+
591+
DomFontFace createDomFontFace(String family, Object source,
592+
[Map<Object?, Object?>? descriptors]) =>
593+
domCallConstructorString('FontFace', <Object>[
594+
family,
595+
source,
596+
if (descriptors != null) js_util.jsify(descriptors)
597+
])! as DomFontFace;
598+
599+
extension DomFontFaceExtension on DomFontFace {
600+
Future<DomFontFace> load() =>
601+
js_util.promiseToFuture(js_util.callMethod(this, 'load', <Object>[]));
602+
}
603+
604+
@JS()
605+
@staticInterop
606+
class DomFontFaceSet extends DomEventTarget {}
607+
608+
extension DomFontFaceSetExtension on DomFontFaceSet {
609+
external DomFontFaceSet? add(DomFontFace font);
610+
external void clear();
611+
}
612+
529613
extension DomResponseExtension on DomResponse {
530614
Future<dynamic> arrayBuffer() => js_util
531615
.promiseToFuture(js_util.callMethod(this, 'arrayBuffer', <Object>[]));

lib/web_ui/lib/src/engine/svg.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import 'dom.dart';
1111
class SVGElement extends DomElement {}
1212

1313
SVGElement createSVGElement(String tag) =>
14-
domDocument.createElementNS('http://www.w3.org/2000/svg', tag) as SVGElement;
14+
domDocument.createElementNS('http://www.w3.org/2000/svg', tag)
15+
as SVGElement;
1516

1617
@JS()
1718
@staticInterop

lib/web_ui/lib/src/engine/text/font_collection.dart

+18-18
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
import 'dart:async';
66
import 'dart:convert';
7-
import 'dart:html' as html;
87
import 'dart:typed_data';
98

109
import '../assets.dart';
1110
import '../browser_detection.dart';
11+
import '../dom.dart';
1212
import '../safe_browser_api.dart';
1313
import '../util.dart';
1414
import 'layout_service.dart';
@@ -105,7 +105,7 @@ class FontCollection {
105105
_assetFontManager = null;
106106
_testFontManager = null;
107107
if (supportsFontsClearApi) {
108-
html.document.fonts!.clear();
108+
domDocument.fonts!.clear();
109109
}
110110
}
111111
}
@@ -139,27 +139,27 @@ class FontManager {
139139
/// Browsers and browsers versions differ significantly on how a valid font
140140
/// family name should be formatted. Notable issues are:
141141
///
142-
/// Safari 12 and Firefox crash if you create a [html.FontFace] with a font
142+
/// Safari 12 and Firefox crash if you create a [DomFontFace] with a font
143143
/// family that is not correct CSS syntax. Font family names with invalid
144144
/// characters are accepted accepted on these browsers, when wrapped it in
145145
/// quotes.
146146
///
147-
/// Additionally, for Safari 12 to work [html.FontFace] name should be
147+
/// Additionally, for Safari 12 to work [DomFontFace] name should be
148148
/// loaded correctly on the first try.
149149
///
150150
/// A font in Chrome is not usable other than inside a '<p>' tag, if a
151-
/// [html.FontFace] is loaded wrapped with quotes. Unlike Safari 12 if a
151+
/// [DomFontFace] is loaded wrapped with quotes. Unlike Safari 12 if a
152152
/// valid version of the font is also loaded afterwards it will show
153153
/// that font normally.
154154
///
155-
/// In Safari 13 the [html.FontFace] should be loaded with unquoted family
155+
/// In Safari 13 the [DomFontFace] should be loaded with unquoted family
156156
/// names.
157157
///
158158
/// In order to avoid all these browser compatibility issues this method:
159159
/// * Detects the family names that might cause a conflict.
160160
/// * Loads it with the quotes.
161161
/// * Loads it again without the quotes.
162-
/// * For all the other family names [html.FontFace] is loaded only once.
162+
/// * For all the other family names [DomFontFace] is loaded only once.
163163
///
164164
/// See also:
165165
///
@@ -187,9 +187,9 @@ class FontManager {
187187
) {
188188
// try/catch because `new FontFace` can crash with an improper font family.
189189
try {
190-
final html.FontFace fontFace = html.FontFace(family, asset, descriptors);
190+
final DomFontFace fontFace = createDomFontFace(family, asset, descriptors);
191191
_fontLoadingFutures.add(fontFace.load().then((_) {
192-
html.document.fonts!.add(fontFace);
192+
domDocument.fonts!.add(fontFace);
193193
}, onError: (dynamic e) {
194194
printWarning('Error while trying to load font family "$family":\n$e');
195195
}));
@@ -202,15 +202,15 @@ class FontManager {
202202
Future<void> _loadFontFaceBytes(String family, Uint8List list) {
203203
// Since these fonts are loaded by user code, surface the error
204204
// through the returned future.
205-
final html.FontFace fontFace = html.FontFace(family, list);
205+
final DomFontFace fontFace = createDomFontFace(family, list);
206206
return fontFace.load().then((_) {
207-
html.document.fonts!.add(fontFace);
207+
domDocument.fonts!.add(fontFace);
208208
// There might be paragraph measurements for this new font before it is
209209
// loaded. They were measured using fallback font, so we should clear the
210210
// cache.
211211
Spanometer.clearRulersCache();
212212
}, onError: (dynamic exception) {
213-
// Failures here will throw an html.DomException which confusingly
213+
// Failures here will throw an DomException which confusingly
214214
// does not implement Exception or Error. Rethrow an Exception so it can
215215
// be caught in user code without depending on dart:html or requiring a
216216
// catch block without "on".
@@ -245,22 +245,22 @@ class _PolyfillFontManager extends FontManager {
245245
String asset,
246246
Map<String, String> descriptors,
247247
) {
248-
final html.ParagraphElement paragraph = html.ParagraphElement();
248+
final DomHTMLParagraphElement paragraph = createDomHTMLParagraphElement();
249249
paragraph.style.position = 'absolute';
250250
paragraph.style.visibility = 'hidden';
251251
paragraph.style.fontSize = '72px';
252252
final String fallbackFontName =
253253
browserEngine == BrowserEngine.ie11 ? 'Times New Roman' : 'sans-serif';
254254
paragraph.style.fontFamily = fallbackFontName;
255255
if (descriptors['style'] != null) {
256-
paragraph.style.fontStyle = descriptors['style'];
256+
paragraph.style.fontStyle = descriptors['style']!;
257257
}
258258
if (descriptors['weight'] != null) {
259-
paragraph.style.fontWeight = descriptors['weight'];
259+
paragraph.style.fontWeight = descriptors['weight']!;
260260
}
261261
paragraph.text = _testString;
262262

263-
html.document.body!.append(paragraph);
263+
domDocument.body!.append(paragraph);
264264
final int sansSerifWidth = paragraph.offsetWidth;
265265

266266
paragraph.style.fontFamily = "'$family', $fallbackFontName";
@@ -297,10 +297,10 @@ class _PolyfillFontManager extends FontManager {
297297
final String fontFaceDeclaration = fontStyleMap.keys
298298
.map((String name) => '$name: ${fontStyleMap[name]};')
299299
.join(' ');
300-
final html.StyleElement fontLoadStyle = html.StyleElement();
300+
final DomHTMLStyleElement fontLoadStyle = DomHTMLStyleElement();
301301
fontLoadStyle.type = 'text/css';
302302
fontLoadStyle.innerHtml = '@font-face { $fontFaceDeclaration }';
303-
html.document.head!.append(fontLoadStyle);
303+
domDocument.head!.append(fontLoadStyle);
304304

305305
// HACK: If this is an icon font, then when it loads it won't change the
306306
// width of our test string. So we just have to hope it loads before the

lib/web_ui/lib/src/engine/text/layout_service.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
65
import 'dart:math' as math;
76

87
import 'package:meta/meta.dart';
98
import 'package:ui/ui.dart' as ui;
109

10+
import '../dom.dart';
1111
import 'canvas_paragraph.dart';
1212
import 'line_breaker.dart';
1313
import 'measurement.dart';
@@ -17,13 +17,13 @@ import 'text_direction.dart';
1717

1818
/// Performs layout on a [CanvasParagraph].
1919
///
20-
/// It uses a [html.CanvasElement] to measure text.
20+
/// It uses a [DomCanvasElement] to measure text.
2121
class TextLayoutService {
2222
TextLayoutService(this.paragraph);
2323

2424
final CanvasParagraph paragraph;
2525

26-
final html.CanvasRenderingContext2D context = html.CanvasElement().context2D;
26+
final DomCanvasRenderingContext2D context = createDomCanvasElement().context2D;
2727

2828
// *** Results of layout *** //
2929

@@ -1582,7 +1582,7 @@ class Spanometer {
15821582
Spanometer(this.paragraph, this.context);
15831583

15841584
final CanvasParagraph paragraph;
1585-
final html.CanvasRenderingContext2D context;
1585+
final DomCanvasRenderingContext2D context;
15861586

15871587
static RulerHost _rulerHost = RulerHost();
15881588

lib/web_ui/lib/src/engine/text/measurement.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'dart:html' as html;
66

77
import '../../engine.dart' show registerHotRestartListener;
8+
import '../dom.dart';
89
import '../embedder.dart';
910

1011
// TODO(yjbanov): this is a hack we use to compute ideographic baseline; this
@@ -70,7 +71,7 @@ double _lastWidth = -1;
7071
/// This method assumes that the correct font has already been set on
7172
/// [_canvasContext].
7273
double measureSubstring(
73-
html.CanvasRenderingContext2D _canvasContext,
74+
DomCanvasRenderingContext2D _canvasContext,
7475
String text,
7576
int start,
7677
int end, {

0 commit comments

Comments
 (0)