mirror of
https://github.com/servo/servo.git
synced 2025-06-06 00:25:37 +00:00
Merge 8a8e308911
into dfa8dde1ca
This commit is contained in:
commit
327c71076f
10 changed files with 142 additions and 55 deletions
|
@ -99,6 +99,15 @@ pub struct Preferences {
|
|||
pub dom_serviceworker_timeout_seconds: i64,
|
||||
pub dom_servo_helpers_enabled: bool,
|
||||
pub dom_servoparser_async_html_tokenizer_enabled: bool,
|
||||
/// When enabled, Servo will create stub implementations for all DOM methods and attributes
|
||||
/// that are known but not implemented. When a page tries to use one of these then a warning
|
||||
/// with the method name will be logged and some appropriate default behaviour will be chosen:
|
||||
/// * Getting the value of a stub attribute will return `undefined`
|
||||
/// * Setting the value of a stub attribute will do nothing
|
||||
/// * Calling a stub method will return `undefined`
|
||||
///
|
||||
/// The warning is dispatched with target `dom-stubs`. Set `RUST_LOG=error,dom-stubs=warn` to see it.
|
||||
pub dom_stub_unimplemented_features: bool,
|
||||
pub dom_svg_enabled: bool,
|
||||
pub dom_testable_crash_enabled: bool,
|
||||
pub dom_testbinding_enabled: bool,
|
||||
|
@ -272,6 +281,7 @@ impl Preferences {
|
|||
dom_serviceworker_timeout_seconds: 60,
|
||||
dom_servo_helpers_enabled: false,
|
||||
dom_servoparser_async_html_tokenizer_enabled: false,
|
||||
dom_stub_unimplemented_features: false,
|
||||
dom_svg_enabled: false,
|
||||
dom_testable_crash_enabled: false,
|
||||
dom_testbinding_enabled: false,
|
||||
|
|
|
@ -417,10 +417,11 @@ class CGMethodCall(CGThing):
|
|||
|
||||
def getPerSignatureCall(signature, argConversionStartsAt=0):
|
||||
signatureIndex = signatures.index(signature)
|
||||
isUnimplemented = method.getExtendedAttribute("Unimplemented") is not None
|
||||
return CGPerSignatureCall(signature[0], argsPre, signature[1],
|
||||
f"{nativeMethodName}{'_' * signatureIndex}",
|
||||
static, descriptor,
|
||||
method, argConversionStartsAt)
|
||||
method, isUnimplemented, argConversionStartsAt)
|
||||
|
||||
if len(signatures) == 1:
|
||||
# Special case: we can just do a per-signature method call
|
||||
|
@ -1614,11 +1615,23 @@ class PropertyDefiner:
|
|||
assert attr[0] is not None
|
||||
return attr[0]
|
||||
|
||||
@staticmethod
|
||||
def hasAttr(member, name) -> bool:
|
||||
attr = member.getExtendedAttribute(name)
|
||||
return attr is not None
|
||||
|
||||
@staticmethod
|
||||
def getControllingCondition(interfaceMember, descriptor):
|
||||
prefCondition = PropertyDefiner.getStringAttr(interfaceMember, "Pref")
|
||||
isUnimplemented = PropertyDefiner.hasAttr(interfaceMember, "Unimplemented")
|
||||
|
||||
if isUnimplemented:
|
||||
if prefCondition is not None:
|
||||
raise TypeError("Cannot preference-gate unimplemented features")
|
||||
prefCondition = "dom_stub_unimplemented_features"
|
||||
|
||||
return MemberCondition(
|
||||
PropertyDefiner.getStringAttr(interfaceMember,
|
||||
"Pref"),
|
||||
prefCondition,
|
||||
PropertyDefiner.getStringAttr(interfaceMember,
|
||||
"Func"),
|
||||
interfaceMember.exposureSet,
|
||||
|
@ -2801,7 +2814,10 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs,
|
|||
traits += ["crate::reflector::DomObjectWrap<Self>"]
|
||||
|
||||
if not descriptor.interface.isCallback() and not descriptor.interface.isIteratorInterface():
|
||||
nonConstMembers = [m for m in descriptor.interface.members if not m.isConst()]
|
||||
nonConstMembers = [
|
||||
m for m in descriptor.interface.members
|
||||
if not m.isConst() and not m.getExtendedAttribute("Unimplemented")
|
||||
]
|
||||
ctor = descriptor.interface.ctor()
|
||||
if (
|
||||
nonConstMembers
|
||||
|
@ -3928,7 +3944,7 @@ def needCx(returnType, arguments, considerTypes):
|
|||
|
||||
class CGCallGenerator(CGThing):
|
||||
"""
|
||||
A class to generate an actual call to a C++ object. Assumes that the C++
|
||||
A class to generate an actual call to a Rust object. Assumes that the Rust
|
||||
object is stored in a variable whose name is given by the |object| argument.
|
||||
|
||||
errorResult should be a string for the value to return in case of an
|
||||
|
@ -3936,7 +3952,7 @@ class CGCallGenerator(CGThing):
|
|||
"""
|
||||
def __init__(self, errorResult, arguments, argsPre, returnType,
|
||||
extendedAttributes, descriptor, nativeMethodName,
|
||||
static, object="this", hasCEReactions=False):
|
||||
static, isUnimplemented: bool, object="this", hasCEReactions=False):
|
||||
CGThing.__init__(self)
|
||||
|
||||
assert errorResult is None or isinstance(errorResult, str)
|
||||
|
@ -3974,6 +3990,17 @@ class CGCallGenerator(CGThing):
|
|||
# Build up our actual call
|
||||
self.cgRoot = CGList([], "\n")
|
||||
|
||||
if isUnimplemented:
|
||||
# Generate a stub implementation that logs a warning and does nothing else
|
||||
logMessage = (
|
||||
f"log::warn!(target: \"dom-stubs\", \""
|
||||
f"Attempt to use unimplemented method or attribute "
|
||||
f"{descriptor.interface.identifier.name}::{nativeMethodName}"
|
||||
f"\");"
|
||||
)
|
||||
self.cgRoot.append(CGGeneric(logMessage))
|
||||
return
|
||||
|
||||
if rootType:
|
||||
self.cgRoot.append(CGList([
|
||||
CGGeneric("rooted!(in(*cx) let mut retval: "),
|
||||
|
@ -4045,7 +4072,7 @@ class CGPerSignatureCall(CGThing):
|
|||
# there.
|
||||
|
||||
def __init__(self, returnType, argsPre, arguments, nativeMethodName, static,
|
||||
descriptor, idlNode, argConversionStartsAt=0,
|
||||
descriptor, idlNode, isUnimplemented: bool, argConversionStartsAt=0,
|
||||
getter=False, setter=False):
|
||||
CGThing.__init__(self)
|
||||
self.returnType = returnType
|
||||
|
@ -4057,6 +4084,8 @@ class CGPerSignatureCall(CGThing):
|
|||
self.argsPre = argsPre
|
||||
self.arguments = arguments
|
||||
self.argCount = len(arguments)
|
||||
self.isUnimplemented = isUnimplemented
|
||||
|
||||
cgThings = []
|
||||
cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgs(),
|
||||
self.getArgc(), self.descriptor,
|
||||
|
@ -4083,7 +4112,7 @@ class CGPerSignatureCall(CGThing):
|
|||
errorResult,
|
||||
self.getArguments(), self.argsPre, returnType,
|
||||
self.extendedAttributes, descriptor, nativeMethodName,
|
||||
static, hasCEReactions=hasCEReactions))
|
||||
static, isUnimplemented, hasCEReactions=hasCEReactions))
|
||||
|
||||
self.cgRoot = CGList(cgThings, "\n")
|
||||
|
||||
|
@ -4100,6 +4129,14 @@ class CGPerSignatureCall(CGThing):
|
|||
return 'infallible' not in self.extendedAttributes
|
||||
|
||||
def wrap_return_value(self):
|
||||
if self.isUnimplemented:
|
||||
# Unimplemented methods don't actually compute a result type, so we stub
|
||||
# it out here
|
||||
return (
|
||||
"args.rval().set(UndefinedValue());\n"
|
||||
"return true;"
|
||||
)
|
||||
|
||||
resultName = "result"
|
||||
# Maplike methods have `any` return values in WebIDL, but our internal bindings
|
||||
# use stronger types so we need to exclude them from being handled like other
|
||||
|
@ -4170,9 +4207,10 @@ class CGGetterCall(CGPerSignatureCall):
|
|||
getter.
|
||||
"""
|
||||
def __init__(self, argsPre, returnType, nativeMethodName, descriptor, attr):
|
||||
isUnimplemented = attr.getExtendedAttribute("Unimplemented") is not None
|
||||
CGPerSignatureCall.__init__(self, returnType, argsPre, [],
|
||||
nativeMethodName, attr.isStatic(), descriptor,
|
||||
attr, getter=True)
|
||||
attr, isUnimplemented, getter=True)
|
||||
|
||||
|
||||
class FakeArgument():
|
||||
|
@ -4197,9 +4235,10 @@ class CGSetterCall(CGPerSignatureCall):
|
|||
setter.
|
||||
"""
|
||||
def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr):
|
||||
isUnimplemented = attr.getExtendedAttribute("Unimplemented") is not None
|
||||
CGPerSignatureCall.__init__(self, None, argsPre,
|
||||
[FakeArgument(argType, attr, allowTreatNonObjectAsNull=True)],
|
||||
nativeMethodName, attr.isStatic(), descriptor, attr,
|
||||
nativeMethodName, attr.isStatic(), descriptor, attr, isUnimplemented,
|
||||
setter=True)
|
||||
|
||||
def wrap_return_value(self):
|
||||
|
@ -5826,8 +5865,9 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
|||
|
||||
# We pass len(arguments) as the final argument so that the
|
||||
# CGPerSignatureCall won't do any argument conversion of its own.
|
||||
isUnimplemented = False
|
||||
CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
|
||||
False, descriptor, operation,
|
||||
False, descriptor, operation, isUnimplemented,
|
||||
len(arguments))
|
||||
|
||||
if operation.isSetter():
|
||||
|
@ -6687,6 +6727,11 @@ class CGInterfaceTrait(CGThing):
|
|||
|
||||
def members():
|
||||
for m in descriptor.interface.members:
|
||||
if m.getExtendedAttribute("Unimplemented"):
|
||||
# Unimplemented methods or attributes generate a stub implementation and should
|
||||
# therefore not be part of the trait
|
||||
continue
|
||||
|
||||
if (m.isMethod()
|
||||
and not m.isMaplikeOrSetlikeOrIterableMethod()
|
||||
and (not m.isIdentifierLess() or (m.isStringifier() and not m.underlyingAttr))
|
||||
|
|
|
@ -16,13 +16,28 @@ typedef (HTMLOrSVGImageElement or
|
|||
/*VideoFrame or*/
|
||||
/*CSSImageValue*/ CSSStyleValue) CanvasImageSource;
|
||||
|
||||
enum PredefinedColorSpace { "srgb", "display-p3" };
|
||||
|
||||
enum CanvasColorType { "unorm8", "float16" };
|
||||
|
||||
enum CanvasFillRule { "nonzero", "evenodd" };
|
||||
|
||||
dictionary CanvasRenderingContext2DSettings {
|
||||
boolean alpha = true;
|
||||
boolean desynchronized = false;
|
||||
PredefinedColorSpace colorSpace = "srgb";
|
||||
CanvasColorType colorType = "unorm8";
|
||||
boolean willReadFrequently = false;
|
||||
};
|
||||
|
||||
enum ImageSmoothingQuality { "low", "medium", "high" };
|
||||
|
||||
[Exposed=Window]
|
||||
interface CanvasRenderingContext2D {
|
||||
// back-reference to the canvas
|
||||
readonly attribute HTMLCanvasElement canvas;
|
||||
};
|
||||
CanvasRenderingContext2D includes CanvasSettings;
|
||||
CanvasRenderingContext2D includes CanvasState;
|
||||
CanvasRenderingContext2D includes CanvasTransform;
|
||||
CanvasRenderingContext2D includes CanvasCompositing;
|
||||
|
@ -40,11 +55,17 @@ CanvasRenderingContext2D includes CanvasPathDrawingStyles;
|
|||
CanvasRenderingContext2D includes CanvasTextDrawingStyles;
|
||||
CanvasRenderingContext2D includes CanvasPath;
|
||||
|
||||
interface mixin CanvasSettings {
|
||||
// settings
|
||||
[Unimplemented] CanvasRenderingContext2DSettings getContextAttributes();
|
||||
};
|
||||
|
||||
interface mixin CanvasState {
|
||||
// state
|
||||
undefined save(); // push state on state stack
|
||||
undefined restore(); // pop state stack and restore state
|
||||
undefined reset();
|
||||
undefined reset(); // reset the rendering context to its default state
|
||||
[Unimplemented] boolean isContextLost(); // return whether context is lost
|
||||
};
|
||||
|
||||
interface mixin CanvasTransform {
|
||||
|
@ -66,7 +87,7 @@ interface mixin CanvasTransform {
|
|||
unrestricted double d,
|
||||
unrestricted double e,
|
||||
unrestricted double f);
|
||||
// void setTransform(optional DOMMatrixInit matrix);
|
||||
// [Unimplemented] undefined setTransform(optional DOMMatrixInit matrix);
|
||||
undefined resetTransform();
|
||||
};
|
||||
|
||||
|
@ -79,7 +100,7 @@ interface mixin CanvasCompositing {
|
|||
interface mixin CanvasImageSmoothing {
|
||||
// image smoothing
|
||||
attribute boolean imageSmoothingEnabled; // (default true)
|
||||
// attribute ImageSmoothingQuality imageSmoothingQuality; // (default low)
|
||||
[Unimplemented] attribute ImageSmoothingQuality imageSmoothingQuality; // (default low)
|
||||
};
|
||||
|
||||
interface mixin CanvasFillStrokeStyles {
|
||||
|
@ -89,6 +110,7 @@ interface mixin CanvasFillStrokeStyles {
|
|||
CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
|
||||
[Throws]
|
||||
CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
|
||||
[Unimplemented] CanvasGradient createConicGradient(double startAngle, double x, double y);
|
||||
[Throws]
|
||||
CanvasPattern? createPattern(CanvasImageSource image, [LegacyNullToEmptyString] DOMString repetition);
|
||||
};
|
||||
|
@ -103,7 +125,7 @@ interface mixin CanvasShadowStyles {
|
|||
|
||||
interface mixin CanvasFilters {
|
||||
// filters
|
||||
//attribute DOMString filter; // (default "none")
|
||||
[Unimplemented] attribute DOMString filter; // (default "none")
|
||||
};
|
||||
|
||||
interface mixin CanvasRect {
|
||||
|
@ -126,15 +148,15 @@ interface mixin CanvasDrawPath {
|
|||
optional CanvasFillRule fillRule = "nonzero");
|
||||
boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y,
|
||||
optional CanvasFillRule fillRule = "nonzero");
|
||||
//boolean isPointInStroke(unrestricted double x, unrestricted double y);
|
||||
//boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
|
||||
[Unimplemented] boolean isPointInStroke(unrestricted double x, unrestricted double y);
|
||||
[Unimplemented] boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
|
||||
};
|
||||
|
||||
interface mixin CanvasUserInterface {
|
||||
//void drawFocusIfNeeded(Element element);
|
||||
//void drawFocusIfNeeded(Path2D path, Element element);
|
||||
//void scrollPathIntoView();
|
||||
//void scrollPathIntoView(Path2D path);
|
||||
[Unimplemented] undefined drawFocusIfNeeded(Element element);
|
||||
[Unimplemented] undefined drawFocusIfNeeded(Path2D path, Element element);
|
||||
[Unimplemented] undefined scrollPathIntoView();
|
||||
[Unimplemented] undefined scrollPathIntoView(Path2D path);
|
||||
};
|
||||
|
||||
interface mixin CanvasText {
|
||||
|
@ -142,8 +164,7 @@ interface mixin CanvasText {
|
|||
[Pref="dom_canvas_text_enabled"]
|
||||
undefined fillText(DOMString text, unrestricted double x, unrestricted double y,
|
||||
optional unrestricted double maxWidth);
|
||||
//void strokeText(DOMString text, unrestricted double x, unrestricted double y,
|
||||
// optional unrestricted double maxWidth);
|
||||
[Unimplemented] undefined strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
|
||||
[Pref="dom_canvas_text_enabled"]
|
||||
TextMetrics measureText(DOMString text);
|
||||
};
|
||||
|
|
|
@ -44,9 +44,8 @@ interface HTMLElement : Element {
|
|||
// attribute boolean draggable;
|
||||
// [SameObject, PutForwards=value] readonly attribute DOMTokenList dropzone;
|
||||
// attribute HTMLMenuElement? contextMenu;
|
||||
// [CEReactions]
|
||||
// attribute boolean spellcheck;
|
||||
// void forceSpellCheck();
|
||||
[Unimplemented, CEReactions] attribute boolean spellcheck;
|
||||
[Unimplemented] undefined forceSpellCheck();
|
||||
|
||||
[CEReactions] attribute [LegacyNullToEmptyString] DOMString innerText;
|
||||
[CEReactions, Throws] attribute [LegacyNullToEmptyString] DOMString outerText;
|
||||
|
|
|
@ -7,30 +7,22 @@
|
|||
interface HTMLLinkElement : HTMLElement {
|
||||
[HTMLConstructor] constructor();
|
||||
|
||||
[CEReactions]
|
||||
attribute USVString href;
|
||||
[CEReactions]
|
||||
attribute DOMString? crossOrigin;
|
||||
[CEReactions]
|
||||
attribute DOMString rel;
|
||||
[CEReactions] attribute USVString href;
|
||||
[CEReactions] attribute DOMString? crossOrigin;
|
||||
[CEReactions] attribute DOMString rel;
|
||||
[CEReactions] attribute DOMString as;
|
||||
[SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
|
||||
[CEReactions]
|
||||
attribute DOMString media;
|
||||
[CEReactions]
|
||||
attribute DOMString integrity;
|
||||
[CEReactions]
|
||||
attribute DOMString hreflang;
|
||||
[CEReactions]
|
||||
attribute DOMString type;
|
||||
// [SameObject, PutForwards=value] readonly attribute DOMTokenList sizes;
|
||||
// [CEReactions] attribute USVString imageSrcset;
|
||||
// [CEReactions] attribute DOMString imageSizes;
|
||||
[CEReactions]
|
||||
attribute DOMString referrerPolicy;
|
||||
// [SameObject, PutForwards=value] readonly attribute DOMTokenList blocking;
|
||||
[CEReactions] attribute DOMString media;
|
||||
[CEReactions] attribute DOMString integrity;
|
||||
[CEReactions] attribute DOMString hreflang;
|
||||
[CEReactions] attribute DOMString type;
|
||||
[Unimplemented, SameObject, PutForwards=value] readonly attribute DOMTokenList sizes;
|
||||
[Unimplemented, CEReactions] attribute USVString imageSrcset;
|
||||
[Unimplemented, CEReactions] attribute DOMString imageSizes;
|
||||
[CEReactions] attribute DOMString referrerPolicy;
|
||||
[Unimplemented, SameObject, PutForwards=value] readonly attribute DOMTokenList blocking;
|
||||
[CEReactions] attribute boolean disabled;
|
||||
// [CEReactions] attribute DOMString fetchPriority;
|
||||
[Unimplemented, CEReactions] attribute DOMString fetchPriority;
|
||||
|
||||
// also has obsolete members
|
||||
};
|
||||
|
@ -38,10 +30,7 @@ HTMLLinkElement includes LinkStyle;
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#HTMLLinkElement-partial
|
||||
partial interface HTMLLinkElement {
|
||||
[CEReactions]
|
||||
attribute DOMString charset;
|
||||
[CEReactions]
|
||||
attribute DOMString rev;
|
||||
[CEReactions]
|
||||
attribute DOMString target;
|
||||
[CEReactions] attribute DOMString charset;
|
||||
[CEReactions] attribute DOMString rev;
|
||||
[CEReactions] attribute DOMString target;
|
||||
};
|
||||
|
|
|
@ -20,5 +20,5 @@
|
|||
undefined replace(USVString url);
|
||||
[Throws] undefined reload();
|
||||
|
||||
//[SameObject] readonly attribute USVString[] ancestorOrigins;
|
||||
[Unimplemented, SameObject] readonly attribute DOMStringList ancestorOrigins;
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ interface TextTrack : EventTarget {
|
|||
readonly attribute DOMString language;
|
||||
|
||||
readonly attribute DOMString id;
|
||||
// readonly attribute DOMString inBandMetadataTrackDispatchType;
|
||||
[Unimplemented] readonly attribute DOMString inBandMetadataTrackDispatchType;
|
||||
|
||||
attribute TextTrackMode mode;
|
||||
|
||||
|
|
2
third_party/WebIDL/WebIDL.py
vendored
2
third_party/WebIDL/WebIDL.py
vendored
|
@ -5939,6 +5939,7 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
or identifier == "BinaryName"
|
||||
or identifier == "NonEnumerable"
|
||||
or identifier == "BindingTemplate"
|
||||
or identifier == "Unimplemented"
|
||||
):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
|
@ -7018,6 +7019,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
or identifier == "NonEnumerable"
|
||||
or identifier == "Unexposed"
|
||||
or identifier == "WebExtensionStub"
|
||||
or identifier == "Unimplemented"
|
||||
):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
|
|
20
third_party/WebIDL/dom-stubs.patch
vendored
Normal file
20
third_party/WebIDL/dom-stubs.patch
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
diff --git a/third_party/WebIDL/WebIDL.py b/third_party/WebIDL/WebIDL.py
|
||||
index 40e118e378..437e3640a6 100644
|
||||
--- a/third_party/WebIDL/WebIDL.py
|
||||
+++ b/third_party/WebIDL/WebIDL.py
|
||||
@@ -5938,6 +5938,7 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
or identifier == "BinaryName"
|
||||
or identifier == "NonEnumerable"
|
||||
or identifier == "BindingTemplate"
|
||||
+ or identifier == "Unimplemented"
|
||||
):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
@@ -7017,6 +7018,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
or identifier == "NonEnumerable"
|
||||
or identifier == "Unexposed"
|
||||
or identifier == "WebExtensionStub"
|
||||
+ or identifier == "Unimplemented"
|
||||
):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
1
third_party/WebIDL/update.sh
vendored
1
third_party/WebIDL/update.sh
vendored
|
@ -8,6 +8,7 @@ patch < like-as-iterable.patch
|
|||
patch < builtin-array.patch
|
||||
patch < array-type.patch
|
||||
patch < transferable.patch
|
||||
patch < dom-stubs.patch
|
||||
|
||||
wget https://hg.mozilla.org/mozilla-central/archive/tip.zip/dom/bindings/parser/tests/ -O tests.zip
|
||||
rm -r tests
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue