From baec01edaf3ee13ca5747089aea6676b8aef2493 Mon Sep 17 00:00:00 2001 From: Hixie Date: Mon, 22 Dec 2014 11:27:47 -0800 Subject: [PATCH] Specs: Split apis.md into dom.md, events.md, idl.md, and move the remainder into README.md and modules.md Specs: Add runloop.md stub. Specs: Add animation.md stub. Review URL: https://codereview.chromium.org/824773002 --- specs/README.md | 13 ++ specs/animation.md | 21 ++ specs/apis.md | 553 --------------------------------------------- specs/dom.md | 257 +++++++++++++++++++++ specs/events.md | 55 +++++ specs/idl.md | 158 +++++++++++++ specs/modules.md | 44 ++++ specs/runloop.md | 23 ++ 8 files changed, 571 insertions(+), 553 deletions(-) create mode 100644 specs/animation.md delete mode 100644 specs/apis.md create mode 100644 specs/dom.md create mode 100644 specs/events.md create mode 100644 specs/idl.md create mode 100644 specs/runloop.md diff --git a/specs/README.md b/specs/README.md index ad96c47604e..90e01f1af5f 100644 --- a/specs/README.md +++ b/specs/README.md @@ -24,3 +24,16 @@ For module files, one of the following: * ``53 4b 59 20 4d 4f 44 55 4c 45 0a`` ("``SKY MODULE\n``") * ``53 4b 59 20 4d 4f 44 55 4c 45 0d`` ("``SKY MODULE\r``") * ``53 4b 59 20 4d 4f 44 55 4c 45 20`` ("``SKY MODULE ``") + + +Notes +----- + +``` +magical imports: + the core mojo fabric JS API sky:mojo:fabric:core + the asyncWait/cancelWait mojo fabric JS API (interface to IPC thread) sky:mojo:fabric:ipc + the mojom for the shell, proxying through C++ so that the shell pipe isn't exposed sky:mojo:shell + the sky API sky:core + the sky debug symbols for private APIs sky:debug +``` diff --git a/specs/animation.md b/specs/animation.md new file mode 100644 index 00000000000..e101bb4f46b --- /dev/null +++ b/specs/animation.md @@ -0,0 +1,21 @@ +Animation API +============= + +```javascript + +dictionary EasingFunctionSettings { + Float duration; // required + Callback? completionCallback = null; +} + +abstract class EasingFunction { + abstract constructor (EasingFunctionSettings settings); + abstract Float getFactor(Float time); + // calls completionCallback if time >= duration + // then returns a number ostensibly in the range 0.0 to 1.0 + // (but it could in practice go outside this range, e.g. for + // animation styles that overreach then come back) +} + + +``` diff --git a/specs/apis.md b/specs/apis.md deleted file mode 100644 index f364d85b0a4..00000000000 --- a/specs/apis.md +++ /dev/null @@ -1,553 +0,0 @@ -APIs -==== - -The Sky core API ----------------- - -```javascript -module 'sky:core' { - - // EVENTS - - class Event { - constructor (String type, Boolean bubbles = true, any data = null); // O(1) - readonly attribute String type; // O(1) - readonly attribute Boolean bubbles; // O(1) - attribute any data; // O(1) - - readonly attribute EventTarget target; // O(1) - attribute Boolean handled; // O(1) - attribute any result; // O(1) - - // TODO(ianh): do events get blocked at scope boundaries, e.g. focus events when both sides are in the scope? - // TODO(ianh): do events get retargetted, e.g. focus when leaving a custom element? - } - - callback EventListener any (Event event); - // if the return value is not undefined: - // assign it to event.result - // set event.handled to true - - abstract class EventTarget { - any dispatchEvent(Event event); // O(N) in total number of listeners for this type in the chain - // sets event.handled to false and event.result to undefined - // makes a record of the event target chain by calling getEventDispatchChain() - // invokes all the handlers on the chain in turn - // returns event.result - virtual Array getEventDispatchChain(); // O(1) // returns [] - void addEventListener(String type, EventListener listener); // O(1) - void removeEventListener(String type, EventListener listener); // O(N) in event listeners with that type - private Array getRegisteredEventListenerTypes(); // O(N) - private Array getRegisteredEventListenersForType(String type); // O(N) - } - - class CustomEventTarget : EventTarget { // implemented in JS - constructor (); // O(1) - attribute EventTarget parentNode; // getter O(1), setter O(N) in height of tree, throws if this would make a loop - - virtual Array getEventDispatchChain(); // O(N) in height of tree // implements EventTarget.getEventDispatchChain() - // let result = []; - // let node = this; - // while (node) { - // result.push(node); - // node = node.parentNode; - // } - // return result; - - // you can inherit from this to make your object into an event target - // or you can inherit from EventTarget and implement your own getEventDispatchChain() - } - - - - // DOM - - typedef ChildNode (Element or Text); - typedef ChildArgument (Element or Text or String); - - abstract class Node : EventTarget { // implemented in C++ - readonly attribute TreeScope? ownerScope; // O(1) - - readonly attribute ParentNode? parentNode; // O(1) - readonly attribute Element? parentElement; // O(1) // if parentNode isn't an element, returns null - readonly attribute ChildNode? previousSibling; // O(1) - readonly attribute ChildNode? nextSibling; // O(1) - - virtual Array getEventDispatchChain(); // O(N) in number of ancestors across shadow trees // implements EventTarget.getEventDispatchChain() - // returns the event dispatch chain (including handling shadow trees) - - // the following all throw if parentNode is null - void insertBefore(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants - void insertAfter(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants - void replaceWith(ChildArgument... nodes); // O(N) in number of descendants plus arguments plus all their descendants - void remove(); // O(N) in number of descendants - Node cloneNode(Boolean deep = false); // O(1) if deep=false, O(N) in the number of descendants if deep=true - - // called when parentNode changes - virtual void parentChangeCallback(ParentNode? oldParent, ParentNode? newParent, ChildNode? previousSibling, ChildNode? nextSibling); // O(N) in descendants (calls attached/detached) - virtual void attachedCallback(); // noop - virtual void detachedCallback(); // noop - } - - abstract class ParentNode : Node { - readonly attribute ChildNode? firstChild; // O(1) - readonly attribute ChildNode? lastChild; // O(1) - - // Returns a new Array every time. - Array getChildNodes(); // O(N) in number of child nodes - Array getChildElements(); // O(N) in number of child nodes // TODO(ianh): might not be necessary if we have the parser drop unnecessary whitespace text nodes - - void append(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants - void prepend(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants - void replaceChildrenWith(ChildArgument... nodes); // O(N) in number of descendants plus arguments plus all their descendants - } - - class Attr { - constructor (String name, String value = ''); // O(1) - readonly attribute String name; // O(1) - readonly attribute String value; // O(1) - } - - abstract class Element : ParentNode { - readonly attribute String tagName; // O(1) - - Boolean hasAttribute(String name); // O(N) in number of attributes - String getAttribute(String name); // O(N) in number of attributes - void setAttribute(String name, String value = ''); // O(N) in number of attributes - void removeAttribute(String name); // O(N) in number of attributes - - // Returns a new Array and new Attr instances every time. - Array getAttributes(); // O(N) in number of attributes - - readonly attribute ShadowRoot? shadowRoot; // O(1) // returns the shadow root - Array getDestinationInsertionPoints(); // O(N) in number of insertion points the node is in - - virtual void endTagParsedCallback(); // noop - virtual void attributeChangeCallback(String name, String? oldValue, String? newValue); // noop - // TODO(ianh): does a node ever need to know when it's been redistributed? - - readonly attribute ElementStyleDeclarationList style; // O(1) - virtual LayoutManagerConstructor getLayoutManager(RenderNode renderNode); // O(1) - // default implementation looks up the 'display' property and returns the value: - // if (renderNode) - // return renderNode.getProperty(phDisplay); - // return null; - readonly attribute RenderNode? renderNode; // O(1) - // this will be null until the first time it is rendered - void resetLayoutManager(); // O(1) - // if renderNode is non-null: - // sets renderNode.layoutManager to null - // sets renderNode.needsManager to true - } - - class Text : Node { - constructor (String value = ''); // O(1) - attribute String value; // O(1) - - void replaceWith(String node); // O(1) // special case override of Node.replaceWith() - - virtual void valueChangeCallback(String? oldValue, String? newValue); // noop - } - - class DocumentFragment : ParentNode { - constructor (ChildArguments... nodes); // O(N) in number of arguments plus all their descendants - } - - abstract class TreeScope : ParentNode { - readonly attribute Document? ownerDocument; // O(1) - readonly attribute TreeScope? parentScope; // O(1) - - Element? findId(String id); // O(1) - } - - class ShadowRoot : TreeScope { - constructor (Element host); // O(1) // note that there is no way in the API to use a newly created ShadowRoot - readonly attribute Element host; // O(1) - } - - class Document : TreeScope { - constructor (ChildArguments... nodes); // O(N) in number of arguments plus all their descendants - } - - class SelectorQuery { - constructor (String selector); // O(F()) where F() is the complexity of the selector - - Boolean matches(Element element); // O(F()) - Element? find(Element root); // O(N*F())+O(M) where N is the number of descendants and M the average depth of the tree - Element? find(DocumentFragment root); // O(N*F())+O(M) where N is the number of descendants and M the average depth of the tree - Element? find(TreeScope root); // O(N*F()) where N is the number of descendants - Array findAll(Element root); // O(N*F())+O(N*M) where N is the number of descendants and M the average depth of the tree - Array findAll(DocumentFragment root); // O(N*F())+O(N*M) where N is the number of descendants and M the average depth of the tree - Array findAll(TreeScope root); // O(N*F()) where N is the number of descendants - } - - - // BUILT-IN ELEMENTS - - class ImportElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "import" - constructor attribute Boolean shadow; // O(1) // false - } - class TemplateElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "template" - constructor attribute Boolean shadow; // O(1) // false - - readonly attribute DocumentFragment content; // O(1) - } - class ScriptElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "script" - constructor attribute Boolean shadow; // O(1) // false - } - class StyleElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "style" - constructor attribute Boolean shadow; // O(1) // false - - Array getRules(); // O(N) in rules - } - class ContentElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "content" - constructor attribute Boolean shadow; // O(1) // false - - Array getDistributedNodes(); // O(N) in distributed nodes - } - class ImgElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "img" - constructor attribute Boolean shadow; // O(1) // false - } - class DivElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "div" - constructor attribute Boolean shadow; // O(1) // false - } - class SpanElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "span" - constructor attribute Boolean shadow; // O(1) // false - } - class IframeElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "iframe" - constructor attribute Boolean shadow; // O(1) // false - } - class TElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "t" - constructor attribute Boolean shadow; // O(1) // false - } - class AElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "a" - constructor attribute Boolean shadow; // O(1) // false - } - class TitleElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "title" - constructor attribute Boolean shadow; // O(1) // false - } - class ErrorElement : Element { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - constructor attribute String tagName; // O(1) // "error" - constructor attribute Boolean shadow; // O(1) // false - } - - - - // MODULES - - callback InternalElementConstructor void (Module module); - dictionary ElementRegistration { - String tagName; - Boolean shadow = false; - InternalElementConstructor? constructor = null; - } - - interface ElementConstructor { - constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants - constructor (ChildArguments... nodes); // shorthand - constructor (Dictionary attributes); // shorthand - constructor (); // shorthand - - constructor attribute String tagName; - constructor attribute Boolean shadow; - } - - abstract class AbstractModule : EventTarget { - readonly attribute Document document; // O(1) // the Documentof the module or application - Promise import(String url); // O(Yikes) // returns the module's exports - private Array getImports(); O(N) // returns the Module objects of all the imported modules - - readonly attribute String url; - - ElementConstructor registerElement(ElementRegistration options); // O(1) - // if you call registerElement() with an object that was created by - // registerElement(), it just returns the object after registering it, - // rather than creating a new constructor - // otherwise, it proceeds as follows: - // 1. let constructor be the constructor passed in, if any - // 2. let prototype be the constructor's prototype; if there is no - // constructor, let prototype be Element - // 3. create a new Function that: - // 1. throws if not called as a constructor - // 2. creates an actual Element object - // 3. initialises the shadow tree if shadow on the options is true - // 4. calls constructor, if it's not null, with the module as the argument - // 4. let that new Function's prototype be the aforementioned prototype - // 5. let that new Function have tagName and shadow properties set to - // the values passed in on options - // 6. register the new element - - readonly attribute ScriptElement? currentScript; // O(1) // returns the -``` - -### Types ### - -The following types are available: - -* ``Integer`` - WebIDL ``long long`` -* ``Float`` - WebIDL ``double`` -* ``Infinity`` - singleton type with value ``Infinity`` -* ``String`` - WebIDL ``USVString`` -* ``Boolean`` - WebIDL ``boolean`` -# ``Object`` - WebIDL ``object`` (``ClassName`` can be used as a literal for this type) -* ``ClassName`` - an instance of the class ClassName -* ``Class`` - a class ClassName or one of its subclasses (not an instance) -* ``DictionaryName`` - an instance of the dictionary DictionaryName -* ``Promise`` - WebIDL ``Promise`` -* ``Generator`` - An ECMAScript generator function that returns data of the given type -* ``Array`` - WebIDL ``sequence`` -* ``Dictionary`` - unordered set of name-value String-Type pairs with no duplicate names -* ``Type?`` - union of Type and the singleton type with value ``null`` (WebIDL nullable) -* ``(Type1 or Type2)`` - union of Type1 and Type2 (WebIDL union) -* ``any`` - union of all types (WebIDL ``any``) - -Methods that return nothing (undefined, in JS) use the keyword "void" -instead of a type. - - -TODO(ianh): Define in detail how this actually works - - -Mojom IDL ---------- - -The Mojom IDL language is used to describe the APIs exposed over Mojo -pipes. - -Mojom IDL definitions are typically compiled to wrappers in each -language, which are then used as imports. - -TODO(ianh): Define in detail how this actually works - - -Notes ------ -```javascript -global object = {} // with Math, RegExp, etc - -magical imports: - the core mojo fabric JS API sky:mojo:fabric:core - the asyncWait/cancelWait mojo fabric JS API (interface to IPC thread) sky:mojo:fabric:ipc - the mojom for the shell, proxying through C++ so that the shell pipe isn't exposed sky:mojo:shell - the sky API sky:core - the sky debug symbols for private APIs sky:debug -``` - -TODO(ianh): determine if we want to separate the "this" from the -Document, especially for Modules, so that exposing a module's element -doesn't expose the module's exports attribute. diff --git a/specs/dom.md b/specs/dom.md new file mode 100644 index 00000000000..6cfe67fb122 --- /dev/null +++ b/specs/dom.md @@ -0,0 +1,257 @@ +Sky DOM APIs +============ + +```javascript + +// DOM + +typedef ChildNode (Element or Text); +typedef ChildArgument (Element or Text or String); + +abstract class Node : EventTarget { // implemented in C++ + readonly attribute TreeScope? ownerScope; // O(1) + + readonly attribute ParentNode? parentNode; // O(1) + readonly attribute Element? parentElement; // O(1) // if parentNode isn't an element, returns null + readonly attribute ChildNode? previousSibling; // O(1) + readonly attribute ChildNode? nextSibling; // O(1) + + virtual Array getEventDispatchChain(); // O(N) in number of ancestors across shadow trees // implements EventTarget.getEventDispatchChain() + // returns the event dispatch chain (including handling shadow trees) + + // the following all throw if parentNode is null + void insertBefore(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants + void insertAfter(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants + void replaceWith(ChildArgument... nodes); // O(N) in number of descendants plus arguments plus all their descendants + void remove(); // O(N) in number of descendants + Node cloneNode(Boolean deep = false); // O(1) if deep=false, O(N) in the number of descendants if deep=true + + // called when parentNode changes + virtual void parentChangeCallback(ParentNode? oldParent, ParentNode? newParent, ChildNode? previousSibling, ChildNode? nextSibling); // O(N) in descendants (calls attached/detached) + virtual void attachedCallback(); // noop + virtual void detachedCallback(); // noop +} + +abstract class ParentNode : Node { + readonly attribute ChildNode? firstChild; // O(1) + readonly attribute ChildNode? lastChild; // O(1) + + // Returns a new Array every time. + Array getChildNodes(); // O(N) in number of child nodes + Array getChildElements(); // O(N) in number of child nodes // TODO(ianh): might not be necessary if we have the parser drop unnecessary whitespace text nodes + + void append(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants + void prepend(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants + void replaceChildrenWith(ChildArgument... nodes); // O(N) in number of descendants plus arguments plus all their descendants +} + +class Attr { + constructor (String name, String value = ''); // O(1) + readonly attribute String name; // O(1) + readonly attribute String value; // O(1) +} + +abstract class Element : ParentNode { + readonly attribute String tagName; // O(1) + + Boolean hasAttribute(String name); // O(N) in number of attributes + String getAttribute(String name); // O(N) in number of attributes + void setAttribute(String name, String value = ''); // O(N) in number of attributes + void removeAttribute(String name); // O(N) in number of attributes + + // Returns a new Array and new Attr instances every time. + Array getAttributes(); // O(N) in number of attributes + + readonly attribute ShadowRoot? shadowRoot; // O(1) // returns the shadow root + Array getDestinationInsertionPoints(); // O(N) in number of insertion points the node is in + + virtual void endTagParsedCallback(); // noop + virtual void attributeChangeCallback(String name, String? oldValue, String? newValue); // noop + // TODO(ianh): does a node ever need to know when it's been redistributed? + + readonly attribute ElementStyleDeclarationList style; // O(1) + readonly attribute RenderNode? renderNode; // O(1) + // this will be null until the first time it is rendered + virtual LayoutManagerConstructor getLayoutManager(); // O(1) + // default implementation looks up the 'display' property and returns the value: + // if (renderNode) + // return renderNode.getProperty(phDisplay); + // return null; + void resetLayoutManager(); // O(1) + // if renderNode is non-null: + // sets renderNode.layoutManager to null + // sets renderNode.needsManager to true +} + +class Text : Node { + constructor (String value = ''); // O(1) + attribute String value; // O(1) + + void replaceWith(String node); // O(1) // special case override of Node.replaceWith() + + virtual void valueChangeCallback(String? oldValue, String? newValue); // noop +} + +class DocumentFragment : ParentNode { + constructor (ChildArguments... nodes); // O(N) in number of arguments plus all their descendants +} + +abstract class TreeScope : ParentNode { + readonly attribute Document? ownerDocument; // O(1) + readonly attribute TreeScope? parentScope; // O(1) + + Element? findId(String id); // O(1) +} + +class ShadowRoot : TreeScope { + constructor (Element host); // O(1) // note that there is no way in the API to use a newly created ShadowRoot + readonly attribute Element host; // O(1) +} + +class Document : TreeScope { + constructor (ChildArguments... nodes); // O(N) in number of arguments plus all their descendants +} + +class SelectorQuery { + constructor (String selector); // O(F()) where F() is the complexity of the selector + + Boolean matches(Element element); // O(F()) + Element? find(Element root); // O(N*F())+O(M) where N is the number of descendants and M the average depth of the tree + Element? find(DocumentFragment root); // O(N*F())+O(M) where N is the number of descendants and M the average depth of the tree + Element? find(TreeScope root); // O(N*F()) where N is the number of descendants + Array findAll(Element root); // O(N*F())+O(N*M) where N is the number of descendants and M the average depth of the tree + Array findAll(DocumentFragment root); // O(N*F())+O(N*M) where N is the number of descendants and M the average depth of the tree + Array findAll(TreeScope root); // O(N*F()) where N is the number of descendants +} + + +// BUILT-IN ELEMENTS + +class ImportElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "import" + constructor attribute Boolean shadow; // O(1) // false +} +class TemplateElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "template" + constructor attribute Boolean shadow; // O(1) // false + + readonly attribute DocumentFragment content; // O(1) +} +class ScriptElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "script" + constructor attribute Boolean shadow; // O(1) // false +} +class StyleElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "style" + constructor attribute Boolean shadow; // O(1) // false + + Array getRules(); // O(N) in rules +} +class ContentElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "content" + constructor attribute Boolean shadow; // O(1) // false + + Array getDistributedNodes(); // O(N) in distributed nodes +} +class ImgElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "img" + constructor attribute Boolean shadow; // O(1) // false +} +class DivElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "div" + constructor attribute Boolean shadow; // O(1) // false +} +class SpanElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "span" + constructor attribute Boolean shadow; // O(1) // false +} +class IframeElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "iframe" + constructor attribute Boolean shadow; // O(1) // false +} +class TElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "t" + constructor attribute Boolean shadow; // O(1) // false +} +class AElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "a" + constructor attribute Boolean shadow; // O(1) // false +} +class TitleElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "title" + constructor attribute Boolean shadow; // O(1) // false +} +class ErrorElement : Element { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + constructor attribute String tagName; // O(1) // "error" + constructor attribute Boolean shadow; // O(1) // false +} + +callback InternalElementConstructor void (Module module); +dictionary ElementRegistration { + String tagName; + Boolean shadow = false; + InternalElementConstructor? constructor = null; +} + +interface ElementConstructor { + constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants + constructor (ChildArguments... nodes); // shorthand + constructor (Dictionary attributes); // shorthand + constructor (); // shorthand + + constructor attribute String tagName; + constructor attribute Boolean shadow; +} +``` diff --git a/specs/events.md b/specs/events.md new file mode 100644 index 00000000000..09ecb247fb1 --- /dev/null +++ b/specs/events.md @@ -0,0 +1,55 @@ +Sky Event Model +=============== + +```javascript + // EVENTS + + class Event { + constructor (String type, Boolean bubbles = true, any data = null); // O(1) + readonly attribute String type; // O(1) + readonly attribute Boolean bubbles; // O(1) + attribute any data; // O(1) + + readonly attribute EventTarget target; // O(1) + attribute Boolean handled; // O(1) + attribute any result; // O(1) + + // TODO(ianh): do events get blocked at scope boundaries, e.g. focus events when both sides are in the scope? + // TODO(ianh): do events get retargetted, e.g. focus when leaving a custom element? + } + + callback EventListener any (Event event); + // if the return value is not undefined: + // assign it to event.result + // set event.handled to true + + abstract class EventTarget { + any dispatchEvent(Event event); // O(N) in total number of listeners for this type in the chain + // sets event.handled to false and event.result to undefined + // makes a record of the event target chain by calling getEventDispatchChain() + // invokes all the handlers on the chain in turn + // returns event.result + virtual Array getEventDispatchChain(); // O(1) // returns [] + void addEventListener(String type, EventListener listener); // O(1) + void removeEventListener(String type, EventListener listener); // O(N) in event listeners with that type + private Array getRegisteredEventListenerTypes(); // O(N) + private Array getRegisteredEventListenersForType(String type); // O(N) + } + + class CustomEventTarget : EventTarget { // implemented in JS + constructor (); // O(1) + attribute EventTarget parentNode; // getter O(1), setter O(N) in height of tree, throws if this would make a loop + + virtual Array getEventDispatchChain(); // O(N) in height of tree // implements EventTarget.getEventDispatchChain() + // let result = []; + // let node = this; + // while (node) { + // result.push(node); + // node = node.parentNode; + // } + // return result; + + // you can inherit from this to make your object into an event target + // or you can inherit from EventTarget and implement your own getEventDispatchChain() + } +``` diff --git a/specs/idl.md b/specs/idl.md new file mode 100644 index 00000000000..9cb185f6eb3 --- /dev/null +++ b/specs/idl.md @@ -0,0 +1,158 @@ +Sky IDL +======= + +The Sky IDL language is used to describe JS APIs found in Sky, in +particular, the JS APIs exposed by the four magical imports defined in +this document. + +Sky IDL definitions are typically compiled to C++ that exposes the C++ +implementations of the APIs to JavaScript. + +Sky IDL works more or less the same as Web IDL but the syntax is a bit +different. + +```javascript +module 'sky:modulename' { + + // this is a comment + + typedef NewType OldType; // useful when OldType is a commonly-used union + + callback CallbackName ReturnType (ArgumentType argumentName); + + class ClassName { + // a class corresponds to a JavaScript prototype + // corresponds to a WebIDL 'interface' + } + + abstract class Superclass { + // an abstract class can't have a non-abstract constructor + // an abstract class may have abstract constructors and methods + // an abstract class may have everything else a class can have + + abstract constructor (); + // this indicates that non-abstract subclasses must have a constructor with the given arguments + + abstract ReturnType methodCallback(); + // this method does nothing, but is included to describe the interface that subclasses will implement + // a non-abstract class must have an explicit implementation of all inherited abstract methods + + } + + class Subclass : Superclass { + // properties + readonly attribute ReturnType attributeName; // getter + attribute ReturnType attributeName; // getter and setter + + // methods and constructors + constructor (); + ReturnType method(); + // When the platform calls this method, it always invokes the "real" method, even if it's been + // deleted from the prototypes (as if it took a reference to the method at startup, and stored + // state using Symbols) + // Calling a method with fewer arguments than defined will throw. + // Calling a method with more arguments ignores the extra arguments. + virtual ReturnType methodCallback(); + // when the platform calls this, it actually calls it the way JS would, so author overrides do + // affect what gets called. Make sure if you override it that you call the superclass implementation! + // The default implementations of 'virtual' methods all end by calling the identically named method + // on the superclass, if there is such a method. + + // non-abstract classes cannot have abstract constructors or methods, and in particular, must + // have explicit non-abstract versions of any inherited abstract constructors or methods + + // properties on the constructor + constructor readonly attribute ReturnType staticName; + + // private APIs - see below + private void method(); + + // arguments and overloading are done as follows + // note that the argument names are only for documentation purposes + ReturnType method(ArgumentType argumentName1, ArgumentType argumentName2); + // the last argument's type can have "..." appended to it to indicate a varargs-like situation + ReturnType method(ArgumentType argumentName1, ArgumentType... allSubsequentArguments); + // trailing arguments can have a default value, which must be a literal of the given type + ReturnType method(ArgumentType argumentName1, ArgumentType argumentName2 = defaultValue); + } + + dictionary Options { + String foo; // if there's no default, the property must be specified or it's a TypeError + Integer bar = 4; // properties can have default values + } + + // the module can have properties and methods also + attribute String Foo; + void method(); + + interface InterfaceName { + // describes a template of a prototype, in the same syntax as a class + // not actually exposed in the runtime + } + +} +``` + +### Private APIs ### + +Private APIs are only accessible via Symbol objects, which are then +exposed on the sky:debug module's exports object as the name of the +member given in the IDL. + +For example, consider: + +```javascript +class Foo { + private void Bar(); +} +``` + +In a script with a ``foo`` object of type ``Foo``, ``foo.Bar`` is +undefined. However, it can be obtained as follows: + +```html + + + +``` + +### Types ### + +The following types are available: + +* ``Integer`` - WebIDL ``long long`` +* ``Float`` - WebIDL ``double`` +* ``Infinity`` - singleton type with value ``Infinity`` +* ``String`` - WebIDL ``USVString`` +* ``Boolean`` - WebIDL ``boolean`` +# ``Object`` - WebIDL ``object`` (``ClassName`` can be used as a literal for this type) +* ``ClassName`` - an instance of the class ClassName +* ``Class`` - a class ClassName or one of its subclasses (not an instance) +* ``DictionaryName`` - an instance of the dictionary DictionaryName +* ``Promise`` - WebIDL ``Promise`` +* ``Generator`` - An ECMAScript generator function that returns data of the given type +* ``Array`` - WebIDL ``sequence`` +* ``Dictionary`` - unordered set of name-value String-Type pairs with no duplicate names +* ``Type?`` - union of Type and the singleton type with value ``null`` (WebIDL nullable) +* ``(Type1 or Type2)`` - union of Type1 and Type2 (WebIDL union) +* ``any`` - union of all types (WebIDL ``any``) + +Methods that return nothing (undefined, in JS) use the keyword "void" +instead of a type. + + +TODO(ianh): Define in detail how this actually works + + +Mojom IDL +--------- + +The Mojom IDL language is used to describe the APIs exposed over Mojo +pipes. + +Mojom IDL definitions are typically compiled to wrappers in each +language, which are then used as imports. + +TODO(ianh): Define in detail how this actually works diff --git a/specs/modules.md b/specs/modules.md index fcd28790adb..cad32ce2ea7 100644 --- a/specs/modules.md +++ b/specs/modules.md @@ -47,6 +47,50 @@ the imported module's ``exports`` value, and for each property that is an element constructor (generated by ``registerElement()``), it adds an element to the importee's element registry. +### IDL ### + +```javascript +abstract class AbstractModule : EventTarget { + readonly attribute Document document; // O(1) // the Documentof the module or application + Promise import(String url); // O(Yikes) // returns the module's exports + private Array getImports(); O(N) // returns the Module objects of all the imported modules + + readonly attribute String url; + + ElementConstructor registerElement(ElementRegistration options); // O(1) + // if you call registerElement() with an object that was created by + // registerElement(), it just returns the object after registering it, + // rather than creating a new constructor + // otherwise, it proceeds as follows: + // 1. let constructor be the constructor passed in, if any + // 2. let prototype be the constructor's prototype; if there is no + // constructor, let prototype be Element + // 3. create a new Function that: + // 1. throws if not called as a constructor + // 2. creates an actual Element object + // 3. initialises the shadow tree if shadow on the options is true + // 4. calls constructor, if it's not null, with the module as the argument + // 4. let that new Function's prototype be the aforementioned prototype + // 5. let that new Function have tagName and shadow properties set to + // the values passed in on options + // 6. register the new element + + readonly attribute ScriptElement? currentScript; // O(1) // returns the