/* 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/. */ //! The implementation of the DOM. //! //! The DOM is comprised of interfaces (defined by specifications using //! [WebIDL](https://heycam.github.io/webidl/)) that are implemented as Rust //! structs in submodules of this module. Its implementation is documented //! below. //! //! A DOM object and its reflector //! ============================== //! //! The implementation of an interface `Foo` in Servo's DOM involves two //! related but distinct objects: //! //! * the **DOM object**: an instance of the Rust struct `dom::foo::Foo` //! (marked with the `#[dom_struct]` attribute) on the Rust heap; //! * the **reflector**: a `JSObject` allocated by SpiderMonkey, that owns the //! DOM object. //! //! Memory management //! ================= //! //! Reflectors of DOM objects, and thus the DOM objects themselves, are managed //! by the SpiderMonkey Garbage Collector. Thus, keeping alive a DOM object //! is done through its reflector. //! //! For more information, see: //! //! * rooting pointers on the stack: //! the [`Root`](bindings/root/struct.Root.html) smart pointer; //! * tracing pointers in member fields: the [`Dom`](bindings/root/struct.Dom.html), //! [`MutNullableDom`](bindings/root/struct.MutNullableDom.html) and //! [`MutDom`](bindings/root/struct.MutDom.html) smart pointers and //! [the tracing implementation](bindings/trace/index.html); //! * rooting pointers from across thread boundaries or in channels: the //! [`Trusted`](bindings/refcounted/struct.Trusted.html) smart pointer; //! //! Inheritance //! =========== //! //! Rust does not support struct inheritance, as would be used for the //! object-oriented DOM APIs. To work around this issue, Servo stores an //! instance of the superclass in the first field of its subclasses. (Note that //! it is stored by value, rather than in a smart pointer such as `Dom`.) //! //! This implies that a pointer to an object can safely be cast to a pointer //! to all its classes. //! //! This invariant is enforced by the lint in //! `plugins::lints::inheritance_integrity`. //! //! Interfaces which either derive from or are derived by other interfaces //! implement the `Castable` trait, which provides three methods `is::()`, //! `downcast::()` and `upcast::()` to cast across the type hierarchy //! and check whether a given instance is of a given type. //! //! ```ignore //! use dom::bindings::inheritance::Castable; //! use dom::element::Element; //! use dom::htmlelement::HTMLElement; //! use dom::htmlinputelement::HTMLInputElement; //! //! if let Some(elem) = node.downcast:: { //! if elem.is::() { //! return elem.upcast::(); //! } //! } //! ``` //! //! Furthermore, when discriminating a given instance against multiple //! interface types, code generation provides a convenient TypeId enum //! which can be used to write `match` expressions instead of multiple //! calls to `Castable::is::`. The `type_id()` method of an instance is //! provided by the farthest interface it derives from, e.g. `EventTarget` //! for `HTMLMediaElement`. For convenience, that method is also provided //! on the `Node` interface to avoid unnecessary upcasts to `EventTarget`. //! //! ```ignore //! use dom::bindings::inheritance::{EventTargetTypeId, NodeTypeId}; //! //! match *node.type_id() { //! EventTargetTypeId::Node(NodeTypeId::CharacterData(_)) => ..., //! EventTargetTypeId::Node(NodeTypeId::Element(_)) => ..., //! ..., //! } //! ``` //! //! Construction //! ============ //! //! DOM objects of type `T` in Servo have two constructors: //! //! * a `T::new_inherited` static method that returns a plain `T`, and //! * a `T::new` static method that returns `DomRoot`. //! //! (The result of either method can be wrapped in `Result`, if that is //! appropriate for the type in question.) //! //! The latter calls the former, boxes the result, and creates a reflector //! corresponding to it by calling `dom::bindings::utils::reflect_dom_object` //! (which yields ownership of the object to the SpiderMonkey Garbage Collector). //! This is the API to use when creating a DOM object. //! //! The former should only be called by the latter, and by subclasses' //! `new_inherited` methods. //! //! DOM object constructors in JavaScript correspond to a `T::Constructor` //! static method. This method is always fallible. //! //! Destruction //! =========== //! //! When the SpiderMonkey Garbage Collector discovers that the reflector of a //! DOM object is garbage, it calls the reflector's finalization hook. This //! function deletes the reflector's DOM object, calling its destructor in the //! process. //! //! Mutability and aliasing //! ======================= //! //! Reflectors are JavaScript objects, and as such can be freely aliased. As //! Rust does not allow mutable aliasing, mutable borrows of DOM objects are //! not allowed. In particular, any mutable fields use `Cell` or `DomRefCell` //! to manage their mutability. //! //! `Reflector` and `DomObject` //! ============================= //! //! Every DOM object has a `Reflector` as its first (transitive) member field. //! This contains a `*mut JSObject` that points to its reflector. //! //! The `FooBinding::Wrap` function creates the reflector, stores a pointer to //! the DOM object in the reflector, and initializes the pointer to the reflector //! in the `Reflector` field. //! //! The `DomObject` trait provides a `reflector()` method that returns the //! DOM object's `Reflector`. It is implemented automatically for DOM structs //! through the `#[dom_struct]` attribute. //! //! Implementing methods for a DOM object //! ===================================== //! //! * `dom::bindings::codegen::Bindings::FooBinding::FooMethods` for methods //! defined through IDL; //! * `&self` public methods for public helpers; //! * `&self` methods for private helpers. //! //! Accessing fields of a DOM object //! ================================ //! //! All fields of DOM objects are private; accessing them from outside their //! module is done through explicit getter or setter methods. //! //! Inheritance and casting //! ======================= //! //! All DOM interfaces part of an inheritance chain (i.e. interfaces //! that derive others or are derived from) implement the trait `Castable` //! which provides both downcast and upcasts. //! //! ```ignore //! # use script::dom::bindings::inheritance::Castable; //! # use script::dom::element::Element; //! # use script::dom::node::Node; //! # use script::dom::htmlelement::HTMLElement; //! fn f(element: &Element) { //! let base = element.upcast::(); //! let derived = element.downcast::().unwrap(); //! } //! ``` //! //! Adding a new DOM interface //! ========================== //! //! Adding a new interface `Foo` requires at least the following: //! //! * adding the new IDL file at `components/script/dom/webidls/Foo.webidl`; //! * creating `components/script/dom/foo.rs`; //! * listing `foo.rs` in `components/script/dom/mod.rs`; //! * defining the DOM struct `Foo` with a `#[dom_struct]` attribute, a //! superclass or `Reflector` member, and other members as appropriate; //! * implementing the //! `dom::bindings::codegen::Bindings::FooBinding::FooMethods` trait for //! `Foo`; //! * adding/updating the match arm in create_element in //! `components/script/dom/create.rs` (only applicable to new types inheriting //! from `HTMLElement`) //! //! More information is available in the [bindings module](bindings/index.html). //! //! Accessing DOM objects from layout //! ================================= //! //! Layout code can access the DOM through the //! [`LayoutDom`](bindings/root/struct.LayoutDom.html) smart pointer. This does not //! keep the DOM object alive; we ensure that no DOM code (Garbage Collection //! in particular) runs while layout is accessing the DOM. //! //! Methods accessible to layout are implemented on `LayoutDom` using //! `LayoutFooHelpers` traits. #[macro_use] pub(crate) mod macros; #[allow(unused_imports)] pub(crate) mod types { include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs")); } pub(crate) mod abortcontroller; pub(crate) mod abortsignal; #[allow(dead_code)] pub(crate) mod abstractrange; pub(crate) mod abstractworker; pub(crate) mod abstractworkerglobalscope; pub(crate) mod activation; pub(crate) mod animationevent; pub(crate) mod attr; pub(crate) mod audio; pub(crate) use self::audio::*; pub(crate) mod beforeunloadevent; pub(crate) mod bindings; pub(crate) mod blob; #[cfg(feature = "bluetooth")] pub(crate) mod bluetooth; #[cfg(feature = "bluetooth")] pub(crate) use self::bluetooth::*; pub(crate) mod broadcastchannel; pub(crate) mod bytelengthqueuingstrategy; mod canvas; pub(crate) use self::canvas::*; pub(crate) mod cdatasection; pub(crate) mod characterdata; pub(crate) mod client; pub(crate) mod clipboard; pub(crate) mod clipboardevent; pub(crate) mod clipboarditem; pub(crate) mod closeevent; pub(crate) mod comment; pub(crate) mod compositionevent; pub(crate) mod console; pub(crate) mod cookiestore; pub(crate) mod countqueuingstrategy; mod create; pub(crate) mod credentialmanagement; pub(crate) use self::credentialmanagement::*; pub(crate) mod crypto; pub(crate) mod cryptokey; pub(crate) mod csp; pub(crate) mod csppolicyviolationreport; pub(crate) mod css; pub(crate) mod cssconditionrule; pub(crate) mod cssfontfacerule; pub(crate) mod cssgroupingrule; pub(crate) mod cssimportrule; pub(crate) mod csskeyframerule; pub(crate) mod csskeyframesrule; pub(crate) mod csslayerblockrule; pub(crate) mod csslayerstatementrule; pub(crate) mod cssmediarule; pub(crate) mod cssnamespacerule; pub(crate) mod cssnesteddeclarations; pub(crate) mod cssrule; pub(crate) mod cssrulelist; pub(crate) mod cssstyledeclaration; pub(crate) mod cssstylerule; pub(crate) mod cssstylesheet; pub(crate) mod cssstylevalue; pub(crate) mod csssupportsrule; pub(crate) mod customelementregistry; pub(crate) mod customevent; pub(crate) mod customstateset; pub(crate) mod datatransfer; pub(crate) mod datatransferitem; pub(crate) mod datatransferitemlist; pub(crate) mod debuggeradddebuggeeevent; pub(crate) mod debuggergetpossiblebreakpointsevent; pub(crate) mod debuggerglobalscope; pub(crate) mod dedicatedworkerglobalscope; pub(crate) mod defaultteereadrequest; pub(crate) mod defaultteeunderlyingsource; pub(crate) mod dissimilaroriginlocation; pub(crate) mod dissimilaroriginwindow; #[allow(dead_code)] pub(crate) mod document; pub(crate) mod document_event_handler; pub(crate) mod documentfragment; pub(crate) mod documentorshadowroot; pub(crate) mod documenttype; pub(crate) mod domexception; pub(crate) mod domimplementation; pub(crate) mod dommatrix; pub(crate) mod dommatrixreadonly; pub(crate) mod domparser; pub(crate) mod dompoint; pub(crate) mod dompointreadonly; pub(crate) mod domquad; pub(crate) mod domrect; pub(crate) mod domrectlist; pub(crate) mod domrectreadonly; pub(crate) mod domstringlist; pub(crate) mod domstringmap; pub(crate) mod domtokenlist; pub(crate) mod dynamicmoduleowner; #[allow(dead_code)] pub(crate) mod element; pub(crate) mod elementinternals; pub(crate) mod errorevent; pub(crate) mod event; pub(crate) mod eventsource; pub(crate) mod eventtarget; pub(crate) mod extendableevent; pub(crate) mod extendablemessageevent; pub(crate) mod file; pub(crate) mod filelist; pub(crate) mod filereader; pub(crate) mod filereadersync; pub(crate) mod focusevent; pub(crate) mod fontface; pub(crate) mod fontfaceset; pub(crate) mod formdata; pub(crate) mod formdataevent; pub(crate) mod gamepad; pub(crate) use self::gamepad::*; #[allow(dead_code)] pub(crate) mod globalscope; pub(crate) mod hashchangeevent; pub(crate) mod headers; pub(crate) mod history; pub(crate) mod html; pub(crate) use self::html::*; pub(crate) mod idbcursor; pub(crate) mod idbcursorwithvalue; pub(crate) mod idbdatabase; pub(crate) mod idbfactory; pub(crate) mod idbindex; pub(crate) mod idbkeyrange; pub(crate) mod idbobjectstore; pub(crate) mod idbopendbrequest; pub(crate) mod idbrequest; pub(crate) mod idbtransaction; pub(crate) mod idbversionchangeevent; pub(crate) mod inputevent; pub(crate) mod intersectionobserver; pub(crate) mod intersectionobserverentry; pub(crate) mod keyboardevent; pub(crate) mod linkprocessingoptions; pub(crate) mod location; pub(crate) mod mediadeviceinfo; pub(crate) mod mediadevices; pub(crate) mod mediaerror; pub(crate) mod mediafragmentparser; pub(crate) mod medialist; pub(crate) mod mediametadata; pub(crate) mod mediaquerylist; pub(crate) mod mediaquerylistevent; pub(crate) mod mediasession; pub(crate) mod mediastream; pub(crate) mod mediastreamtrack; pub(crate) mod messagechannel; pub(crate) mod messageevent; #[allow(dead_code)] pub(crate) mod messageport; pub(crate) mod mimetype; pub(crate) mod mimetypearray; pub(crate) mod mouseevent; pub(crate) mod mutationobserver; pub(crate) mod mutationrecord; pub(crate) mod namednodemap; pub(crate) mod navigationpreloadmanager; pub(crate) mod navigator; pub(crate) mod navigatorinfo; #[allow(dead_code)] pub(crate) mod node; pub(crate) mod nodeiterator; #[allow(dead_code)] pub(crate) mod nodelist; pub(crate) mod notification; pub(crate) mod pagetransitionevent; pub(crate) mod paintsize; pub(crate) mod paintworkletglobalscope; pub(crate) mod performance; #[allow(dead_code)] pub(crate) mod performanceentry; pub(crate) mod performancemark; pub(crate) mod performancemeasure; pub(crate) mod performancenavigation; pub(crate) mod performancenavigationtiming; #[allow(dead_code)] pub(crate) mod performanceobserver; pub(crate) mod performanceobserverentrylist; pub(crate) mod performancepainttiming; pub(crate) mod performanceresourcetiming; pub(crate) mod permissions; pub(crate) mod permissionstatus; pub(crate) mod pipelineid; pub(crate) mod plugin; pub(crate) mod pluginarray; #[allow(dead_code)] pub(crate) mod pointerevent; pub(crate) mod popstateevent; pub(crate) mod processinginstruction; pub(crate) mod progressevent; #[allow(dead_code)] pub(crate) mod promise; pub(crate) mod promisenativehandler; pub(crate) mod promiserejectionevent; pub(crate) mod quotaexceedederror; pub(crate) mod radionodelist; pub(crate) mod range; pub(crate) mod raredata; #[allow(dead_code)] pub(crate) mod readablebytestreamcontroller; pub(crate) mod readablestream; pub(crate) mod readablestreambyobreader; pub(crate) mod readablestreambyobrequest; pub(crate) mod readablestreamdefaultcontroller; pub(crate) mod readablestreamdefaultreader; pub(crate) mod readablestreamgenericreader; pub(crate) mod reportingendpoint; pub(crate) mod reportingobserver; pub(crate) mod request; pub(crate) mod resizeobserver; pub(crate) mod resizeobserverentry; pub(crate) mod resizeobserversize; pub(crate) mod response; pub(crate) mod screen; mod scrolling_box; pub(crate) mod securitypolicyviolationevent; pub(crate) mod selection; #[allow(dead_code)] pub(crate) mod serviceworker; pub(crate) mod serviceworkercontainer; pub(crate) mod serviceworkerglobalscope; #[allow(dead_code)] pub(crate) mod serviceworkerregistration; pub(crate) mod servointernals; #[allow(dead_code)] pub(crate) mod servoparser; pub(crate) mod shadowroot; pub(crate) mod staticrange; pub(crate) mod storage; pub(crate) mod storageevent; pub(crate) mod stylepropertymapreadonly; pub(crate) mod stylesheet; pub(crate) mod stylesheetcontentscache; pub(crate) mod stylesheetlist; pub(crate) mod submitevent; pub(crate) mod subtlecrypto; pub(crate) mod svgelement; pub(crate) mod svggraphicselement; pub(crate) mod svgimageelement; pub(crate) mod svgsvgelement; #[cfg(feature = "testbinding")] pub(crate) mod testbinding; #[cfg(feature = "testbinding")] pub(crate) mod testbindingiterable; #[cfg(feature = "testbinding")] pub(crate) mod testbindingmaplikewithinterface; #[cfg(feature = "testbinding")] pub(crate) mod testbindingmaplikewithprimitive; #[cfg(feature = "testbinding")] pub(crate) mod testbindingpairiterable; #[cfg(feature = "testbinding")] pub(crate) mod testbindingproxy; #[cfg(feature = "testbinding")] pub(crate) mod testbindingsetlikewithinterface; #[cfg(feature = "testbinding")] pub(crate) mod testbindingsetlikewithprimitive; #[cfg(feature = "testbinding")] pub(crate) mod testns; #[cfg(feature = "testbinding")] pub(crate) mod testutils; #[cfg(feature = "testbinding")] pub(crate) mod testworklet; #[cfg(feature = "testbinding")] pub(crate) mod testworkletglobalscope; pub(crate) mod text; pub(crate) mod textcontrol; pub(crate) mod textdecoder; pub(crate) mod textdecodercommon; pub(crate) mod textdecoderstream; pub(crate) mod textencoder; pub(crate) mod textencoderstream; pub(crate) mod texttrack; pub(crate) mod texttrackcue; pub(crate) mod texttrackcuelist; pub(crate) mod texttracklist; #[allow(dead_code)] pub(crate) mod timeranges; pub(crate) mod touch; pub(crate) mod touchevent; pub(crate) mod touchlist; pub(crate) mod trackevent; pub(crate) mod transitionevent; pub(crate) mod treewalker; pub(crate) mod trustedhtml; pub(crate) mod trustedscript; pub(crate) mod trustedscripturl; pub(crate) mod trustedtypepolicy; pub(crate) mod trustedtypepolicyfactory; pub(crate) mod uievent; pub(crate) mod underlyingsourcecontainer; pub(crate) mod url; pub(crate) mod urlhelper; pub(crate) mod urlpattern; pub(crate) mod urlsearchparams; pub(crate) mod userscripts; pub(crate) mod validation; pub(crate) mod validitystate; pub(crate) mod values; pub(crate) mod videotrack; pub(crate) mod videotracklist; pub(crate) mod virtualmethods; pub(crate) mod visibilitystateentry; pub(crate) mod vttcue; pub(crate) mod vttregion; pub(crate) mod webgl; pub(crate) use self::webgl::extensions::ext::*; pub(crate) use self::webgl::*; pub(crate) mod websocket; #[cfg(feature = "webxr")] mod webxr; #[cfg(feature = "webxr")] pub(crate) use self::webxr::*; #[cfg(feature = "webgpu")] pub(crate) mod webgpu; #[cfg(feature = "webgpu")] pub(crate) use self::webgpu::*; #[cfg(not(feature = "webgpu"))] pub(crate) mod gpucanvascontext; pub(crate) mod webrtc; pub(crate) use self::webrtc::*; pub(crate) mod transformstream; pub(crate) mod transformstreamdefaultcontroller; pub(crate) mod wheelevent; #[allow(dead_code)] pub(crate) mod window; #[allow(dead_code)] pub(crate) mod windowproxy; pub(crate) mod worker; #[allow(dead_code)] pub(crate) mod workerglobalscope; pub(crate) mod workerlocation; pub(crate) mod workernavigator; pub(crate) mod worklet; pub(crate) mod workletglobalscope; pub(crate) mod writablestream; pub(crate) mod writablestreamdefaultcontroller; pub(crate) mod writablestreamdefaultwriter; pub(crate) mod xmldocument; pub(crate) mod xmlhttprequest; pub(crate) mod xmlhttprequesteventtarget; pub(crate) mod xmlhttprequestupload; pub(crate) mod xmlserializer; pub(crate) mod xpathevaluator; pub(crate) mod xpathexpression; pub(crate) mod xpathresult;