/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/script_bindings/dom.rs
314 строк
10 KB
Martin Robinson
script/layout: Add initial support for visible selections (#46698)
23 июл 2026, 12:21
Не верифицирован
23 июл 2026, 12:21
295e3cf
Код
Авторство
О чём код?
/* 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/. */ use std::cell::UnsafeCell; use std::marker::PhantomData; use std::ops::Deref; use std::{mem, ptr}; use js::context::NoGC; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use crate::DomObject; use crate::assert::assert_in_script; use crate::conversions::DerivedFrom; use crate::inheritance::Castable; use crate::root::{Dom, DomRoot}; /// A holder that provides interior mutability for GC-managed values such as /// `Dom<T>`. Essentially a `Cell<Dom<T>>`, but safer. /// /// This should only be used as a field in other DOM objects; see warning /// on `Dom<T>`. #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] #[derive(JSTraceable)] pub struct MutDom<T: DomObject> { val: UnsafeCell<Dom<T>>, } impl<T: DomObject> MutDom<T> { /// Create a new `MutDom`. pub fn new(initial: &T) -> MutDom<T> { assert_in_script(); MutDom { val: UnsafeCell::new(Dom::from_ref(initial)), } } /// Set this `MutDom` to the given value. pub fn set(&self, val: &T) { assert_in_script(); unsafe { *self.val.get() = Dom::from_ref(val); } } /// Get the value in this `MutDom`. pub fn get(&self) -> DomRoot<T> { assert_in_script(); unsafe { DomRoot::from_ref(&*ptr::read(self.val.get())) } } /// Get the [`DomObject`] without rooting it as an [`UnrootedDom`]. This is safe as /// the return value shares the lifetime of the provided [`NoGC`] This implies that /// while the [`UnrootedDom`] is alive, garbage collection will not happen. pub fn get_unrooted<'a>(&self, _: &'a NoGC) -> UnrootedDom<'a, T> { assert_in_script(); UnrootedDom { inner: unsafe { ptr::read(self.val.get()) }, _phantom: PhantomData, } } /// Get a reference to the traced inner value of this [`MutDom`]. /// /// # Safety /// /// - The caller *must not* modify the value of the [`MutDom`] while the /// reference is alive. /// - The caller *must ensure* that no garbage collection happens while the /// reference is alive. pub unsafe fn as_ref_unsafe(&self) -> &Dom<T> { unsafe { &*self.val.get() } } } impl<T: DomObject> MallocSizeOf for MutDom<T> { fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { // See comment on MallocSizeOf for Dom<T>. 0 } } impl<T: DomObject> PartialEq for MutDom<T> { fn eq(&self, other: &Self) -> bool { unsafe { *self.val.get() == *other.val.get() } } } impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> { fn eq(&self, other: &T) -> bool { unsafe { **self.val.get() == *other } } } /// A reference to a [`DomObject`] that can live on the stack unrooted by having it /// inherit the lifetime of a [`NoGC`], which is a token that ensures that garbage /// collection will not happen. #[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)] pub struct UnrootedDom<'a, T: DomObject> { inner: Dom<T>, _phantom: PhantomData<&'a ()>, } impl<'a, T: DomObject + std::fmt::Debug> std::fmt::Debug for UnrootedDom<'a, T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.inner.fmt(f) } } impl<'a, T: DomObject> Clone for UnrootedDom<'a, T> { fn clone(&self) -> Self { Self { inner: self.inner.clone(), _phantom: PhantomData, } } } impl<'a, T: DomObject> UnrootedDom<'a, T> { /// Construct an [`UnrootedDom`] with the lifetime of the given [`NoGC`] token. It is /// safe to keep the returned value on the stack as it cannot outlive the lifetime of /// the token and the token should ensure that no garbage collection will take place /// as long as it is alive. #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub fn from_dom(object: Dom<T>, _no_gc: &'a NoGC) -> UnrootedDom<'a, T> { UnrootedDom { inner: object, _phantom: PhantomData, } } } impl<'a, T: DomObject> Deref for UnrootedDom<'a, T> { type Target = Dom<T>; fn deref(&self) -> &Self::Target { &self.inner } } impl<'a, T: Castable> UnrootedDom<'a, T> { /// Cast a DOM object root upwards to one of the interfaces it derives from. pub fn upcast<U>(dom: UnrootedDom<'a, T>) -> UnrootedDom<'a, U> where U: Castable, T: DerivedFrom<U>, { UnrootedDom { inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) }, _phantom: PhantomData, } } /// Cast a DOM object root downwards to one of the interfaces it might implement. pub fn downcast<U>(dom: UnrootedDom<'a, T>) -> Option<UnrootedDom<'a, U>> where U: DerivedFrom<T>, { if dom.is::<U>() { Some(UnrootedDom { inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) }, _phantom: PhantomData, }) } else { None } } } impl<'a, T: DomObject> PartialEq<T> for UnrootedDom<'a, T> { fn eq(&self, other: &T) -> bool { self.inner == other } } impl<'a, T: DomObject> PartialEq<UnrootedDom<'a, T>> for UnrootedDom<'a, T> { fn eq(&self, other: &UnrootedDom<'a, T>) -> bool { self.inner == other.inner } } /// A holder that provides interior mutability for GC-managed values such as /// `Dom<T>`, with nullability represented by an enclosing Option wrapper. /// Essentially a `Cell<Option<Dom<T>>>`, but safer. /// /// This should only be used as a field in other DOM objects; see warning /// on `Dom<T>`. #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] #[derive(JSTraceable)] pub struct MutNullableDom<T: DomObject> { ptr: UnsafeCell<Option<Dom<T>>>, } impl<T: DomObject> MutNullableDom<T> { /// Create a new `MutNullableDom`. pub fn new(initial: Option<&T>) -> MutNullableDom<T> { assert_in_script(); MutNullableDom { ptr: UnsafeCell::new(initial.map(Dom::from_ref)), } } /// Retrieve a copy of the current inner value. If it is `None`, it is /// initialized with the result of `cb` first. pub fn or_init<F>(&self, cb: F) -> DomRoot<T> where F: FnOnce() -> DomRoot<T>, { assert_in_script(); match self.get() { Some(inner) => inner, None => { let inner = cb(); self.set(Some(&inner)); inner }, } } /// Get a rooted ([`DomRoot`]) reference to the value contained in this /// [`MutNullableDom`]. pub fn get(&self) -> Option<DomRoot<T>> { assert_in_script(); unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) } } /// Get a reference to the traced inner value of this [`MutNullableDom`]. /// /// # Safety /// /// - The caller *must not* modify the value of the [`MutNullableDom`] while the /// reference is alive. /// - The caller *must ensure* that no garbage collection happens while the /// reference is alive. pub unsafe fn as_ref_unsafe(&self) -> Option<&Dom<T>> { unsafe { (*self.ptr.get()).as_ref() } } /// Get the `DomObject` without rooting it. Constructing an UnrootedDom. This is safe /// as we take a reference to NoGC and bound the lifetime by NoGC bound. This implies that /// while the `UnrootedDom` is alive we do not have a GC run. #[cfg_attr(crown, expect(crown::unrooted_must_root))] pub fn get_unrooted<'a>(&self, _: &'a NoGC) -> Option<UnrootedDom<'a, T>> { assert_in_script(); let ptr = unsafe { ptr::read(self.ptr.get()) }; ptr.map(|traced_value| Dom::from_ref(&*traced_value)) .map(|dom| UnrootedDom { inner: dom, _phantom: PhantomData, }) } /// Set this `MutNullableDom` to the given value. pub fn set(&self, val: Option<&T>) { assert_in_script(); unsafe { *self.ptr.get() = val.map(|p| Dom::from_ref(p)); } } /// Gets the current value out of this object and sets it to `None`. pub fn take(&self) -> Option<DomRoot<T>> { let value = self.get(); self.set(None); value } /// Sets the current value of this [`MutNullableDom`] to `None`. pub fn clear(&self) { self.set(None) } /// Runs the given callback on the object if it's not null. pub fn if_is_some<F, R>(&self, cb: F) -> Option<&R> where F: FnOnce(&T) -> &R, { unsafe { if let Some(ref value) = *self.ptr.get() { Some(cb(value)) } else { None } } } } impl<T: DomObject> PartialEq for MutNullableDom<T> { fn eq(&self, other: &Self) -> bool { unsafe { *self.ptr.get() == *other.ptr.get() } } } impl<T: DomObject> PartialEq<Option<&T>> for MutNullableDom<T> { fn eq(&self, other: &Option<&T>) -> bool { unsafe { *self.ptr.get() == other.map(Dom::from_ref) } } } impl<T: DomObject> Default for MutNullableDom<T> { fn default() -> MutNullableDom<T> { assert_in_script(); MutNullableDom { ptr: UnsafeCell::new(None), } } } impl<T: DomObject> MallocSizeOf for MutNullableDom<T> { fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { // See comment on MallocSizeOf for Dom<T>. 0 } }