diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 4842c307884..9d1ebd605e4 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -1937,13 +1937,13 @@ class ButtonElement extends HtmlElement {
set formAction(String? value) native;
- String get formEnctype native;
+ String? get formEnctype native;
- set formEnctype(String value) native;
+ set formEnctype(String? value) native;
- String get formMethod native;
+ String? get formMethod native;
- set formMethod(String value) native;
+ set formMethod(String? value) native;
bool get formNoValidate native;
@@ -2120,15 +2120,15 @@ class CanvasElement extends HtmlElement implements CanvasImageSource {
/// The height of this canvas element in CSS pixels.
- int get height native;
+ int? get height native;
- set height(int value) native;
+ set height(int? value) native;
/// The width of this canvas element in CSS pixels.
- int get width native;
+ int? get width native;
- set width(int value) native;
+ set width(int? value) native;
MediaStream captureStream([num? frameRate]) native;
@@ -15994,9 +15994,9 @@ class FieldSetElement extends HtmlElement {
*/
FieldSetElement.created() : super.created();
- bool get disabled native;
+ bool? get disabled native;
- set disabled(bool value) native;
+ set disabled(bool? value) native;
@Returns('HtmlCollection')
@Creates('HtmlCollection')
@@ -21740,34 +21740,34 @@ class MeterElement extends HtmlElement {
/// Checks if this type is supported on the current platform.
static bool get supported => Element.isTagSupported('meter');
- num get high native;
+ num? get high native;
- set high(num value) native;
+ set high(num? value) native;
@Unstable()
@Returns('NodeList')
@Creates('NodeList')
List? get labels native;
- num get low native;
+ num? get low native;
- set low(num value) native;
+ set low(num? value) native;
- num get max native;
+ num? get max native;
- set max(num value) native;
+ set max(num? value) native;
- num get min native;
+ num? get min native;
- set min(num value) native;
+ set min(num? value) native;
- num get optimum native;
+ num? get optimum native;
- set optimum(num value) native;
+ set optimum(num? value) native;
- num get value native;
+ num? get value native;
- set value(num value) native;
+ set value(num? value) native;
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -29170,9 +29170,9 @@ class StyleElement extends HtmlElement {
StyleSheet? get sheet native;
- String get type native;
+ String? get type native;
- set type(String value) native;
+ set type(String? value) native;
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index f016890f23b..aa97d1981a7 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -683,9 +683,9 @@ class FEColorMatrixElement extends SvgElement
AnimatedString get in1 native;
- AnimatedEnumeration get type native;
+ AnimatedEnumeration? get type native;
- AnimatedNumberList get values native;
+ AnimatedNumberList? get values native;
// From SVGFilterPrimitiveStandardAttributes
diff --git a/tests/lib/html/custom/document_register_type_extensions_test.dart b/tests/lib/html/custom/document_register_type_extensions_test.dart
index bbeafb56283..7da7cfdf1ad 100644
--- a/tests/lib/html/custom/document_register_type_extensions_test.dart
+++ b/tests/lib/html/custom/document_register_type_extensions_test.dart
@@ -60,7 +60,7 @@ class MyCanvas extends CanvasElement {
CanvasRenderingContext2D context =
this.getContext('2d') as CanvasRenderingContext2D;
context.fillStyle = 'red';
- context.fillRect(0, 0, width, height);
+ context.fillRect(0, 0, width!, height!);
context.fill();
var data = context.getImageData(0, 0, 1, 1).data;
diff --git a/tests/lib/html/url_test.dart b/tests/lib/html/url_test.dart
index 201f52386b8..857f8ae29f1 100644
--- a/tests/lib/html/url_test.dart
+++ b/tests/lib/html/url_test.dart
@@ -17,7 +17,7 @@ Blob createImageBlob() {
var context = canvas.context2D;
context.fillStyle = 'red';
- context.fillRect(0, 0, canvas.width, canvas.height);
+ context.fillRect(0, 0, canvas.width!, canvas.height!);
var dataUri = canvas.toDataUrl('image/png');
var byteString = window.atob(dataUri.split(',')[1]);
diff --git a/tools/dom/scripts/mdnreader.py b/tools/dom/scripts/mdnreader.py
index b748d1ff850..9fe43a3e977 100644
--- a/tools/dom/scripts/mdnreader.py
+++ b/tools/dom/scripts/mdnreader.py
@@ -5,8 +5,15 @@
import json
import os.path
+import re
import sys
+_COMPAT_KEY = '__compat'
+_EXPERIMENTAL_KEY = 'experimental'
+_STATUS_KEY = 'status'
+_SUPPORT_KEY = 'support'
+_VERSION_ADDED_KEY = 'version_added'
+
def _get_browser_compat_data():
current_dir = os.path.dirname(__file__)
@@ -89,17 +96,164 @@ def _get_browser_compat_data():
}
if interface in browser_compat_data:
- browser_compat_data[interface].update(metadata)
+ _unify_metadata(browser_compat_data[interface],
+ metadata)
else:
browser_compat_data[interface] = metadata
else:
names[:] = [] # Do not go underneath
+ # Attempts to unify two compatibility infos by taking the union of both, and
+ # for conflicting information, taking the "stricter" of the two versions.
+ # Updates `a` in place to represent the union of `a` and `b`.
+ def _unify_compat(a, b):
+
+ def _has_compat_data(metadata):
+ return _COMPAT_KEY in metadata and _SUPPORT_KEY in metadata[_COMPAT_KEY]
+
+ # Unifies the support statements of both metadata and updates
+ # `support_a` in place. If either metadata do not contain simple support
+ # statements, defaults attribute to not supported.
+ def _unify_support(support_a, support_b):
+ for browser in support_a.keys():
+ if browser in support_b:
+ if _is_simple_support_statement(support_a[browser]) and _is_simple_support_statement(support_b[browser]):
+ support_a[browser][_VERSION_ADDED_KEY] = _unify_versions(
+ support_a[browser][_VERSION_ADDED_KEY],
+ support_b[browser][_VERSION_ADDED_KEY])
+ else:
+ # Only support simple statements for now.
+ support_a[browser] = {_VERSION_ADDED_KEY: None}
+ for browser in support_b.keys():
+ if not browser in support_a:
+ support_a[browser] = support_b[browser]
+
+ if not _has_compat_data(b):
+ return
+ if not _has_compat_data(a):
+ a[_COMPAT_KEY] = b[_COMPAT_KEY]
+ return
+
+ support_a = a[_COMPAT_KEY][_SUPPORT_KEY]
+ support_b = b[_COMPAT_KEY][_SUPPORT_KEY]
+
+ _unify_support(support_a, support_b)
+
+ # Unifies any status info in the two metadata. Modifies `a` in place to
+ # represent the union of both `a` and `b`.
+ def _unify_status(a, b):
+
+ def _has_status(metadata):
+ return _COMPAT_KEY in metadata and _STATUS_KEY in metadata[_COMPAT_KEY]
+
+ # Modifies `status_a` in place to combine "experimental" tags.
+ def _unify_experimental(status_a, status_b):
+ # If either of the statuses report experimental, assume attribute is
+ # experimental.
+ status_a[_EXPERIMENTAL_KEY] = status_a.get(
+ _EXPERIMENTAL_KEY, False) or status_b.get(_EXPERIMENTAL_KEY, False)
+
+ if not _has_status(b):
+ return
+ if not _has_status(a):
+ a[_COMPAT_KEY] = b[_COMPAT_KEY]
+ return
+
+ status_a = a[_COMPAT_KEY][_STATUS_KEY]
+ status_b = b[_COMPAT_KEY][_STATUS_KEY]
+
+ _unify_experimental(status_a, status_b)
+
+ # If there exists multiple definitions of the same interface metadata e.g.
+ # elements, this attempts to unify the compatibilities for the interface as
+ # well as for each attribute.
+ def _unify_metadata(a, b):
+ # Unify the compatibility statement and status of the API or element.
+ _unify_compat(a, b)
+ _unify_status(a, b)
+ # Unify the compatibility statement and status of each attribute.
+ for attr in list(a.keys()):
+ if attr == _COMPAT_KEY:
+ continue
+ if attr in b:
+ _unify_compat(a[attr], b[attr])
+ _unify_status(a[attr], b[attr])
+ for attr in b.keys():
+ if not attr in a:
+ a[attr] = b[attr]
+
os.path.walk(browser_compat_folder, visitor, browser_compat_folder)
return browser_compat_data
+# Given two version values for a given browser, chooses the more strict version.
+def _unify_versions(version_a, version_b):
+ # Given two valid version strings, compares parts of the version string
+ # iteratively.
+ def _greater_version(version_a, version_b):
+ version_a_split = map(int, version_a.split('.'))
+ version_b_split = map(int, version_b.split('.'))
+ for i in range(min(len(version_a_split), len(version_b_split))):
+ if version_a_split[i] > version_b_split[i]:
+ return version_a
+ elif version_a_split[i] < version_b_split[i]:
+ return version_b
+ return version_a if len(version_a_split) > len(
+ version_b_split) else version_b
+
+ # Validate that we can handle the given version.
+ def _validate_version(version):
+ if not version:
+ return False
+ if version is True:
+ return True
+ if isinstance(version, str) or isinstance(version, unicode):
+ pattern = re.compile('^([0-9]+\.)*[0-9]+$')
+ if not pattern.match(version):
+ # It's possible for version strings to look like '<35'. We don't
+ # attempt to parse the conditional logic, and just default to
+ # potentially incompatible.
+ return None
+ return version
+ else:
+ raise ValueError(
+ 'Type of version_a was not handled correctly! type(version) = '
+ + str(type(version)))
+
+ version_a = _validate_version(version_a)
+ version_b = _validate_version(version_b)
+ # If one version reports not supported, default to not supported.
+ if not version_a or not version_b:
+ return False
+ # If one version reports always supported, the other version can only be
+ # more strict.
+ if version_a is True:
+ return version_b
+ if version_b is True:
+ return version_a
+
+ return _greater_version(version_a, version_b)
+
+
+# At this time, we only handle simple support statements due to the complexity
+# and variability around support statements with multiple elements.
+def _is_simple_support_statement(support_statement):
+ if isinstance(support_statement, list): # array_support_statement
+ # TODO(srujzs): Parse this list to determine compatibility. Will
+ # likely require parsing for 'version_removed' keys. Notes about
+ # which browser version enabled this attribute for which
+ # platform also complicates things. For now, we assume it's not
+ # compatible.
+ return False
+ if len(support_statement.keys()) > 1:
+ # If it's anything more complicated than 'version_added', like
+ # 'notes' that specify platform versions, we assume it's not
+ # compatible.
+ return False
+ return True
+
+
class MDNReader(object):
# Statically initialize and treat as constant.
_BROWSER_COMPAT_DATA = _get_browser_compat_data()
@@ -114,40 +268,29 @@ class MDNReader(object):
# For now, we will require support for browsers since the last IDL roll.
# TODO(srujzs): Determine if this is too conservative.
browser_version_map = {
- 'chrome': 63,
- 'firefox': 57,
- 'safari': 11,
+ 'chrome': '63',
+ 'firefox': '57',
+ 'safari': '11',
# We still support the latest version of IE.
- 'ie': 11,
- 'opera': 50,
+ 'ie': '11',
+ 'opera': '50',
}
- version_key = 'version_added'
for browser in browser_version_map.keys():
- support_data = compat_data['support']
+ support_data = compat_data[_SUPPORT_KEY]
if browser not in support_data:
return False
support_statement = support_data[browser]
- if isinstance(support_statement, list): # array_support_statement
- # TODO(srujzs): Parse this list to determine compatibility. Will
- # likely require parsing for 'version_removed' keys. Notes about
- # which browser version enabled this attribute for which
- # platform also complicates things. For now, we assume it's not
- # compatible.
+ if not _is_simple_support_statement(support_statement):
return False
- if len(support_statement.keys()) > 1:
- # If it's anything more complicated than 'version_added', like
- # 'notes' that specify platform versions, we assume it's not
- # compatible.
- return False
- version = support_statement[version_key]
- if not version or browser_version_map[browser] < float(version):
- # simple_support_statement
+ version = support_statement[_VERSION_ADDED_KEY]
+ # Compare version strings, target should be the more strict version.
+ target = browser_version_map[browser]
+ if _unify_versions(version, target) != target:
return False
+
# If the attribute is experimental, we assume it's not compatible.
- status_data = compat_data['status']
- experimental_key = 'experimental'
- if experimental_key in status_data and \
- status_data[experimental_key]:
+ status_data = compat_data[_STATUS_KEY]
+ if _EXPERIMENTAL_KEY in status_data and status_data[_EXPERIMENTAL_KEY]:
return False
return True
@@ -169,7 +312,7 @@ class MDNReader(object):
return False
elif id_name in interface_dict:
id_data = interface_dict[id_name]
- return self._get_attr_compatibility(id_data['__compat'])
+ return self._get_attr_compatibility(id_data[_COMPAT_KEY])
else:
# Might be an attribute that is defined in a parent interface.
# We defer until attribute emitting to determine if this is the