script/dom/mod.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! The implementation of the DOM.
6//!
7//! The DOM is comprised of interfaces (defined by specifications using
8//! [WebIDL](https://heycam.github.io/webidl/)) that are implemented as Rust
9//! structs in submodules of this module. Its implementation is documented
10//! below.
11//!
12//! A DOM object and its reflector
13//! ==============================
14//!
15//! The implementation of an interface `Foo` in Servo's DOM involves two
16//! related but distinct objects:
17//!
18//! * the **DOM object**: an instance of the Rust struct `dom::foo::Foo`
19//! (marked with the `#[dom_struct]` attribute) on the Rust heap;
20//! * the **reflector**: a `JSObject` allocated by SpiderMonkey, that owns the
21//! DOM object.
22//!
23//! Memory management
24//! =================
25//!
26//! Reflectors of DOM objects, and thus the DOM objects themselves, are managed
27//! by the SpiderMonkey Garbage Collector. Thus, keeping alive a DOM object
28//! is done through its reflector.
29//!
30//! For more information, see:
31//!
32//! * rooting pointers on the stack:
33//! the [`Root`](bindings/root/struct.Root.html) smart pointer;
34//! * tracing pointers in member fields: the [`Dom`](bindings/root/struct.Dom.html),
35//! [`MutNullableDom`](bindings/root/struct.MutNullableDom.html) and
36//! [`MutDom`](bindings/root/struct.MutDom.html) smart pointers and
37//! [the tracing implementation](bindings/trace/index.html);
38//! * rooting pointers from across thread boundaries or in channels: the
39//! [`Trusted`](bindings/refcounted/struct.Trusted.html) smart pointer;
40//!
41//! Inheritance
42//! ===========
43//!
44//! Rust does not support struct inheritance, as would be used for the
45//! object-oriented DOM APIs. To work around this issue, Servo stores an
46//! instance of the superclass in the first field of its subclasses. (Note that
47//! it is stored by value, rather than in a smart pointer such as `Dom<T>`.)
48//!
49//! This implies that a pointer to an object can safely be cast to a pointer
50//! to all its classes.
51//!
52//! This invariant is enforced by the lint in
53//! `plugins::lints::inheritance_integrity`.
54//!
55//! Interfaces which either derive from or are derived by other interfaces
56//! implement the `Castable` trait, which provides three methods `is::<T>()`,
57//! `downcast::<T>()` and `upcast::<T>()` to cast across the type hierarchy
58//! and check whether a given instance is of a given type.
59//!
60//! ```ignore
61//! use dom::bindings::inheritance::Castable;
62//! use dom::element::Element;
63//! use dom::htmlelement::HTMLElement;
64//! use dom::htmlinputelement::HTMLInputElement;
65//!
66//! if let Some(elem) = node.downcast::<Element> {
67//! if elem.is::<HTMLInputElement>() {
68//! return elem.upcast::<HTMLElement>();
69//! }
70//! }
71//! ```
72//!
73//! Furthermore, when discriminating a given instance against multiple
74//! interface types, code generation provides a convenient TypeId enum
75//! which can be used to write `match` expressions instead of multiple
76//! calls to `Castable::is::<T>`. The `type_id()` method of an instance is
77//! provided by the farthest interface it derives from, e.g. `EventTarget`
78//! for `HTMLMediaElement`. For convenience, that method is also provided
79//! on the `Node` interface to avoid unnecessary upcasts to `EventTarget`.
80//!
81//! ```ignore
82//! use dom::bindings::inheritance::{EventTargetTypeId, NodeTypeId};
83//!
84//! match *node.type_id() {
85//! EventTargetTypeId::Node(NodeTypeId::CharacterData(_)) => ...,
86//! EventTargetTypeId::Node(NodeTypeId::Element(_)) => ...,
87//! ...,
88//! }
89//! ```
90//!
91//! Construction
92//! ============
93//!
94//! DOM objects of type `T` in Servo have two constructors:
95//!
96//! * a `T::new_inherited` static method that returns a plain `T`, and
97//! * a `T::new` static method that returns `DomRoot<T>`.
98//!
99//! (The result of either method can be wrapped in `Result`, if that is
100//! appropriate for the type in question.)
101//!
102//! The latter calls the former, boxes the result, and creates a reflector
103//! corresponding to it by calling `dom::bindings::utils::reflect_dom_object`
104//! (which yields ownership of the object to the SpiderMonkey Garbage Collector).
105//! This is the API to use when creating a DOM object.
106//!
107//! The former should only be called by the latter, and by subclasses'
108//! `new_inherited` methods.
109//!
110//! DOM object constructors in JavaScript correspond to a `T::Constructor`
111//! static method. This method is always fallible.
112//!
113//! Destruction
114//! ===========
115//!
116//! When the SpiderMonkey Garbage Collector discovers that the reflector of a
117//! DOM object is garbage, it calls the reflector's finalization hook. This
118//! function deletes the reflector's DOM object, calling its destructor in the
119//! process.
120//!
121//! Mutability and aliasing
122//! =======================
123//!
124//! Reflectors are JavaScript objects, and as such can be freely aliased. As
125//! Rust does not allow mutable aliasing, mutable borrows of DOM objects are
126//! not allowed. In particular, any mutable fields use `Cell` or `DomRefCell`
127//! to manage their mutability.
128//!
129//! `Reflector` and `DomObject`
130//! =============================
131//!
132//! Every DOM object has a `Reflector` as its first (transitive) member field.
133//! This contains a `*mut JSObject` that points to its reflector.
134//!
135//! The `FooBinding::Wrap` function creates the reflector, stores a pointer to
136//! the DOM object in the reflector, and initializes the pointer to the reflector
137//! in the `Reflector` field.
138//!
139//! The `DomObject` trait provides a `reflector()` method that returns the
140//! DOM object's `Reflector`. It is implemented automatically for DOM structs
141//! through the `#[dom_struct]` attribute.
142//!
143//! Implementing methods for a DOM object
144//! =====================================
145//!
146//! * `dom::bindings::codegen::Bindings::FooBinding::FooMethods` for methods
147//! defined through IDL;
148//! * `&self` public methods for public helpers;
149//! * `&self` methods for private helpers.
150//!
151//! Accessing fields of a DOM object
152//! ================================
153//!
154//! All fields of DOM objects are private; accessing them from outside their
155//! module is done through explicit getter or setter methods.
156//!
157//! Inheritance and casting
158//! =======================
159//!
160//! All DOM interfaces part of an inheritance chain (i.e. interfaces
161//! that derive others or are derived from) implement the trait `Castable`
162//! which provides both downcast and upcasts.
163//!
164//! ```ignore
165//! # use script::dom::bindings::inheritance::Castable;
166//! # use script::dom::element::Element;
167//! # use script::dom::node::Node;
168//! # use script::dom::htmlelement::HTMLElement;
169//! fn f(element: &Element) {
170//! let base = element.upcast::<Node>();
171//! let derived = element.downcast::<HTMLElement>().unwrap();
172//! }
173//! ```
174//!
175//! Adding a new DOM interface
176//! ==========================
177//!
178//! Adding a new interface `Foo` requires at least the following:
179//!
180//! * adding the new IDL file at `components/script/dom/webidls/Foo.webidl`;
181//! * creating `components/script/dom/foo.rs`;
182//! * listing `foo.rs` in `components/script/dom/mod.rs`;
183//! * defining the DOM struct `Foo` with a `#[dom_struct]` attribute, a
184//! superclass or `Reflector` member, and other members as appropriate;
185//! * implementing the
186//! `dom::bindings::codegen::Bindings::FooBinding::FooMethods` trait for
187//! `Foo`;
188//! * adding/updating the match arm in create_element in
189//! `components/script/dom/create.rs` (only applicable to new types inheriting
190//! from `HTMLElement`)
191//!
192//! More information is available in the [bindings module](bindings/index.html).
193//!
194//! Accessing DOM objects from layout
195//! =================================
196//!
197//! Layout code can access the DOM through the
198//! [`LayoutDom`](bindings/root/struct.LayoutDom.html) smart pointer. This does not
199//! keep the DOM object alive; we ensure that no DOM code (Garbage Collection
200//! in particular) runs while layout is accessing the DOM.
201//!
202//! Methods accessible to layout are implemented on `LayoutDom<Foo>` using
203//! `LayoutFooHelpers` traits.
204
205#[macro_use]
206pub(crate) mod macros;
207
208pub(crate) mod types {
209 include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs"));
210}
211
212pub(crate) mod abortcontroller;
213pub(crate) mod abortsignal;
214#[expect(dead_code)]
215pub(crate) mod abstractrange;
216pub(crate) mod activation;
217pub(crate) mod animations;
218pub(crate) use self::animations::*;
219pub(crate) mod attr;
220pub(crate) mod audio;
221pub(crate) use self::audio::*;
222pub(crate) mod bindings;
223pub(crate) mod blob;
224#[cfg(feature = "bluetooth")]
225pub(crate) mod bluetooth;
226#[cfg(feature = "bluetooth")]
227pub(crate) use self::bluetooth::*;
228pub(crate) mod broadcastchannel;
229mod canvas;
230pub(crate) use self::canvas::*;
231
232pub(crate) mod cdatasection;
233pub(crate) mod characterdata;
234pub(crate) mod client;
235pub(crate) mod clipboard;
236pub(crate) use self::clipboard::*;
237pub(crate) mod comment;
238pub(crate) mod console;
239pub(crate) mod cookiestore;
240mod create;
241pub(crate) mod credentialmanagement;
242pub(crate) use self::credentialmanagement::*;
243pub(crate) mod css;
244pub(crate) use self::css::*;
245pub(crate) mod customelementregistry;
246pub(crate) mod customstateset;
247pub(crate) mod datatransfer;
248pub(crate) use self::datatransfer::*;
249pub(crate) mod debugger;
250pub(crate) use self::debugger::*;
251pub(crate) mod dissimilaroriginlocation;
252pub(crate) mod dissimilaroriginwindow;
253#[expect(dead_code)]
254pub(crate) mod document;
255pub(crate) use self::document::*;
256pub(crate) mod domexception;
257pub(crate) mod domimplementation;
258pub(crate) mod dommatrix;
259pub(crate) mod dommatrixreadonly;
260pub(crate) mod domparser;
261pub(crate) mod dompoint;
262pub(crate) mod dompointreadonly;
263pub(crate) mod domquad;
264pub(crate) mod domrect;
265pub(crate) mod domrectlist;
266pub(crate) mod domrectreadonly;
267pub(crate) mod domstringlist;
268pub(crate) mod domstringmap;
269pub(crate) mod domtokenlist;
270pub(crate) mod element;
271pub(crate) mod elementinternals;
272pub(crate) mod encoding;
273pub(crate) use self::encoding::*;
274pub(crate) mod event;
275pub(crate) use self::event::*;
276pub(crate) mod eventsource;
277pub(crate) mod execcommand;
278pub(crate) mod fetchlaterresult;
279pub(crate) mod file;
280pub(crate) use self::file::*;
281pub(crate) mod formdata;
282pub(crate) mod fullscreen;
283#[cfg(feature = "gamepad")]
284pub(crate) mod gamepad;
285#[cfg(feature = "gamepad")]
286pub(crate) use self::gamepad::*;
287pub(crate) mod geolocation;
288pub(crate) use self::geolocation::*;
289pub(crate) mod global_scope_script_execution;
290pub(crate) mod globalscope;
291pub(crate) mod headers;
292pub(crate) mod history;
293pub(crate) mod html;
294pub(crate) use self::html::*;
295pub(crate) mod indexeddb;
296pub(crate) use self::indexeddb::*;
297pub(crate) mod intersectionobserver;
298pub(crate) mod intersectionobserverentry;
299pub(crate) mod location;
300pub(crate) mod media;
301pub(crate) use self::media::*;
302pub(crate) mod messagechannel;
303#[expect(dead_code)]
304pub(crate) mod messageport;
305pub(crate) mod mimetype;
306pub(crate) mod mimetypearray;
307pub(crate) mod mutationobserver;
308pub(crate) use self::mutationobserver::*;
309pub(crate) mod namednodemap;
310pub(crate) mod navigationpreloadmanager;
311pub(crate) mod navigator;
312pub(crate) mod navigatorinfo;
313#[expect(dead_code)]
314pub(crate) mod node;
315pub(crate) use self::node::*;
316pub(crate) mod notification;
317pub(crate) mod origin;
318pub(crate) mod paintsize;
319pub(crate) mod paintworkletglobalscope;
320pub(crate) mod performance;
321pub(crate) use self::performance::*;
322pub(crate) mod permissions;
323pub(crate) mod permissionstatus;
324pub(crate) mod pipelineid;
325pub(crate) mod plugin;
326pub(crate) mod pluginarray;
327pub(crate) mod processinginstruction;
328pub(crate) mod processingoptions;
329#[expect(dead_code)]
330pub(crate) mod promise;
331pub(crate) mod promisenativehandler;
332pub(crate) mod quotaexceedederror;
333pub(crate) mod radionodelist;
334pub(crate) mod range;
335pub(crate) mod raredata;
336pub(crate) mod reporting;
337pub(crate) use self::reporting::*;
338pub(crate) mod request;
339pub(crate) mod resizeobserver;
340pub(crate) use self::resizeobserver::*;
341pub(crate) mod response;
342pub(crate) mod screen;
343mod scrolling_box;
344pub(crate) mod security;
345pub(crate) use self::security::*;
346pub(crate) mod selection;
347pub(crate) mod servointernals;
348#[expect(dead_code)]
349pub(crate) mod servoparser;
350pub(crate) mod shadowroot;
351pub(crate) mod staticrange;
352pub(crate) mod storage;
353pub(crate) mod stream;
354pub(crate) use self::stream::*;
355pub(crate) mod svg;
356pub(crate) use self::svg::*;
357#[cfg(feature = "testbinding")]
358mod testing;
359#[cfg(feature = "testbinding")]
360pub(crate) use self::testing::*;
361pub(crate) mod text;
362pub(crate) mod textcontrol;
363pub(crate) mod timeranges;
364pub(crate) mod touch;
365pub(crate) mod touchlist;
366pub(crate) mod treewalker;
367pub(crate) mod trustedtypes;
368pub(crate) use self::trustedtypes::*;
369pub(crate) mod url;
370pub(crate) use self::url::*;
371pub(crate) mod useractivation;
372pub(crate) mod userscripts;
373pub(crate) mod validation;
374pub(crate) mod validitystate;
375pub(crate) mod values;
376pub(crate) mod virtualmethods;
377pub(crate) mod visibilitystateentry;
378pub(crate) mod visualviewport;
379pub(crate) mod webgl;
380pub(crate) use self::webgl::extensions::ext::*;
381pub(crate) use self::webgl::*;
382pub(crate) mod websocket;
383#[cfg(feature = "webxr")]
384mod webxr;
385#[cfg(feature = "webxr")]
386pub(crate) use self::webxr::*;
387#[cfg(feature = "webgpu")]
388pub(crate) mod webgpu;
389#[cfg(feature = "webgpu")]
390pub(crate) use self::webgpu::*;
391#[cfg(not(feature = "webgpu"))]
392pub(crate) mod gpucanvascontext;
393pub(crate) mod webcrypto;
394pub(crate) use self::webcrypto::*;
395pub(crate) mod webrtc;
396pub(crate) use self::webrtc::*;
397pub(crate) mod webvtt;
398pub(crate) use self::webvtt::*;
399#[expect(dead_code)]
400pub(crate) mod window;
401pub(crate) mod windowproxy;
402pub(crate) mod workers;
403pub(crate) use self::workers::*;
404pub(crate) mod worklet;
405pub(crate) mod workletglobalscope;
406pub(crate) mod xmldocument;
407pub(crate) mod xmlhttprequest;
408pub(crate) mod xmlhttprequesteventtarget;
409pub(crate) mod xmlhttprequestupload;
410pub(crate) mod xmlserializer;
411pub(crate) mod xpath;
412pub(crate) use self::xpath::*;