script: Move code generation and webidl files to new script_bindings crate. (#35157)

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2025-01-24 15:47:43 -05:00 committed by GitHub
parent a88b59534f
commit af8d7c2de7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
469 changed files with 187 additions and 137 deletions

View file

@ -1,615 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# DOM Bindings Configuration.
#
# The WebIDL interfaces are defined in dom/webidls. For each such interface,
# there is a corresponding entry in the configuration table below.
# The configuration table maps each interface name to a |descriptor|.
#
# Valid fields for all descriptors:
# * outerObjectHook: string to use in place of default value for outerObject and thisObject
# JS class hooks
DOMInterfaces = {
'AbstractRange': {
'weakReferenceable': True,
},
'AudioContext': {
'inRealms': ['Close', 'Suspend'],
'canGc':['CreateMediaStreamDestination', 'CreateMediaElementSource', 'CreateMediaStreamSource', 'CreateMediaStreamTrackSource', 'Suspend', 'Close'],
},
'BaseAudioContext': {
'inRealms': ['DecodeAudioData', 'Resume', 'ParseFromString', 'GetBounds', 'GetClientRects'],
'canGc': ['CreateChannelMerger', 'CreateOscillator', 'CreateStereoPanner', 'CreateGain', 'CreateIIRFilter', 'CreateBiquadFilter', 'CreateBufferSource', 'CreateAnalyser', 'CreatePanner', 'CreateChannelSplitter', 'CreateBuffer', 'CreateConstantSource', 'Resume', 'DecodeAudioData'],
},
'Blob': {
'weakReferenceable': True,
'canGc': ['Slice', 'Text', 'ArrayBuffer', 'Stream'],
},
'Bluetooth': {
'inRealms': ['GetAvailability', 'RequestDevice'],
'canGc': ['RequestDevice', 'GetAvailability'],
},
'BluetoothDevice': {
'inRealms': ['WatchAdvertisements'],
'canGc': ['WatchAdvertisements'],
},
'BluetoothRemoteGATTCharacteristic': {
'inRealms': ['ReadValue', 'StartNotifications', 'StopNotifications', 'WriteValue'],
'canGc': ['GetDescriptor', 'GetDescriptors', 'ReadValue', 'StartNotifications', 'StopNotifications', 'WriteValue'],
},
'BluetoothRemoteGATTDescriptor': {
'inRealms': ['ReadValue', 'WriteValue'],
'canGc': ['ReadValue', 'WriteValue'],
},
'BluetoothRemoteGATTServer': {
'inRealms': ['Connect'],
'canGc': ['GetPrimaryService', 'GetPrimaryServices', 'Connect', 'Disconnect'],
},
'BluetoothRemoteGATTService': {
'canGc': ['GetCharacteristic', 'GetCharacteristics', 'GetIncludedService', 'GetIncludedServices'],
},
'CanvasGradient': {
'canGc': ['AddColorStop'],
},
'CanvasRenderingContext2D': {
'canGc': ['GetTransform','GetImageData', 'CreateImageData', 'CreateImageData_', 'SetFont', 'FillText', 'MeasureText', 'SetStrokeStyle', 'SetFillStyle', 'SetShadowColor'],
},
'CharacterData': {
'canGc': ['Before', 'After', 'ReplaceWith']
},
'CSSStyleDeclaration': {
'canGc': ['RemoveProperty', 'SetCssText', 'GetPropertyValue', 'SetProperty', 'CssFloat', 'SetCssFloat']
},
'CustomElementRegistry': {
'inRealms': ['WhenDefined'],
'canGc': ['WhenDefined'],
},
'DataTransfer': {
'canGc': ['Files']
},
'DataTransferItem': {
'canGc': ['GetAsFile']
},
'DataTransferItemList': {
'canGc': ['IndexedGetter', 'Add', 'Add_']
},
'Document': {
'canGc': ['Close', 'CreateElement', 'CreateElementNS', 'ImportNode', 'SetTitle', 'Write', 'Writeln', 'CreateEvent', 'CreateRange', 'Open', 'Open_', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ElementFromPoint', 'ElementsFromPoint', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate'],
},
'DocumentFragment': {
'canGc': ['Prepend', 'Append', 'ReplaceChildren']
},
'DocumentType': {
'canGc': ['Before', 'After', 'ReplaceWith']
},
'DOMImplementation': {
'canGc': ['CreateDocument', 'CreateHTMLDocument', 'CreateDocumentType'],
},
'DOMMatrix': {
'canGc': ['FromMatrix', 'FromFloat32Array', 'FromFloat64Array'],
},
'DOMMatrixReadOnly': {
'canGc': ['Multiply', 'Inverse', 'Scale', 'Translate', 'Rotate', 'RotateFromVector','FlipY', 'ScaleNonUniform', 'Scale3d', 'RotateAxisAngle', 'SkewX', 'SkewY', 'FlipX', 'TransformPoint', 'FromFloat32Array', 'FromFloat64Array','FromMatrix'],
},
'DOMParser': {
'canGc': ['ParseFromString'],
},
'DOMPoint': {
'canGc': ['FromPoint'],
},
'DOMPointReadOnly': {
'canGc': ['FromPoint'],
},
'DOMQuad': {
'canGc': ['FromRect', 'FromQuad', 'GetBounds'],
},
'DOMStringMap': {
'canGc': ['NamedSetter']
},
"DOMTokenList": {
'canGc': ['SetValue', 'Add', 'Remove', 'Toggle', 'Replace']
},
'DynamicModuleOwner': {
'inRealms': ['PromiseAttribute'],
},
'Element': {
'canGc': ['SetInnerHTML', 'SetOuterHTML', 'InsertAdjacentHTML', 'GetClientRects', 'GetBoundingClientRect', 'InsertAdjacentText', 'ToggleAttribute', 'SetAttribute', 'SetAttributeNS', 'SetId','SetClassName','Prepend','Append','ReplaceChildren','Before','After','ReplaceWith', 'SetRole', 'SetAriaAtomic', 'SetAriaAutoComplete', 'SetAriaBrailleLabel', 'SetAriaBrailleRoleDescription', 'SetAriaBusy', 'SetAriaChecked', 'SetAriaColCount', 'SetAriaColIndex', 'SetAriaColIndexText', 'SetAriaColSpan', 'SetAriaCurrent', 'SetAriaDescription', 'SetAriaDisabled', 'SetAriaExpanded', 'SetAriaHasPopup', 'SetAriaHidden', 'SetAriaInvalid', 'SetAriaKeyShortcuts', 'SetAriaLabel', 'SetAriaLevel', 'SetAriaLive', 'SetAriaModal', 'SetAriaMultiLine', 'SetAriaMultiSelectable', 'SetAriaOrientation', 'SetAriaPlaceholder', 'SetAriaPosInSet', 'SetAriaPressed','SetAriaReadOnly', 'SetAriaRelevant', 'SetAriaRequired', 'SetAriaRoleDescription', 'SetAriaRowCount', 'SetAriaRowIndex', 'SetAriaRowIndexText', 'SetAriaRowSpan', 'SetAriaSelected', 'SetAriaSetSize','SetAriaSort', 'SetAriaValueMax', 'SetAriaValueMin', 'SetAriaValueNow', 'SetAriaValueText', 'SetScrollTop', 'SetScrollLeft', 'Scroll', 'Scroll_', 'ScrollBy', 'ScrollBy_', 'ScrollWidth', 'ScrollHeight', 'ScrollTop', 'ScrollLeft', 'ClientTop', 'ClientLeft', 'ClientWidth', 'ClientHeight', 'RequestFullscreen'],
},
'ElementInternals': {
'canGc': ['CheckValidity', 'ReportValidity'],
},
'EventSource': {
'weakReferenceable': True,
},
'EventTarget': {
'canGc': ['DispatchEvent'],
},
'FakeXRDevice': {
'canGc': ['Disconnect'],
},
'File': {
'weakReferenceable': True,
},
'FileReader': {
'canGc': ['Abort'],
},
'GamepadHapticActuator': {
'inRealms': ['PlayEffect', 'Reset'],
'canGc': ['PlayEffect', 'Reset'],
},
'GPU': {
'inRealms': ['RequestAdapter'],
'canGc': ['RequestAdapter', 'WgslLanguageFeatures'],
},
'GPUAdapter': {
'inRealms': ['RequestAdapterInfo', 'RequestDevice'],
'canGc': ['RequestAdapterInfo', 'RequestDevice'],
},
'GPUBuffer': {
'inRealms': ['MapAsync'],
'canGc': ['MapAsync'],
},
'GPUCanvasContext': {
'weakReferenceable': True,
},
'GPUDevice': {
'inRealms': [
'CreateComputePipelineAsync',
'CreateRenderPipelineAsync',
'CreateShaderModule', # Creates promise for compilation info
'PopErrorScope'
],
'canGc': [
'CreateComputePipelineAsync',
'CreateRenderPipelineAsync',
'CreateShaderModule',
'PopErrorScope'
],
'weakReferenceable': True, # for usage in GlobalScope https://github.com/servo/servo/issues/32519
},
'GPUQueue': {
'canGc': ['OnSubmittedWorkDone'],
},
'History': {
'canGc': ['Go'],
},
"HTMLAnchorElement": {
"canGc": ["SetText","SetRel","SetHref", 'SetHash', 'SetHost', 'SetHostname', 'SetPassword', 'SetPathname', 'SetPort', 'SetProtocol', 'SetSearch', 'SetUsername']
},
"HTMLAreaElement": {
"canGc": ["SetRel"]
},
"HTMLBodyElement": {
"canGc": ["SetBackground"]
},
'HTMLButtonElement': {
'canGc': ['CheckValidity', 'ReportValidity','SetBackground'],
},
'HTMLCanvasElement': {
'canGc': ['CaptureStream', 'GetContext'],
},
'HTMLDialogElement': {
'canGc': ['Show'],
},
'HTMLElement': {
'canGc': ['Focus', 'Blur', 'Click', 'SetInnerText', 'SetOuterText', "SetTranslate", 'SetAutofocus', 'GetOffsetParent', 'OffsetTop', 'OffsetLeft', 'OffsetWidth', 'OffsetHeight', 'InnerText', 'GetOuterText', 'GetOnerror', 'GetOnload', 'GetOnblur', 'GetOnfocus', 'GetOnresize', 'GetOnscroll'],
},
'HTMLFieldSetElement': {
'canGc': ['CheckValidity', 'ReportValidity'],
},
'HTMLFontElement': {
'canGc': ['SetSize']
},
'HTMLFormElement': {
'canGc': ['CheckValidity', 'RequestSubmit', 'ReportValidity', 'Submit', 'Reset', 'SetRel'],
},
'HTMLImageElement': {
'canGc': ['RequestSubmit', 'ReportValidity', 'Reset','SetRel', 'Width', 'Height', 'Decode', 'SetCrossOrigin', 'SetWidth', 'SetHeight', 'SetReferrerPolicy'],
},
'HTMLInputElement': {
'canGc': ['ReportValidity', 'SetValue', 'SetValueAsNumber', 'SetValueAsDate', 'StepUp', 'StepDown', 'CheckValidity', 'ReportValidity', 'SelectFiles'],
},
'HTMLLinkElement': {
'canGc': ['SetRel', 'SetCrossOrigin'],
},
'HTMLMediaElement': {
'canGc': ['Load', 'Pause', 'Play', 'SetSrcObject', 'SetCrossOrigin'],
'inRealms': ['Play'],
},
'HTMLMeterElement': {
'canGc': ['SetValue', 'SetMin', 'SetMax', 'SetLow', 'SetHigh', 'SetOptimum', 'CheckValidity', 'ReportValidity']
},
'HTMLObjectElement': {
'canGc': ['CheckValidity', 'ReportValidity'],
},
'HTMLOptionElement': {
'canGc': ['SetText']
},
'HTMLOptionsCollection': {
'canGc': ['IndexedSetter', 'SetLength']
},
'HTMLOutputElement': {
'canGc': ['ReportValidity', 'SetDefaultValue', 'SetValue', 'CheckValidity'],
},
'HTMLProgressElement': {
'canGc': ['SetValue', 'SetMax']
},
'HTMLScriptElement': {
'canGc': ['SetAsync', 'SetCrossOrigin', 'SetText']
},
'HTMLSelectElement': {
'canGc': ['ReportValidity', 'SetLength', 'IndexedSetter', 'CheckValidity'],
},
'HTMLTableElement': {
'canGc': ['CreateCaption', 'CreateTBody', 'InsertRow', 'InsertCell', 'InsertRow', 'CreateTHead', 'CreateTFoot']
},
'HTMLTableRowElement': {
'canGc': ['InsertCell']
},
'HTMLTableSectionElement': {
'canGc': ['InsertRow']
},
'HTMLTemplateElement': {
'canGc': ['Content'],
},
'HTMLTextAreaElement': {
'canGc': ['ReportValidity', 'SetDefaultValue', 'CheckValidity'],
},
'HTMLTitleElement': {
'canGc': ['SetText']
},
'Location': {
'canGc': ['Assign', 'Reload', 'Replace', 'SetHash', 'SetHost', 'SetHostname', 'SetHref', 'SetPathname', 'SetPort', 'SetProtocol', 'SetSearch'],
},
'MediaDevices': {
'canGc': ['GetUserMedia', 'EnumerateDevices'],
'inRealms': ['GetUserMedia', 'GetClientRects', 'GetBoundingClientRect'],
},
'MediaQueryList': {
'weakReferenceable': True,
},
'MediaSession': {
'canGc': ['GetMetadata'],
},
'MediaStream': {
'canGc': ['Clone'],
},
'MessagePort': {
'weakReferenceable': True,
'canGc': ['GetOnmessage'],
},
'MouseEvent': {
'canGc': ['OffsetX', 'OffsetY'],
},
'NavigationPreloadManager': {
'inRealms': ['Disable', 'Enable', 'GetState', 'SetHeaderValue'],
'canGc': ['Disable', 'Enable', 'GetState', 'SetHeaderValue'],
},
'Navigator': {
'inRealms': ['GetVRDisplays'],
},
'Node': {
'canGc': ['CloneNode', 'SetTextContent'],
},
'OfflineAudioContext': {
'inRealms': ['StartRendering'],
'canGc': ['StartRendering'],
},
'OffscreenCanvasRenderingContext2D': {
'canGc': ['CreateImageData', 'CreateImageData_', 'GetImageData', 'GetTransform', 'SetFont', 'FillText', 'MeasureText', 'SetStrokeStyle', 'SetFillStyle', 'SetShadowColor'],
},
'PaintRenderingContext2D': {
'canGc': ['GetTransform', 'SetStrokeStyle', 'SetFillStyle', 'SetShadowColor'],
},
'Performance': {
'canGc': ['Mark', 'Measure'],
},
'Permissions': {
'canGc': ['Query', 'Request', 'Revoke'],
},
'Promise': {
'spiderMonkeyInterface': True,
},
'Range': {
'canGc': ['CloneContents', 'CloneRange', 'CreateContextualFragment', 'ExtractContents', 'SurroundContents', 'InsertNode'],
'weakReferenceable': True,
},
'Request': {
'canGc': ['Headers', 'Text', 'Blob', 'FormData', 'Json', 'ArrayBuffer', 'Clone'],
},
'Response': {
'canGc': ['Error', 'Redirect', 'Clone', 'Text', 'Blob', 'FormData', 'Json', 'ArrayBuffer', 'Headers'],
},
'RTCPeerConnection': {
'inRealms': ['AddIceCandidate', 'CreateAnswer', 'CreateOffer', 'SetLocalDescription', 'SetRemoteDescription'],
'canGc': ['Close', 'AddIceCandidate', 'CreateAnswer', 'CreateOffer', 'SetLocalDescription', 'SetRemoteDescription'],
},
'RTCRtpSender': {
'canGc': ['SetParameters'],
},
'Selection': {
'canGc': ['Collapse', 'CollapseToEnd', 'CollapseToStart', 'Extend', 'SelectAllChildren', 'SetBaseAndExtent', 'SetPosition'],
},
'ServiceWorkerContainer': {
'inRealms': ['Register'],
'canGc': ['Register'],
},
'ShadowRoot': {
'canGc': ['ElementFromPoint', 'ElementsFromPoint', 'SetInnerHTML'],
},
'StaticRange': {
'weakReferenceable': True,
},
'SubtleCrypto': {
'inRealms': ['Encrypt', 'Decrypt', 'Sign', 'Verify', 'GenerateKey', 'DeriveKey', 'DeriveBits', 'Digest', 'ImportKey', 'ExportKey', 'WrapKey', 'UnwrapKey'],
'canGc': ['Encrypt', 'Decrypt', 'Sign', 'Verify', 'GenerateKey', 'DeriveKey', 'DeriveBits', 'Digest', 'ImportKey', 'ExportKey', 'WrapKey', 'UnwrapKey'],
},
'SVGElement': {
'canGc': ['SetAutofocus']
},
#FIXME(jdm): This should be 'register': False, but then we don't generate enum types
'TestBinding': {
'inRealms': ['PromiseAttribute', 'PromiseNativeHandler'],
'canGc': ['InterfaceAttribute', 'GetInterfaceAttributeNullable', 'ReceiveInterface', 'ReceiveInterfaceSequence', 'ReceiveNullableInterface', 'PromiseAttribute', 'PromiseNativeHandler'],
},
'TestWorklet': {
'inRealms': ['AddModule'],
'canGc': ['AddModule'],
},
'Text': {
'canGc': ['SplitText']
},
'URL': {
'weakReferenceable': True,
'canGc': ['Parse', 'SearchParams'],
},
'WebGLRenderingContext': {
'canGc': ['MakeXRCompatible'],
},
'WebGL2RenderingContext': {
'canGc': ['MakeXRCompatible'],
},
'Window': {
'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap'],
'inRealms': ['Fetch', 'GetOpener'],
},
'WindowProxy' : {
'path': 'crate::dom::windowproxy::WindowProxy',
'register': False,
},
'WorkerGlobalScope': {
'inRealms': ['Fetch'],
'canGc': ['Fetch', 'CreateImageBitmap', 'ImportScripts'],
},
'Worklet': {
'inRealms': ['AddModule'],
'canGc': ['AddModule'],
},
'XMLHttpRequest': {
'canGc': ['Abort', 'GetResponseXML', 'Response', 'Send'],
},
'XPathEvaluator': {
'canGc': ['CreateExpression', 'Evaluate'],
},
'XPathExpression': {
'canGc': ['Evaluate'],
},
'XRBoundedReferenceSpace': {
'canGc': ['BoundsGeometry'],
},
'XRFrame': {
'canGc': ['GetViewerPose', 'GetPose', 'GetJointPose'],
},
'XRHitTestResult': {
'canGc': ['GetPose'],
},
'XRRay': {
'canGc': ['Origin', 'Direction'],
},
'XRReferenceSpace': {
'canGc': ['GetOffsetReferenceSpace'],
},
'XRRigidTransform': {
'canGc': ['Position', 'Orientation', 'Inverse'],
},
'XRSession': {
'inRealms': ['RequestReferenceSpace', 'UpdateRenderState', 'UpdateTargetFrameRate'],
'canGc': ['End', 'RequestReferenceSpace', 'UpdateTargetFrameRate', 'RequestHitTestSource'],
},
'XRSystem': {
'inRealms': ['RequestSession'],
'canGc': ['RequestSession', 'IsSessionSupported'],
},
'XRTest': {
'canGc': ['SimulateDeviceConnection', 'DisconnectAllDevices'],
},
'ReadableStream': {
'canGc': ['GetReader', 'Cancel', 'Tee'],
},
"ReadableStreamDefaultController": {
"canGc": ["Enqueue"]
},
"ReadableStreamBYOBReader": {
"canGc": ["Read", "Cancel"]
},
"ReadableStreamDefaultReader": {
"canGc": ["Read", "Cancel"]
},
}
Dictionaries = {
'GPUCanvasConfiguration': {
'derives': ['Clone']
},
'GPUExtent3DDict': {
'derives': ["MallocSizeOf"],
},
'GPUObjectDescriptorBase': {
'derives': ['MallocSizeOf']
},
'GPUTextureDescriptor': {
'derives': ["MallocSizeOf"],
},
'HeadersInit': {
'derives': ["Clone"],
},
}
Enums = {
'GPUFeatureName': {
'derives': ['Hash', 'Eq']
}
}
Unions = {
'ByteStringSequenceSequenceOrByteStringByteStringRecord': {
'derives': ['Clone']
},
'HTMLCanvasElementOrOffscreenCanvas': {
'derives': ['Clone', 'MallocSizeOf']
},
'RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict': {
'derives': ['MallocSizeOf']
},
'StringOrUnsignedLong': {
'derives': ['Clone'],
},
}

File diff suppressed because it is too large Load diff

View file

@ -1,553 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import functools
import os
from WebIDL import IDLExternalInterface, IDLSequenceType, IDLWrapperType, WebIDLError
class Configuration:
"""
Represents global configuration state based on IDL parse data and
the configuration file.
"""
def __init__(self, filename, parseData):
# Read the configuration file.
glbl = {}
exec(compile(open(filename).read(), filename, 'exec'), glbl)
config = glbl['DOMInterfaces']
self.enumConfig = glbl['Enums']
self.dictConfig = glbl['Dictionaries']
self.unionConfig = glbl['Unions']
# Build descriptors for all the interfaces we have in the parse data.
# This allows callers to specify a subset of interfaces by filtering
# |parseData|.
self.descriptors = []
self.interfaces = {}
self.maxProtoChainLength = 0
for thing in parseData:
# Servo does not support external interfaces.
if isinstance(thing, IDLExternalInterface):
raise WebIDLError("Servo does not support external interfaces.",
[thing.location])
assert not thing.isType()
if not thing.isInterface() and not thing.isNamespace():
continue
iface = thing
self.interfaces[iface.identifier.name] = iface
if iface.identifier.name not in config:
entry = {}
else:
entry = config[iface.identifier.name]
if not isinstance(entry, list):
assert isinstance(entry, dict)
entry = [entry]
self.descriptors.extend(
[Descriptor(self, iface, x) for x in entry])
# Mark the descriptors for which only a single nativeType implements
# an interface.
for descriptor in self.descriptors:
interfaceName = descriptor.interface.identifier.name
otherDescriptors = [d for d in self.descriptors
if d.interface.identifier.name == interfaceName]
descriptor.uniqueImplementation = len(otherDescriptors) == 1
self.enums = [e for e in parseData if e.isEnum()]
self.typedefs = [e for e in parseData if e.isTypedef()]
self.dictionaries = [d for d in parseData if d.isDictionary()]
self.callbacks = [c for c in parseData if
c.isCallback() and not c.isInterface()]
# Keep the descriptor list sorted for determinism.
def cmp(x, y):
return (x > y) - (x < y)
self.descriptors.sort(key=functools.cmp_to_key(lambda x, y: cmp(x.name, y.name)))
def getInterface(self, ifname):
return self.interfaces[ifname]
def getDescriptors(self, **filters):
"""Gets the descriptors that match the given filters."""
curr = self.descriptors
for key, val in filters.items():
if key == 'webIDLFile':
def getter(x):
return x.interface.location.filename
elif key == 'hasInterfaceObject':
def getter(x):
return x.interface.hasInterfaceObject()
elif key == 'isCallback':
def getter(x):
return x.interface.isCallback()
elif key == 'isNamespace':
def getter(x):
return x.interface.isNamespace()
elif key == 'isJSImplemented':
def getter(x):
return x.interface.isJSImplemented()
elif key == 'isGlobal':
def getter(x):
return x.isGlobal()
elif key == 'isInline':
def getter(x):
return x.interface.getExtendedAttribute('Inline') is not None
elif key == 'isExposedConditionally':
def getter(x):
return x.interface.isExposedConditionally()
elif key == 'isIteratorInterface':
def getter(x):
return x.interface.isIteratorInterface()
else:
def getter(x):
return getattr(x, key)
curr = [x for x in curr if getter(x) == val]
return curr
def getEnums(self, webIDLFile):
return [e for e in self.enums if e.filename == webIDLFile]
def getEnumConfig(self, name):
return self.enumConfig.get(name, {})
def getTypedefs(self, webIDLFile):
return [e for e in self.typedefs if e.filename == webIDLFile]
@staticmethod
def _filterForFile(items, webIDLFile=""):
"""Gets the items that match the given filters."""
if not webIDLFile:
return items
return [x for x in items if x.filename == webIDLFile]
def getUnionConfig(self, name):
return self.unionConfig.get(name, {})
def getDictionaries(self, webIDLFile=""):
return self._filterForFile(self.dictionaries, webIDLFile=webIDLFile)
def getDictConfig(self, name):
return self.dictConfig.get(name, {})
def getCallbacks(self, webIDLFile=""):
return self._filterForFile(self.callbacks, webIDLFile=webIDLFile)
def getDescriptor(self, interfaceName):
"""
Gets the appropriate descriptor for the given interface name.
"""
iface = self.getInterface(interfaceName)
descriptors = self.getDescriptors(interface=iface)
# We should have exactly one result.
if len(descriptors) != 1:
raise NoSuchDescriptorError("For " + interfaceName + " found "
+ str(len(descriptors)) + " matches")
return descriptors[0]
def getDescriptorProvider(self):
"""
Gets a descriptor provider that can provide descriptors as needed.
"""
return DescriptorProvider(self)
class NoSuchDescriptorError(TypeError):
def __init__(self, str):
TypeError.__init__(self, str)
class DescriptorProvider:
"""
A way of getting descriptors for interface names
"""
def __init__(self, config):
self.config = config
def getDescriptor(self, interfaceName):
"""
Gets the appropriate descriptor for the given interface name given the
context of the current descriptor.
"""
return self.config.getDescriptor(interfaceName)
def MemberIsLegacyUnforgeable(member, descriptor):
return ((member.isAttr() or member.isMethod())
and not member.isStatic()
and (member.isLegacyUnforgeable()
or bool(descriptor.interface.getExtendedAttribute("LegacyUnforgeable"))))
class Descriptor(DescriptorProvider):
"""
Represents a single descriptor for an interface. See Bindings.conf.
"""
def __init__(self, config, interface, desc):
DescriptorProvider.__init__(self, config)
self.interface = interface
if not self.isExposedConditionally():
if interface.parent and interface.parent.isExposedConditionally():
raise TypeError("%s is not conditionally exposed but inherits from "
"%s which is" %
(interface.identifier.name, interface.parent.identifier.name))
# Read the desc, and fill in the relevant defaults.
ifaceName = self.interface.identifier.name
nativeTypeDefault = ifaceName
# For generated iterator interfaces for other iterable interfaces, we
# just use IterableIterator as the native type, templated on the
# nativeType of the iterable interface. That way we can have a
# templated implementation for all the duplicated iterator
# functionality.
if self.interface.isIteratorInterface():
itrName = self.interface.iterableInterface.identifier.name
itrDesc = self.getDescriptor(itrName)
nativeTypeDefault = iteratorNativeType(itrDesc)
typeName = desc.get('nativeType', nativeTypeDefault)
spiderMonkeyInterface = desc.get('spiderMonkeyInterface', False)
# Callback and SpiderMonkey types do not use JS smart pointers, so we should not use the
# built-in rooting mechanisms for them.
if spiderMonkeyInterface:
self.returnType = 'Rc<%s>' % typeName
self.argumentType = '&%s' % typeName
self.nativeType = typeName
pathDefault = 'crate::dom::types::%s' % typeName
elif self.interface.isCallback():
ty = 'crate::dom::bindings::codegen::Bindings::%sBinding::%s' % (ifaceName, ifaceName)
pathDefault = ty
self.returnType = "Rc<%s>" % ty
self.argumentType = "???"
self.nativeType = ty
else:
self.returnType = "DomRoot<%s>" % typeName
self.argumentType = "&%s" % typeName
self.nativeType = "*const %s" % typeName
if self.interface.isIteratorInterface():
pathDefault = 'crate::dom::bindings::iterable::IterableIterator'
else:
pathDefault = 'crate::dom::types::%s' % MakeNativeName(typeName)
self.concreteType = typeName
self.register = desc.get('register', True)
self.path = desc.get('path', pathDefault)
self.inRealmMethods = [name for name in desc.get('inRealms', [])]
self.canGcMethods = [name for name in desc.get('canGc', [])]
self.bindingPath = f"{getModuleFromObject(self.interface)}::{ifaceName}_Binding"
self.outerObjectHook = desc.get('outerObjectHook', 'None')
self.proxy = False
self.weakReferenceable = desc.get('weakReferenceable', False)
# If we're concrete, we need to crawl our ancestor interfaces and mark
# them as having a concrete descendant.
self.concrete = (not self.interface.isCallback()
and not self.interface.isNamespace()
and not self.interface.getExtendedAttribute("Abstract")
and not self.interface.getExtendedAttribute("Inline")
and not spiderMonkeyInterface)
self.hasLegacyUnforgeableMembers = (self.concrete
and any(MemberIsLegacyUnforgeable(m, self) for m in
self.interface.members))
self.operations = {
'IndexedGetter': None,
'IndexedSetter': None,
'IndexedDeleter': None,
'NamedGetter': None,
'NamedSetter': None,
'NamedDeleter': None,
'Stringifier': None,
}
self.hasDefaultToJSON = False
def addOperation(operation, m):
if not self.operations[operation]:
self.operations[operation] = m
# Since stringifiers go on the prototype, we only need to worry
# about our own stringifier, not those of our ancestor interfaces.
for m in self.interface.members:
if m.isMethod() and m.isStringifier():
addOperation('Stringifier', m)
if m.isMethod() and m.isDefaultToJSON():
self.hasDefaultToJSON = True
if self.concrete:
iface = self.interface
while iface:
for m in iface.members:
if not m.isMethod():
continue
def addIndexedOrNamedOperation(operation, m):
if not self.isGlobal():
self.proxy = True
if m.isIndexed():
operation = 'Indexed' + operation
else:
assert m.isNamed()
operation = 'Named' + operation
addOperation(operation, m)
if m.isGetter():
addIndexedOrNamedOperation('Getter', m)
if m.isSetter():
addIndexedOrNamedOperation('Setter', m)
if m.isDeleter():
addIndexedOrNamedOperation('Deleter', m)
iface = iface.parent
if iface:
iface.setUserData('hasConcreteDescendant', True)
if self.isMaybeCrossOriginObject():
self.proxy = True
if self.proxy:
iface = self.interface
while iface.parent:
iface = iface.parent
iface.setUserData('hasProxyDescendant', True)
self.name = interface.identifier.name
# self.extendedAttributes is a dict of dicts, keyed on
# all/getterOnly/setterOnly and then on member name. Values are an
# array of extended attributes.
self.extendedAttributes = {'all': {}, 'getterOnly': {}, 'setterOnly': {}}
def addExtendedAttribute(attribute, config):
def add(key, members, attribute):
for member in members:
self.extendedAttributes[key].setdefault(member, []).append(attribute)
if isinstance(config, dict):
for key in ['all', 'getterOnly', 'setterOnly']:
add(key, config.get(key, []), attribute)
elif isinstance(config, list):
add('all', config, attribute)
else:
assert isinstance(config, str)
if config == '*':
iface = self.interface
while iface:
add('all', [m.name for m in iface.members], attribute)
iface = iface.parent
else:
add('all', [config], attribute)
self._binaryNames = desc.get('binaryNames', {})
self._binaryNames.setdefault('__legacycaller', 'LegacyCall')
self._binaryNames.setdefault('__stringifier', 'Stringifier')
self._internalNames = desc.get('internalNames', {})
for member in self.interface.members:
if not member.isAttr() and not member.isMethod():
continue
binaryName = member.getExtendedAttribute("BinaryName")
if binaryName:
assert isinstance(binaryName, list)
assert len(binaryName) == 1
self._binaryNames.setdefault(member.identifier.name,
binaryName[0])
self._internalNames.setdefault(member.identifier.name,
member.identifier.name.replace('-', '_'))
# Build the prototype chain.
self.prototypeChain = []
parent = interface
while parent:
self.prototypeChain.insert(0, parent.identifier.name)
parent = parent.parent
self.prototypeDepth = len(self.prototypeChain) - 1
config.maxProtoChainLength = max(config.maxProtoChainLength,
len(self.prototypeChain))
def maybeGetSuperModule(self):
"""
Returns name of super module if self is part of it
"""
filename = getIdlFileName(self.interface)
# if interface name is not same as webidl file
# webidl is super module for interface
if filename.lower() != self.interface.identifier.name.lower():
return filename
return None
def binaryNameFor(self, name):
return self._binaryNames.get(name, name)
def internalNameFor(self, name):
return self._internalNames.get(name, name)
def hasNamedPropertiesObject(self):
if self.interface.isExternal():
return False
return self.isGlobal() and self.supportsNamedProperties()
def supportsNamedProperties(self):
return self.operations['NamedGetter'] is not None
def getExtendedAttributes(self, member, getter=False, setter=False):
def maybeAppendInfallibleToAttrs(attrs, throws):
if throws is None:
attrs.append("infallible")
elif throws is True:
pass
else:
raise TypeError("Unknown value for 'Throws'")
name = member.identifier.name
if member.isMethod():
attrs = self.extendedAttributes['all'].get(name, [])
throws = member.getExtendedAttribute("Throws")
maybeAppendInfallibleToAttrs(attrs, throws)
return attrs
assert member.isAttr()
assert bool(getter) != bool(setter)
key = 'getterOnly' if getter else 'setterOnly'
attrs = self.extendedAttributes['all'].get(name, []) + self.extendedAttributes[key].get(name, [])
throws = member.getExtendedAttribute("Throws")
if throws is None:
throwsAttr = "GetterThrows" if getter else "SetterThrows"
throws = member.getExtendedAttribute(throwsAttr)
maybeAppendInfallibleToAttrs(attrs, throws)
return attrs
def getParentName(self):
parent = self.interface.parent
while parent:
if not parent.getExtendedAttribute("Inline"):
return parent.identifier.name
parent = parent.parent
return None
def supportsIndexedProperties(self):
return self.operations['IndexedGetter'] is not None
def isMaybeCrossOriginObject(self):
# If we're isGlobal and have cross-origin members, we're a Window, and
# that's not a cross-origin object. The WindowProxy is.
return self.concrete and self.interface.hasCrossOriginMembers and not self.isGlobal()
def hasDescendants(self):
return (self.interface.getUserData("hasConcreteDescendant", False)
or self.interface.getUserData("hasProxyDescendant", False))
def hasHTMLConstructor(self):
ctor = self.interface.ctor()
return ctor and ctor.isHTMLConstructor()
def shouldHaveGetConstructorObjectMethod(self):
assert self.interface.hasInterfaceObject()
if self.interface.getExtendedAttribute("Inline"):
return False
return (self.interface.isCallback() or self.interface.isNamespace()
or self.hasDescendants() or self.hasHTMLConstructor())
def shouldCacheConstructor(self):
return self.hasDescendants() or self.hasHTMLConstructor()
def isExposedConditionally(self):
return self.interface.isExposedConditionally()
def isGlobal(self):
"""
Returns true if this is the primary interface for a global object
of some sort.
"""
return bool(self.interface.getExtendedAttribute("Global")
or self.interface.getExtendedAttribute("PrimaryGlobal"))
# Some utility methods
def MakeNativeName(name):
return name[0].upper() + name[1:]
def getIdlFileName(object):
return os.path.basename(object.location.filename).split('.webidl')[0]
def getModuleFromObject(object):
return ('crate::dom::bindings::codegen::Bindings::' + getIdlFileName(object) + 'Binding')
def getTypesFromDescriptor(descriptor):
"""
Get all argument and return types for all members of the descriptor
"""
members = [m for m in descriptor.interface.members]
if descriptor.interface.ctor():
members.append(descriptor.interface.ctor())
members.extend(descriptor.interface.legacyFactoryFunctions)
signatures = [s for m in members if m.isMethod() for s in m.signatures()]
types = []
for s in signatures:
assert len(s) == 2
(returnType, arguments) = s
types.append(returnType)
types.extend(a.type for a in arguments)
types.extend(a.type for a in members if a.isAttr())
return types
def getTypesFromDictionary(dictionary):
"""
Get all member types for this dictionary
"""
if isinstance(dictionary, IDLWrapperType):
dictionary = dictionary.inner
types = []
curDict = dictionary
while curDict:
types.extend([getUnwrappedType(m.type) for m in curDict.members])
curDict = curDict.parent
return types
def getTypesFromCallback(callback):
"""
Get the types this callback depends on: its return type and the
types of its arguments.
"""
sig = callback.signatures()[0]
types = [sig[0]] # Return type
types.extend(arg.type for arg in sig[1]) # Arguments
return types
def getUnwrappedType(type):
while isinstance(type, IDLSequenceType):
type = type.inner
return type
def iteratorNativeType(descriptor, infer=False):
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
assert (iterableDecl.isIterable() and iterableDecl.isPairIterator()) \
or iterableDecl.isSetlike() or iterableDecl.isMaplike()
res = "IterableIterator%s" % ("" if infer else '<%s>' % descriptor.interface.identifier.name)
# todo: this hack is telling us that something is still wrong in codegen
if iterableDecl.isSetlike() or iterableDecl.isMaplike():
res = f"crate::dom::bindings::iterable::{res}"
return res

View file

@ -1,6 +0,0 @@
<table id="${interface}">
<tr>
<th>${interface}</th>
</tr>
${properties}
</table>

View file

@ -1,35 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="rustdoc">
<meta name="description" content="API documentation for the Rust `servo` crate.">
<meta name="keywords" content="rust, rustlang, rust-lang, servo">
<title>Supported DOM APIs - servo - Rust</title>
<link rel="stylesheet" type="text/css" href="../rustdoc.css">
<link rel="stylesheet" type="text/css" href="../main.css">
</head>
<body class="rustdoc">
<!--[if lte IE 8]>
<div class="warning">
This old browser is unsupported and will most likely display funky
things.
</div>
<![endif]-->
<nav class='sidebar'>
<div class='block crate'>
<h3>Interfaces</h3>
<ul>
${interfaces}
</ul>
</div>
</nav>
<section id='main' class="content mod">
<h1 class='fqn'><span class='in-band'>DOM APIs currently supported in <a class='mod' href=''>Servo</a></span></h1>
<div id='properties' class='docblock'>
${apis}
</div>
</section>
</body>
</html>

View file

@ -1 +0,0 @@
<li><a href="#${interface}">${interface}</a></li>

View file

@ -1,3 +0,0 @@
<tr>
<td>${name}</td>
</tr>

View file

@ -1,159 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import os
import sys
import json
import re
SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__))
SERVO_ROOT = os.path.abspath(os.path.join(SCRIPT_PATH, "..", "..", "..", "..", ".."))
FILTER_PATTERN = re.compile("// skip-unless ([A-Z_]+)\n")
def main():
os.chdir(os.path.join(os.path.dirname(__file__)))
sys.path.insert(0, os.path.join(SERVO_ROOT, "third_party", "WebIDL"))
sys.path.insert(0, os.path.join(SERVO_ROOT, "third_party", "ply"))
css_properties_json, out_dir = sys.argv[1:]
# Four dotdots: /path/to/target(4)/debug(3)/build(2)/style-*(1)/out
# Do not ascend above the target dir, because it may not be called target
# or even have a parent (see CARGO_TARGET_DIR).
doc_servo = os.path.join(out_dir, "..", "..", "..", "..", "doc")
webidls_dir = os.path.join(SCRIPT_PATH, "..", "..", "webidls")
config_file = "Bindings.conf"
import WebIDL
from Configuration import Configuration
from CodegenRust import CGBindingRoot
parser = WebIDL.Parser(make_dir(os.path.join(out_dir, "cache")))
webidls = [name for name in os.listdir(webidls_dir) if name.endswith(".webidl")]
for webidl in webidls:
filename = os.path.join(webidls_dir, webidl)
with open(filename, "r", encoding="utf-8") as f:
contents = f.read()
filter_match = FILTER_PATTERN.search(contents)
if filter_match:
env_var = filter_match.group(1)
if not os.environ.get(env_var):
continue
parser.parse(contents, filename)
add_css_properties_attributes(css_properties_json, parser)
parser_results = parser.finish()
config = Configuration(config_file, parser_results)
make_dir(os.path.join(out_dir, "Bindings"))
for name, filename in [
("PrototypeList", "PrototypeList.rs"),
("RegisterBindings", "RegisterBindings.rs"),
("InterfaceObjectMap", "InterfaceObjectMap.rs"),
("InterfaceObjectMapData", "InterfaceObjectMapData.json"),
("InterfaceTypes", "InterfaceTypes.rs"),
("InheritTypes", "InheritTypes.rs"),
("Bindings", "Bindings/mod.rs"),
("UnionTypes", "UnionTypes.rs"),
("DomTypes", "DomTypes.rs"),
("DomTypeHolder", "DomTypeHolder.rs"),
]:
generate(config, name, os.path.join(out_dir, filename))
make_dir(doc_servo)
generate(config, "SupportedDomApis", os.path.join(doc_servo, "apis.html"))
for webidl in webidls:
filename = os.path.join(webidls_dir, webidl)
prefix = "Bindings/%sBinding" % webidl[:-len(".webidl")]
module = CGBindingRoot(config, prefix, filename).define()
if module:
with open(os.path.join(out_dir, prefix + ".rs"), "wb") as f:
f.write(module.encode("utf-8"))
def make_dir(path):
if not os.path.exists(path):
os.makedirs(path)
return path
def generate(config, name, filename):
from CodegenRust import GlobalGenRoots
root = getattr(GlobalGenRoots, name)(config)
code = root.define()
with open(filename, "wb") as f:
f.write(code.encode("utf-8"))
def add_css_properties_attributes(css_properties_json, parser):
def map_preference_name(preference_name: str):
"""Map between Stylo preference names and Servo preference names as the
`css-properties.json` file is generated by Stylo. This should be kept in sync with the
preference mapping done in `components/servo_config/prefs.rs`, which handles the runtime version of
these preferences."""
MAPPING = [
["layout.unimplemented", "layout_unimplemented"],
["layout.threads", "layout_threads"],
["layout.legacy_layout", "layout_legacy_layout"],
["layout.flexbox.enabled", "layout_flexbox_enabled"],
["layout.columns.enabled", "layout_columns_enabled"],
["layout.grid.enabled", "layout_grid_enabled"],
["layout.css.transition-behavior.enabled", "layout_css_transition_behavior_enabled"],
["layout.writing-mode.enabled", "layout_writing_mode_enabled"],
["layout.container-queries.enabled", "layout_container_queries_enabled"],
]
for mapping in MAPPING:
if mapping[0] == preference_name:
return mapping[1]
return preference_name
css_properties = json.load(open(css_properties_json, "rb"))
idl = "partial interface CSSStyleDeclaration {\n%s\n};\n" % "\n".join(
" [%sCEReactions, SetterThrows] attribute [LegacyNullToEmptyString] DOMString %s;" % (
(f'Pref="{map_preference_name(data["pref"])}", ' if data["pref"] else ""),
attribute_name
)
for (kind, properties_list) in sorted(css_properties.items())
for (property_name, data) in sorted(properties_list.items())
for attribute_name in attribute_names(property_name)
)
parser.parse(idl, "CSSStyleDeclaration_generated.webidl")
def attribute_names(property_name):
# https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-dashed-attribute
if property_name != "float":
yield property_name
else:
yield "_float"
# https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-camel-cased-attribute
if "-" in property_name:
yield "".join(camel_case(property_name))
# https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-webkit-cased-attribute
if property_name.startswith("-webkit-"):
yield "".join(camel_case(property_name), True)
# https://drafts.csswg.org/cssom/#css-property-to-idl-attribute
def camel_case(chars, webkit_prefixed=False):
if webkit_prefixed:
chars = chars[1:]
next_is_uppercase = False
for c in chars:
if c == '-':
next_is_uppercase = True
elif next_is_uppercase:
next_is_uppercase = False
# Should be ASCII-uppercase, but all non-custom CSS property names are within ASCII
yield c.upper()
else:
yield c
if __name__ == "__main__":
main()

View file

@ -174,28 +174,28 @@ pub(crate) mod xmlname;
#[allow(missing_docs, non_snake_case)]
pub(crate) mod codegen {
pub(crate) mod DomTypeHolder {
include!(concat!(env!("OUT_DIR"), "/DomTypeHolder.rs"));
include!(concat!(env!("BINDINGS_OUT_DIR"), "/DomTypeHolder.rs"));
}
pub(crate) mod DomTypes {
include!(concat!(env!("OUT_DIR"), "/DomTypes.rs"));
include!(concat!(env!("BINDINGS_OUT_DIR"), "/DomTypes.rs"));
}
#[allow(dead_code)]
pub(crate) mod Bindings {
include!(concat!(env!("OUT_DIR"), "/Bindings/mod.rs"));
include!(concat!(env!("BINDINGS_OUT_DIR"), "/Bindings/mod.rs"));
}
pub(crate) mod InterfaceObjectMap {
include!(concat!(env!("OUT_DIR"), "/InterfaceObjectMap.rs"));
include!(concat!(env!("BINDINGS_OUT_DIR"), "/InterfaceObjectMap.rs"));
}
#[allow(dead_code, unused_imports, clippy::enum_variant_names)]
pub(crate) mod InheritTypes {
include!(concat!(env!("OUT_DIR"), "/InheritTypes.rs"));
include!(concat!(env!("BINDINGS_OUT_DIR"), "/InheritTypes.rs"));
}
#[allow(clippy::upper_case_acronyms)]
pub(crate) mod PrototypeList {
include!(concat!(env!("OUT_DIR"), "/PrototypeList.rs"));
include!(concat!(env!("BINDINGS_OUT_DIR"), "/PrototypeList.rs"));
}
pub(crate) mod RegisterBindings {
include!(concat!(env!("OUT_DIR"), "/RegisterBindings.rs"));
include!(concat!(env!("BINDINGS_OUT_DIR"), "/RegisterBindings.rs"));
}
#[allow(
non_camel_case_types,
@ -206,6 +206,6 @@ pub(crate) mod codegen {
clippy::enum_variant_names
)]
pub(crate) mod UnionTypes {
include!(concat!(env!("OUT_DIR"), "/UnionTypes.rs"));
include!(concat!(env!("BINDINGS_OUT_DIR"), "/UnionTypes.rs"));
}
}