mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
Compare commits
10 Commits
8ced3d1b8e
...
6d70fcda1b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d70fcda1b | ||
|
|
6f43bba0f4 | ||
|
|
902d5d10d9 | ||
|
|
1a9808d421 | ||
|
|
e0d7542d37 | ||
|
|
ac9f747509 | ||
|
|
55ec768fb7 | ||
|
|
b768a93a47 | ||
|
|
87daffa1fd | ||
|
|
d0908b0342 |
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -5068,9 +5068,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mozjs"
|
||||
version = "0.15.9"
|
||||
version = "0.15.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "475b6fbb284d1229f4108c5cf3842da47ee319b45c9a6c24358f41a0640a64f5"
|
||||
checksum = "2231fbdbc1ee3eaae2d2859792f5f1a6ca065fdebecccfe9447e531292883126"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
@@ -5083,9 +5083,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mozjs_sys"
|
||||
version = "0.140.8-4"
|
||||
version = "0.140.10-1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59e4cb2d3bf4a10d2f0005331419fb12b21ff260711ded47b9590ed432fad41e"
|
||||
checksum = "4d2a078fe5215b5afe55502b2a5c40b2119d81492eafc246373dc9cfda332129"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
@@ -8886,6 +8886,7 @@ name = "servo-wakelock"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"servo-embedder-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -111,7 +111,7 @@ indexmap = { version = "2.14.0", features = ["std"] }
|
||||
inventory = { version = "0.3.24" }
|
||||
ipc-channel = "0.21"
|
||||
itertools = "0.14"
|
||||
js = { package = "mozjs", version = "=0.15.9", default-features = false, features = ["libz-sys", "intl"] }
|
||||
js = { package = "mozjs", version = "=0.15.11", default-features = false, features = ["libz-sys", "intl"] }
|
||||
keyboard-types = { version = "0.8.3", features = ["serde", "webdriver"] }
|
||||
kurbo = { version = "0.12", features = ["euclid"] }
|
||||
libc = "0.2"
|
||||
|
||||
@@ -60,6 +60,9 @@ pub struct Opts {
|
||||
/// Directory for a default config directory
|
||||
pub config_dir: Option<PathBuf>,
|
||||
|
||||
/// Use temporary storage (data on disk will not persist across restarts).
|
||||
pub temporary_storage: bool,
|
||||
|
||||
/// Path to PEM encoded SSL CA certificate store.
|
||||
pub certificate_path: Option<String>,
|
||||
|
||||
@@ -222,6 +225,7 @@ impl Default for Opts {
|
||||
sandbox: false,
|
||||
debug: Default::default(),
|
||||
config_dir: None,
|
||||
temporary_storage: false,
|
||||
shaders_path: None,
|
||||
certificate_path: None,
|
||||
ignore_certificate_errors: false,
|
||||
|
||||
@@ -111,8 +111,8 @@ use embedder_traits::{
|
||||
GenericEmbedderProxy, InputEvent, InputEventAndId, InputEventOutcome, JSValue,
|
||||
JavaScriptEvaluationError, JavaScriptEvaluationId, KeyboardEvent, MediaSessionActionType,
|
||||
MediaSessionEvent, MediaSessionPlaybackState, MouseButton, MouseButtonAction, MouseButtonEvent,
|
||||
NewWebViewDetails, PaintHitTestResult, Theme, ViewportDetails, WebDriverCommandMsg,
|
||||
WebDriverLoadStatus, WebDriverScriptCommand,
|
||||
NewWebViewDetails, PaintHitTestResult, Theme, ViewportDetails, WakeLockDelegate, WakeLockType,
|
||||
WebDriverCommandMsg, WebDriverLoadStatus, WebDriverScriptCommand,
|
||||
};
|
||||
use euclid::Size2D;
|
||||
use euclid::default::Size2D as UntypedSize2D;
|
||||
@@ -168,7 +168,6 @@ use servo_constellation_traits::{
|
||||
TraversalDirection, UserContentManagerAction, WindowSizeType,
|
||||
};
|
||||
use servo_url::{Host, ImmutableOrigin, ServoUrl};
|
||||
use servo_wakelock::{WakeLockProvider, WakeLockType};
|
||||
use storage_traits::StorageThreads;
|
||||
use storage_traits::client_storage::ClientStorageThreadMessage;
|
||||
use storage_traits::indexeddb::{IndexedDBThreadMsg, SyncOperation};
|
||||
@@ -493,7 +492,7 @@ pub struct Constellation<STF, SWF> {
|
||||
screen_wake_lock_count: u32,
|
||||
|
||||
/// Provider for OS-level screen wake lock acquisition and release.
|
||||
wake_lock_provider: Box<dyn WakeLockProvider>,
|
||||
wake_lock_provider: Box<dyn WakeLockDelegate>,
|
||||
|
||||
/// The image bytes associated with the BrokenImageIcon embedder resource.
|
||||
/// Read during startup and provided to image caches that are created
|
||||
@@ -594,7 +593,7 @@ pub struct InitialConstellationState {
|
||||
pub async_runtime: Box<dyn AsyncRuntime>,
|
||||
|
||||
/// The wake lock provider for acquiring and releasing OS-level screen wake locks.
|
||||
pub wake_lock_provider: Box<dyn WakeLockProvider>,
|
||||
pub wake_lock_provider: Box<dyn WakeLockDelegate>,
|
||||
}
|
||||
|
||||
/// When we are exiting a pipeline, we can either force exiting or not. A normal exit
|
||||
|
||||
@@ -278,12 +278,9 @@ impl TextRunSegment {
|
||||
|
||||
// Split off any trailing whitespace into a separate glyph run.
|
||||
let mut whitespace = slice.end..slice.end;
|
||||
let mut rev_char_indices = word.char_indices().rev().peekable();
|
||||
let rev_char_indices = word.char_indices().rev().peekable();
|
||||
|
||||
let mut ends_with_whitespace = false;
|
||||
let ends_with_newline = rev_char_indices
|
||||
.peek()
|
||||
.is_some_and(|&(_, character)| character == '\n');
|
||||
if let Some((first_white_space_index, first_white_space_character)) = rev_char_indices
|
||||
.take_while(|&(_, character)| char_is_whitespace(character))
|
||||
.last()
|
||||
@@ -291,14 +288,12 @@ impl TextRunSegment {
|
||||
ends_with_whitespace = true;
|
||||
whitespace.start = slice.start + first_white_space_index;
|
||||
|
||||
// If line breaking for a piece of text that has `white-space-collapse: break-spaces` there
|
||||
// is a line break opportunity *after* every preserved space, but not before. This means
|
||||
// that we should not split off the first whitespace, unless that white-space is a preserved
|
||||
// newline.
|
||||
// If line breaking for a piece of text that has `white-space-collapse:
|
||||
// break-spaces` there is a line break opportunity *after* every preserved space,
|
||||
// but not before. This means that we should not split off the first whitespace.
|
||||
//
|
||||
// An exception to this is if the style tells us that we can break in the middle of words.
|
||||
if text_style.white_space_collapse == WhiteSpaceCollapse::BreakSpaces &&
|
||||
first_white_space_character != '\n' &&
|
||||
!can_break_anywhere
|
||||
{
|
||||
whitespace.start += first_white_space_character.len_utf8();
|
||||
@@ -352,25 +347,7 @@ impl TextRunSegment {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The breaker breaks after every newline, so either there is none,
|
||||
// or there is exactly one at the very end. In the latter case,
|
||||
// split it into a different run. That's because shaping considers
|
||||
// a newline to have the same advance as a space, but during layout
|
||||
// we want to treat the newline as having no advance.
|
||||
if ends_with_newline && whitespace.len() > 1 {
|
||||
self.shape_and_push_range(
|
||||
&(whitespace.start..whitespace.end - 1),
|
||||
formatting_context_text,
|
||||
&options,
|
||||
);
|
||||
self.shape_and_push_range(
|
||||
&(whitespace.end - 1..whitespace.end),
|
||||
formatting_context_text,
|
||||
&options,
|
||||
);
|
||||
} else {
|
||||
self.shape_and_push_range(&whitespace, formatting_context_text, &options);
|
||||
}
|
||||
self.shape_and_push_range(&whitespace, formatting_context_text, &options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ use embedder_traits::UntrustedNodeAddress;
|
||||
use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
|
||||
use itertools::Itertools;
|
||||
use layout_api::{
|
||||
AxesOverflow, BoxAreaType, CSSPixelRectIterator, LayoutElement, LayoutElementType, LayoutNode,
|
||||
LayoutNodeType, OffsetParentResponse, PhysicalSides, ScrollContainerQueryFlags,
|
||||
ScrollContainerResponse,
|
||||
AxesOverflow, BoxAreaType, CSSPixelRectIterator, DangerousStyleElementOf, LayoutElement,
|
||||
LayoutElementType, LayoutNode, LayoutNodeType, OffsetParentResponse, PhysicalSides,
|
||||
ScrollContainerQueryFlags, ScrollContainerResponse,
|
||||
};
|
||||
use paint_api::display_list::ScrollTree;
|
||||
use script::layout_dom::ServoLayoutNode;
|
||||
@@ -1483,7 +1483,7 @@ where
|
||||
};
|
||||
context
|
||||
.stylist
|
||||
.compute_for_declarations::<E::ConcreteDangerousStyleElement>(
|
||||
.compute_for_declarations::<DangerousStyleElementOf<'dom, E::ConcreteTypeBundle>>(
|
||||
&context.guards,
|
||||
parent_style,
|
||||
ServoArc::new(shared_lock.wrap(declarations)),
|
||||
|
||||
@@ -14,6 +14,7 @@ use embedder_traits::JavaScriptErrorInfo;
|
||||
use js::context::JSContext;
|
||||
use js::conversions::jsstr_to_string;
|
||||
use js::error::{throw_range_error, throw_type_error};
|
||||
use js::gc::{HandleObject, HandleValue, MutableHandleValue};
|
||||
#[cfg(feature = "js_backtrace")]
|
||||
use js::jsapi::StackFormat as JSStackFormat;
|
||||
use js::jsapi::{ExceptionStackBehavior, JS_ClearPendingException, JS_IsExceptionPending};
|
||||
@@ -21,7 +22,7 @@ use js::jsval::UndefinedValue;
|
||||
use js::realm::CurrentRealm;
|
||||
use js::rust::wrappers::{JS_ErrorFromException, JS_GetPendingException, JS_SetPendingException};
|
||||
use js::rust::wrappers2::JS_GetProperty;
|
||||
use js::rust::{HandleObject, HandleValue, MutableHandleValue, describe_scripted_caller};
|
||||
use js::rust::{describe_scripted_caller, error_info_from_exception_stack};
|
||||
use libc::c_uint;
|
||||
use script_bindings::conversions::SafeToJSValConvertible;
|
||||
pub(crate) use script_bindings::error::*;
|
||||
@@ -348,28 +349,34 @@ impl ErrorInfo {
|
||||
/// Report a pending exception, thereby clearing it.
|
||||
pub(crate) fn report_pending_exception(cx: SafeJSContext, realm: InRealm, can_gc: CanGc) {
|
||||
rooted!(in(*cx) let mut value = UndefinedValue());
|
||||
if take_pending_exception(cx, value.handle_mut()) {
|
||||
GlobalScope::from_safe_context(cx, realm).report_an_exception(cx, value.handle(), can_gc);
|
||||
if let Some(error_info) = error_info_from_pending_exception(cx, value.handle_mut(), can_gc) {
|
||||
GlobalScope::from_safe_context(cx, realm).report_an_error(
|
||||
error_info,
|
||||
value.handle(),
|
||||
can_gc,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn take_pending_exception(cx: SafeJSContext, value: MutableHandleValue) -> bool {
|
||||
fn error_info_from_pending_exception(
|
||||
cx: SafeJSContext,
|
||||
value: MutableHandleValue,
|
||||
_can_gc: CanGc,
|
||||
) -> Option<ErrorInfo> {
|
||||
unsafe {
|
||||
if !JS_IsExceptionPending(*cx) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if !JS_GetPendingException(*cx, value) {
|
||||
JS_ClearPendingException(*cx);
|
||||
error!("Uncaught exception: JS_GetPendingException failed");
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
|
||||
JS_ClearPendingException(*cx);
|
||||
let error_info = error_info_from_exception_stack(*cx, value.into())?;
|
||||
|
||||
Some(ErrorInfo {
|
||||
message: error_info.message,
|
||||
filename: error_info.filename,
|
||||
lineno: error_info.line,
|
||||
column: error_info.col,
|
||||
})
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn javascript_error_info_from_error_info(
|
||||
@@ -417,11 +424,9 @@ pub(crate) fn take_and_report_pending_exception_for_api(
|
||||
let in_realm = InRealm::Already(&in_realm_proof);
|
||||
|
||||
rooted!(&in(cx) let mut value = UndefinedValue());
|
||||
if !take_pending_exception(cx.into(), value.handle_mut()) {
|
||||
return None;
|
||||
}
|
||||
let error_info =
|
||||
error_info_from_pending_exception(cx.into(), value.handle_mut(), CanGc::from_cx(cx))?;
|
||||
|
||||
let error_info = ErrorInfo::from_value(value.handle(), cx.into(), CanGc::from_cx(cx));
|
||||
let return_value = javascript_error_info_from_error_info(cx, &error_info, value.handle());
|
||||
GlobalScope::from_safe_context(cx.into(), in_realm).report_an_error(
|
||||
error_info,
|
||||
|
||||
@@ -13,6 +13,7 @@ use embedder_traits::resources::{self, Resource};
|
||||
use js::context::JSContext;
|
||||
use js::rust::wrappers2::JS_DefineDebuggerObject;
|
||||
use net_traits::ResourceThreads;
|
||||
use net_traits::response::HttpsState;
|
||||
use profile_traits::{mem, time};
|
||||
use servo_base::generic_channel::{GenericCallback, GenericSender, channel};
|
||||
use servo_base::id::{Index, PipelineId, PipelineNamespaceId};
|
||||
@@ -117,6 +118,7 @@ impl DebuggerGlobalScope {
|
||||
None,
|
||||
false,
|
||||
None, // font_context
|
||||
HttpsState::None,
|
||||
),
|
||||
devtools_to_script_sender,
|
||||
get_possible_breakpoints_result_sender: RefCell::new(None),
|
||||
|
||||
@@ -7,6 +7,7 @@ use js::context::JSContext;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue, MutableHandleValue};
|
||||
use net_traits::response::HttpsState;
|
||||
use servo_base::id::PipelineId;
|
||||
use servo_constellation_traits::{ScriptToConstellationMessage, StructuredSerializedData};
|
||||
use servo_url::ServoUrl;
|
||||
@@ -69,6 +70,7 @@ impl DissimilarOriginWindow {
|
||||
Some(global_to_clone_from.is_secure_context()),
|
||||
false,
|
||||
global_to_clone_from.font_context().cloned(),
|
||||
HttpsState::None,
|
||||
),
|
||||
window_proxy: Dom::from_ref(window_proxy),
|
||||
location: Default::default(),
|
||||
|
||||
@@ -42,7 +42,6 @@ use net_traits::pub_domains::is_pub_domain;
|
||||
use net_traits::request::{
|
||||
InsecureRequestsPolicy, PreloadId, PreloadKey, PreloadedResources, RequestBuilder,
|
||||
};
|
||||
use net_traits::response::HttpsState;
|
||||
use percent_encoding::percent_decode;
|
||||
use profile_traits::generic_channel as profile_generic_channel;
|
||||
use profile_traits::time::TimerMetadataFrameType;
|
||||
@@ -438,9 +437,7 @@ pub(crate) struct Document {
|
||||
unload_event_start: Cell<Option<CrossProcessInstant>>,
|
||||
#[no_trace]
|
||||
unload_event_end: Cell<Option<CrossProcessInstant>>,
|
||||
/// <https://html.spec.whatwg.org/multipage/#concept-document-https-state>
|
||||
#[no_trace]
|
||||
https_state: Cell<HttpsState>,
|
||||
|
||||
/// The document's origin.
|
||||
#[no_trace]
|
||||
origin: DomRefCell<MutableOrigin>,
|
||||
@@ -842,10 +839,6 @@ impl Document {
|
||||
self.content_type.matches(APPLICATION, "xhtml+xml")
|
||||
}
|
||||
|
||||
pub(crate) fn set_https_state(&self, https_state: HttpsState) {
|
||||
self.https_state.set(https_state);
|
||||
}
|
||||
|
||||
pub(crate) fn is_fully_active(&self) -> bool {
|
||||
self.activity.get() == DocumentActivity::FullyActive
|
||||
}
|
||||
@@ -3590,7 +3583,6 @@ impl Document {
|
||||
load_event_end: Cell::new(Default::default()),
|
||||
unload_event_start: Cell::new(Default::default()),
|
||||
unload_event_end: Cell::new(Default::default()),
|
||||
https_state: Cell::new(HttpsState::None),
|
||||
origin: DomRefCell::new(origin),
|
||||
referrer,
|
||||
target_element: MutNullableDom::new(None),
|
||||
|
||||
@@ -13,8 +13,8 @@ use js::jsapi::{ExceptionStackBehavior, Heap, JSScript, SetScriptPrivate};
|
||||
use js::jsval::{PrivateValue, UndefinedValue};
|
||||
use js::panic::maybe_resume_unwind;
|
||||
use js::rust::wrappers2::{
|
||||
Compile1, JS_ClearPendingException, JS_ExecuteScript, JS_GetPendingException,
|
||||
JS_GetScriptPrivate, JS_SetPendingException,
|
||||
Compile1, JS_ClearPendingException, JS_ExecuteScript, JS_GetScriptPrivate,
|
||||
JS_IsExceptionPending, JS_SetPendingException,
|
||||
};
|
||||
use js::rust::{CompileOptionsWrapper, MutableHandleValue, transform_str_to_source_text};
|
||||
use script_bindings::cformat;
|
||||
@@ -24,11 +24,12 @@ use servo_url::ServoUrl;
|
||||
|
||||
use crate::DomTypeHolder;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||
use crate::dom::bindings::error::{Error, ErrorResult};
|
||||
use crate::dom::bindings::error::{Error, ErrorResult, report_pending_exception};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::window::Window;
|
||||
use crate::realms::{InRealm, enter_auto_realm};
|
||||
use crate::script_module::{
|
||||
ModuleScript, ModuleSource, ModuleTree, RethrowError, ScriptFetchOptions,
|
||||
};
|
||||
@@ -157,11 +158,13 @@ impl GlobalScope {
|
||||
|
||||
// TODO Step 3. Record classic script execution start time given script.
|
||||
|
||||
let mut realm = enter_auto_realm(cx, self);
|
||||
let cx = &mut realm.current_realm();
|
||||
|
||||
// Step 4. Prepare to run script given settings.
|
||||
// Once dropped this will run "Step 9. Clean up after running script" steps
|
||||
run_a_script::<DomTypeHolder, _>(self, || {
|
||||
// Step 5. Let evaluationStatus be null.
|
||||
rooted!(&in(cx) let mut evaluation_status = UndefinedValue());
|
||||
let mut result = false;
|
||||
|
||||
match script.record {
|
||||
@@ -188,10 +191,8 @@ impl GlobalScope {
|
||||
},
|
||||
}
|
||||
|
||||
unsafe { JS_GetPendingException(cx, evaluation_status.handle_mut()) };
|
||||
|
||||
// Step 8. If evaluationStatus is an abrupt completion, then:
|
||||
if !evaluation_status.is_undefined() {
|
||||
if unsafe { JS_IsExceptionPending(cx) } {
|
||||
warn!("Error evaluating script");
|
||||
|
||||
match (rethrow_errors, script.muted_errors) {
|
||||
@@ -208,13 +209,10 @@ impl GlobalScope {
|
||||
},
|
||||
// Step 8.3. Otherwise, rethrow errors is false. Perform the following steps:
|
||||
_ => {
|
||||
unsafe { JS_ClearPendingException(cx) };
|
||||
let in_realm_proof = cx.into();
|
||||
let in_realm = InRealm::Already(&in_realm_proof);
|
||||
// Report an exception given by evaluationStatus.[[Value]] for script's settings object's global object.
|
||||
self.report_an_exception(
|
||||
cx.into(),
|
||||
evaluation_status.handle(),
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
report_pending_exception(cx.into(), in_realm, CanGc::from_cx(cx));
|
||||
|
||||
// Return evaluationStatus.
|
||||
return Err(Error::JSFailed);
|
||||
|
||||
@@ -771,6 +771,7 @@ impl GlobalScope {
|
||||
inherited_secure_context: Option<bool>,
|
||||
unminify_js: bool,
|
||||
font_context: Option<Arc<FontContext>>,
|
||||
initial_https_state: HttpsState,
|
||||
) -> Self {
|
||||
Self {
|
||||
task_manager: Default::default(),
|
||||
@@ -809,7 +810,7 @@ impl GlobalScope {
|
||||
#[cfg(feature = "webgpu")]
|
||||
gpu_devices: DomRefCell::new(HashMapTracedValues::new_fx()),
|
||||
frozen_supported_performance_entry_types: CachedFrozenArray::new(),
|
||||
https_state: Cell::new(HttpsState::None),
|
||||
https_state: Cell::new(initial_https_state),
|
||||
console_group_stack: DomRefCell::new(Vec::new()),
|
||||
console_count_map: Default::default(),
|
||||
inherited_secure_context,
|
||||
|
||||
@@ -41,7 +41,7 @@ impl HTMLBodyElement {
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
cx: &mut js::context::JSContext,
|
||||
cx: &mut JSContext,
|
||||
local_name: LocalName,
|
||||
prefix: Option<Prefix>,
|
||||
document: &Document,
|
||||
@@ -73,11 +73,14 @@ impl HTMLBodyElementMethods<crate::DomTypeHolder> for HTMLBodyElement {
|
||||
make_getter!(Background, "background");
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-body-background>
|
||||
fn SetBackground(&self, input: DOMString, can_gc: CanGc) {
|
||||
fn SetBackground(&self, cx: &mut JSContext, input: DOMString) {
|
||||
let value =
|
||||
AttrValue::from_resolved_url(&self.owner_document().base_url().get_arc(), input.into());
|
||||
self.upcast::<Element>()
|
||||
.set_attribute(&local_name!("background"), value, can_gc);
|
||||
self.upcast::<Element>().set_attribute(
|
||||
&local_name!("background"),
|
||||
value,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#windoweventhandlers
|
||||
@@ -146,12 +149,7 @@ impl VirtualMethods for HTMLBodyElement {
|
||||
}
|
||||
}
|
||||
|
||||
fn attribute_mutated(
|
||||
&self,
|
||||
cx: &mut js::context::JSContext,
|
||||
attr: &Attr,
|
||||
mutation: AttributeMutation,
|
||||
) {
|
||||
fn attribute_mutated(&self, cx: &mut JSContext, attr: &Attr, mutation: AttributeMutation) {
|
||||
let do_super_mutate = match (attr.local_name(), mutation) {
|
||||
(name, AttributeMutation::Set(..)) if name.starts_with("on") => {
|
||||
let document = self.owner_document();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
use cssparser::match_ignore_ascii_case;
|
||||
use dom_struct::dom_struct;
|
||||
use html5ever::{LocalName, Prefix, local_name, ns};
|
||||
use js::context::JSContext;
|
||||
use js::rust::HandleObject;
|
||||
use style::attr::AttrValue;
|
||||
use style::color::AbsoluteColor;
|
||||
@@ -43,7 +44,7 @@ impl HTMLFontElement {
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
cx: &mut js::context::JSContext,
|
||||
cx: &mut JSContext,
|
||||
local_name: LocalName,
|
||||
prefix: Option<Prefix>,
|
||||
document: &Document,
|
||||
@@ -100,15 +101,15 @@ impl HTMLFontElementMethods<crate::DomTypeHolder> for HTMLFontElement {
|
||||
make_getter!(Face, "face");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-font-face
|
||||
make_atomic_setter!(SetFace, "face");
|
||||
make_atomic_setter!(cx, SetFace, "face");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-font-size
|
||||
make_getter!(Size, "size");
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-font-size>
|
||||
fn SetSize(&self, value: DOMString, can_gc: CanGc) {
|
||||
fn SetSize(&self, cx: &mut JSContext, value: DOMString) {
|
||||
let element = self.upcast::<Element>();
|
||||
element.set_attribute(&local_name!("size"), parse_size(&value), can_gc);
|
||||
element.set_attribute(&local_name!("size"), parse_size(&value), CanGc::from_cx(cx));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ impl HTMLHRElementMethods<crate::DomTypeHolder> for HTMLHRElement {
|
||||
make_getter!(Align, "align");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-hr-align
|
||||
make_atomic_setter!(SetAlign, "align");
|
||||
make_atomic_setter!(cx, SetAlign, "align");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-hr-color
|
||||
make_getter!(Color, "color");
|
||||
@@ -74,19 +74,19 @@ impl HTMLHRElementMethods<crate::DomTypeHolder> for HTMLHRElement {
|
||||
make_bool_getter!(NoShade, "noshade");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-hr-noshade
|
||||
make_bool_setter!(SetNoShade, "noshade");
|
||||
make_bool_setter!(cx, SetNoShade, "noshade");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-hr-size
|
||||
make_getter!(Size, "size");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-hr-size
|
||||
make_dimension_setter!(SetSize, "size");
|
||||
make_dimension_setter!(cx, SetSize, "size");
|
||||
|
||||
// <https://html.spec.whatwg.org/multipage/#dom-hr-width>
|
||||
make_getter!(Width, "width");
|
||||
|
||||
// <https://html.spec.whatwg.org/multipage/#dom-hr-width>
|
||||
make_dimension_setter!(SetWidth, "width");
|
||||
make_dimension_setter!(cx, SetWidth, "width");
|
||||
}
|
||||
|
||||
/// The result of applying the presentational hint for the `size` attribute.
|
||||
|
||||
@@ -67,7 +67,7 @@ impl HTMLTableColElementMethods<crate::DomTypeHolder> for HTMLTableColElement {
|
||||
make_getter!(Width, "width");
|
||||
|
||||
// <https://html.spec.whatwg.org/multipage/#dom-col-width>
|
||||
make_dimension_setter!(SetWidth, "width");
|
||||
make_dimension_setter!(cx, SetWidth, "width");
|
||||
}
|
||||
|
||||
impl<'dom> LayoutDom<'dom, HTMLTableColElement> {
|
||||
|
||||
@@ -471,15 +471,15 @@ impl HTMLTableElementMethods<crate::DomTypeHolder> for HTMLTableElement {
|
||||
make_nonzero_dimension_setter!(SetWidth, "width");
|
||||
|
||||
// <https://html.spec.whatwg.org/multipage/#dom-table-align>
|
||||
make_setter!(SetAlign, "align");
|
||||
make_setter!(cx, SetAlign, "align");
|
||||
make_getter!(Align, "align");
|
||||
|
||||
// <https://html.spec.whatwg.org/multipage/#dom-table-cellpadding>
|
||||
make_setter!(SetCellPadding, "cellpadding");
|
||||
make_setter!(cx, SetCellPadding, "cellpadding");
|
||||
make_getter!(CellPadding, "cellpadding");
|
||||
|
||||
// <https://html.spec.whatwg.org/multipage/#dom-table-cellspacing>
|
||||
make_setter!(SetCellSpacing, "cellspacing");
|
||||
make_setter!(cx, SetCellSpacing, "cellspacing");
|
||||
make_getter!(CellSpacing, "cellspacing");
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTex
|
||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||
use crate::dom::bindings::error::ErrorResult;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::clipboardevent::{ClipboardEvent, ClipboardEventType};
|
||||
@@ -33,6 +34,8 @@ use crate::dom::document::Document;
|
||||
use crate::dom::document_embedder_controls::ControlElement;
|
||||
use crate::dom::element::{AttributeMutation, Element};
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::event::event::{EventBubbles, EventCancelable, EventComposed};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::html::htmlelement::HTMLElement;
|
||||
use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
|
||||
use crate::dom::html::htmlformelement::{FormControl, HTMLFormElement};
|
||||
@@ -69,6 +72,9 @@ pub(crate) struct HTMLTextAreaElement {
|
||||
#[no_trace]
|
||||
#[conditional_malloc_size_of]
|
||||
shared_selection: SharedSelection,
|
||||
|
||||
/// <https://w3c.github.io/selection-api/#dfn-has-scheduled-selectionchange-event>
|
||||
has_scheduled_selectionchange_event: Cell<bool>,
|
||||
}
|
||||
|
||||
impl LayoutDom<'_, HTMLTextAreaElement> {
|
||||
@@ -131,6 +137,7 @@ impl HTMLTextAreaElement {
|
||||
validity_state: Default::default(),
|
||||
text_input_widget: Default::default(),
|
||||
shared_selection: Default::default(),
|
||||
has_scheduled_selectionchange_event: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,6 +239,41 @@ impl HTMLTextAreaElement {
|
||||
self.maybe_update_shared_selection();
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/selection-api/#dfn-schedule-a-selectionchange-event>
|
||||
fn schedule_a_selection_change_event(&self) {
|
||||
// Step 1. If target's has scheduled selectionchange event is true, abort these steps.
|
||||
if self.has_scheduled_selectionchange_event.get() {
|
||||
return;
|
||||
}
|
||||
// Step 2. Set target's has scheduled selectionchange event to true.
|
||||
self.has_scheduled_selectionchange_event.set(true);
|
||||
// Step 3. Queue a task on the user interaction task source to fire a selectionchange event on target.
|
||||
let this = Trusted::new(self);
|
||||
self.owner_global()
|
||||
.task_manager()
|
||||
.user_interaction_task_source()
|
||||
.queue(
|
||||
// https://w3c.github.io/selection-api/#firing-selectionchange-event
|
||||
task!(selectionchange_task_steps: move |cx| {
|
||||
let this = this.root();
|
||||
// Step 1. Set target's has scheduled selectionchange event to false.
|
||||
this.has_scheduled_selectionchange_event.set(false);
|
||||
// Step 2. If target is an element, fire an event named selectionchange, which bubbles and not cancelable, at target.
|
||||
this.upcast::<EventTarget>().fire_event_with_params(
|
||||
atom!("selectionchange"),
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::NotCancelable,
|
||||
EventComposed::Composed,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
// Step 3. Otherwise, if target is a document, fire an event named selectionchange,
|
||||
// which does not bubble and not cancelable, at target.
|
||||
//
|
||||
// n/a
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl TextControlElement for HTMLTextAreaElement {
|
||||
@@ -263,9 +305,19 @@ impl TextControlElement for HTMLTextAreaElement {
|
||||
let enabled = self.upcast::<Element>().focus_state();
|
||||
|
||||
let mut shared_selection = self.shared_selection.borrow_mut();
|
||||
if range == shared_selection.range && enabled == shared_selection.enabled {
|
||||
let range_remained_equal = range == shared_selection.range;
|
||||
if range_remained_equal && enabled == shared_selection.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
if !range_remained_equal {
|
||||
// https://w3c.github.io/selection-api/#selectionchange-event
|
||||
// > When an input or textarea element provide a text selection and its selection changes
|
||||
// > (in either extent or direction),
|
||||
// > the user agent must schedule a selectionchange event on the element.
|
||||
self.schedule_a_selection_change_event();
|
||||
}
|
||||
|
||||
*shared_selection = ScriptSelection {
|
||||
range,
|
||||
character_range: self
|
||||
|
||||
@@ -44,6 +44,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputE
|
||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
|
||||
use crate::dom::bindings::error::{Error, ErrorResult};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
|
||||
use crate::dom::bindings::str::{DOMString, USVString};
|
||||
use crate::dom::clipboardevent::{ClipboardEvent, ClipboardEventType};
|
||||
@@ -52,6 +53,7 @@ use crate::dom::document::Document;
|
||||
use crate::dom::document_embedder_controls::ControlElement;
|
||||
use crate::dom::element::{AttributeMutation, Element};
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::event::event::{EventBubbles, EventCancelable, EventComposed};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::filelist::FileList;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
@@ -156,6 +158,9 @@ pub(crate) struct HTMLInputElement {
|
||||
validity_state: MutNullableDom<ValidityState>,
|
||||
#[no_trace]
|
||||
pending_webdriver_response: RefCell<Option<PendingWebDriverResponse>>,
|
||||
|
||||
/// <https://w3c.github.io/selection-api/#dfn-has-scheduled-selectionchange-event>
|
||||
has_scheduled_selectionchange_event: Cell<bool>,
|
||||
}
|
||||
|
||||
#[derive(JSTraceable)]
|
||||
@@ -212,6 +217,7 @@ impl HTMLInputElement {
|
||||
labels_node_list: MutNullableDom::new(None),
|
||||
validity_state: Default::default(),
|
||||
pending_webdriver_response: Default::default(),
|
||||
has_scheduled_selectionchange_event: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,6 +899,41 @@ impl HTMLInputElement {
|
||||
fn textinput_mut(&self) -> RefMut<'_, TextInput<EmbedderClipboardProvider>> {
|
||||
self.textinput.borrow_mut()
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/selection-api/#dfn-schedule-a-selectionchange-event>
|
||||
fn schedule_a_selection_change_event(&self) {
|
||||
// Step 1. If target's has scheduled selectionchange event is true, abort these steps.
|
||||
if self.has_scheduled_selectionchange_event.get() {
|
||||
return;
|
||||
}
|
||||
// Step 2. Set target's has scheduled selectionchange event to true.
|
||||
self.has_scheduled_selectionchange_event.set(true);
|
||||
// Step 3. Queue a task on the user interaction task source to fire a selectionchange event on target.
|
||||
let this = Trusted::new(self);
|
||||
self.owner_global()
|
||||
.task_manager()
|
||||
.user_interaction_task_source()
|
||||
.queue(
|
||||
// https://w3c.github.io/selection-api/#firing-selectionchange-event
|
||||
task!(selectionchange_task_steps: move |cx| {
|
||||
let this = this.root();
|
||||
// Step 1. Set target's has scheduled selectionchange event to false.
|
||||
this.has_scheduled_selectionchange_event.set(false);
|
||||
// Step 2. If target is an element, fire an event named selectionchange, which bubbles and not cancelable, at target.
|
||||
this.upcast::<EventTarget>().fire_event_with_params(
|
||||
atom!("selectionchange"),
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::NotCancelable,
|
||||
EventComposed::Composed,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
// Step 3. Otherwise, if target is a document, fire an event named selectionchange,
|
||||
// which does not bubble and not cancelable, at target.
|
||||
//
|
||||
// n/a
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'dom> LayoutDom<'dom, HTMLInputElement> {
|
||||
@@ -961,10 +1002,19 @@ impl TextControlElement for HTMLInputElement {
|
||||
let enabled = self.is_textual_or_password() && self.upcast::<Element>().focus_state();
|
||||
|
||||
let mut shared_selection = self.shared_selection.borrow_mut();
|
||||
if range == shared_selection.range && enabled == shared_selection.enabled {
|
||||
let range_remained_equal = range == shared_selection.range;
|
||||
if range_remained_equal && enabled == shared_selection.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
if !range_remained_equal {
|
||||
// https://w3c.github.io/selection-api/#selectionchange-event
|
||||
// > When an input or textarea element provide a text selection and its selection changes
|
||||
// > (in either extent or direction),
|
||||
// > the user agent must schedule a selectionchange event on the element.
|
||||
self.schedule_a_selection_change_event();
|
||||
}
|
||||
|
||||
*shared_selection = ScriptSelection {
|
||||
range,
|
||||
character_range: self
|
||||
|
||||
@@ -263,30 +263,52 @@ macro_rules! make_enumerated_getter(
|
||||
);
|
||||
);
|
||||
|
||||
macro_rules! make_setter_inner(
|
||||
( $self:ident, $value:ident, $htmlname:tt, $can_gc:expr ) => (
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use $crate::script_runtime::CanGc;
|
||||
let element = $self.upcast::<Element>();
|
||||
element.set_string_attribute(&html5ever::local_name!($htmlname), $value, $can_gc)
|
||||
);
|
||||
);
|
||||
|
||||
// concat_idents! doesn't work for function name positions, so
|
||||
// we have to specify both the content name and the HTML name here
|
||||
#[macro_export]
|
||||
macro_rules! make_setter(
|
||||
( $attr:ident, $htmlname:tt ) => (
|
||||
fn $attr(&self, value: DOMString) {
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use $crate::script_runtime::CanGc;
|
||||
let element = self.upcast::<Element>();
|
||||
element.set_string_attribute(&html5ever::local_name!($htmlname), value, CanGc::deprecated_note())
|
||||
make_setter_inner!(self, value, $htmlname, CanGc::deprecated_note());
|
||||
}
|
||||
);
|
||||
( $cx:ident, $attr:ident, $htmlname:tt ) => (
|
||||
fn $attr(&self, $cx: &mut js::context::JSContext, value: DOMString) {
|
||||
make_setter_inner!(self, value, $htmlname, CanGc::from_cx($cx));
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
macro_rules! make_bool_setter_inner(
|
||||
( $self:ident, $value:ident, $htmlname:tt, $can_gc:expr ) => (
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use $crate::script_runtime::CanGc;
|
||||
let element = $self.upcast::<Element>();
|
||||
element.set_bool_attribute(&html5ever::local_name!($htmlname), $value, $can_gc)
|
||||
);
|
||||
);
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! make_bool_setter(
|
||||
( $attr:ident, $htmlname:tt ) => (
|
||||
fn $attr(&self, value: bool) {
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use $crate::script_runtime::CanGc;
|
||||
let element = self.upcast::<Element>();
|
||||
element.set_bool_attribute(&html5ever::local_name!($htmlname), value, CanGc::deprecated_note())
|
||||
make_bool_setter_inner!(self, value, $htmlname, CanGc::deprecated_note());
|
||||
}
|
||||
);
|
||||
( $cx:ident, $attr:ident, $htmlname:tt ) => (
|
||||
fn $attr(&self, $cx: &mut js::context::JSContext, value: bool) {
|
||||
make_bool_setter_inner!(self, value, $htmlname, CanGc::from_cx($cx));
|
||||
}
|
||||
);
|
||||
);
|
||||
@@ -316,7 +338,7 @@ macro_rules! make_uint_setter(
|
||||
#[macro_export]
|
||||
macro_rules! make_clamped_uint_setter(
|
||||
($attr:ident, $htmlname:tt, $min:expr, $max:expr, $default:expr) => (
|
||||
fn $attr(&self, value: u32) {
|
||||
fn $attr(&self, cx: &mut js::context::JSContext, value: u32) {
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use $crate::dom::values::UNSIGNED_LONG_MAX;
|
||||
@@ -328,7 +350,7 @@ macro_rules! make_clamped_uint_setter(
|
||||
};
|
||||
|
||||
let element = self.upcast::<Element>();
|
||||
element.set_uint_attribute(&html5ever::local_name!($htmlname), value, CanGc::deprecated_note())
|
||||
element.set_uint_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
|
||||
}
|
||||
);
|
||||
);
|
||||
@@ -385,28 +407,39 @@ macro_rules! make_atomic_setter(
|
||||
#[macro_export]
|
||||
macro_rules! make_legacy_color_setter(
|
||||
( $attr:ident, $htmlname:tt ) => (
|
||||
fn $attr(&self, value: DOMString) {
|
||||
fn $attr(&self, cx: &mut js::context::JSContext, value: DOMString) {
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use style::attr::AttrValue;
|
||||
use $crate::script_runtime::CanGc;
|
||||
let element = self.upcast::<Element>();
|
||||
let value = AttrValue::from_legacy_color(value.into());
|
||||
element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::deprecated_note())
|
||||
element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
macro_rules! make_dimension_setter_inner(
|
||||
( $self:ident, $value:ident, $htmlname:tt, $can_gc:expr ) => (
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use $crate::script_runtime::CanGc;
|
||||
let element = $self.upcast::<Element>();
|
||||
let value = AttrValue::from_dimension($value.into());
|
||||
element.set_attribute(&html5ever::local_name!($htmlname), value, $can_gc)
|
||||
);
|
||||
);
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! make_dimension_setter(
|
||||
( $attr:ident, $htmlname:tt ) => (
|
||||
fn $attr(&self, value: DOMString) {
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use $crate::script_runtime::CanGc;
|
||||
let element = self.upcast::<Element>();
|
||||
let value = AttrValue::from_dimension(value.into());
|
||||
element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::deprecated_note())
|
||||
make_dimension_setter_inner!(self, value, $htmlname, CanGc::deprecated_note());
|
||||
}
|
||||
);
|
||||
( $cx:ident, $attr:ident, $htmlname:tt ) => (
|
||||
fn $attr(&self, $cx: &mut js::context::JSContext, value: DOMString) {
|
||||
make_dimension_setter_inner!(self, value, $htmlname, CanGc::from_cx($cx));
|
||||
}
|
||||
);
|
||||
);
|
||||
@@ -414,13 +447,13 @@ macro_rules! make_dimension_setter(
|
||||
#[macro_export]
|
||||
macro_rules! make_nonzero_dimension_setter(
|
||||
( $attr:ident, $htmlname:tt ) => (
|
||||
fn $attr(&self, value: DOMString) {
|
||||
fn $attr(&self, cx: &mut js::context::JSContext, value: DOMString) {
|
||||
use $crate::dom::bindings::inheritance::Castable;
|
||||
use $crate::dom::element::Element;
|
||||
use $crate::script_runtime::CanGc;
|
||||
let element = self.upcast::<Element>();
|
||||
let value = AttrValue::from_nonzero_dimension(value.into());
|
||||
element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::deprecated_note())
|
||||
element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
|
||||
}
|
||||
);
|
||||
);
|
||||
@@ -522,7 +555,7 @@ macro_rules! define_window_owned_event_handler(
|
||||
}
|
||||
}
|
||||
|
||||
fn $setter(&self, listener: Option<::std::rc::Rc<$handler>>) {
|
||||
fn $setter(&self, _cx: &mut js::context::JSContext, listener: Option<::std::rc::Rc<$handler>>) {
|
||||
let document = self.owner_document();
|
||||
if document.has_browsing_context() {
|
||||
document.window().$setter(listener)
|
||||
|
||||
@@ -92,7 +92,7 @@ impl RoutedPromiseListener<AllowOrDeny> for WakeLock {
|
||||
let global = self.global();
|
||||
global.as_window().send_to_constellation(
|
||||
ScriptToConstellationMessage::AcquireWakeLock(
|
||||
servo_wakelock::WakeLockType::Screen,
|
||||
embedder_traits::WakeLockType::Screen,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ use net_traits::image_cache::{
|
||||
ImageResponse, PendingImageId, PendingImageResponse, RasterizationCompleteResponse,
|
||||
};
|
||||
use net_traits::request::Referrer;
|
||||
use net_traits::response::HttpsState;
|
||||
use net_traits::{ResourceFetchTiming, ResourceThreads};
|
||||
use num_traits::ToPrimitive;
|
||||
use paint_api::{CrossProcessPaintApi, PinchZoomInfos};
|
||||
@@ -3677,6 +3678,7 @@ impl Window {
|
||||
inherited_secure_context: Option<bool>,
|
||||
theme: Theme,
|
||||
weak_script_thread: Weak<ScriptThread>,
|
||||
initial_https_state: HttpsState,
|
||||
) -> DomRoot<Self> {
|
||||
let error_reporter = CSSErrorReporter {
|
||||
pipelineid: pipeline_id,
|
||||
@@ -3702,6 +3704,7 @@ impl Window {
|
||||
inherited_secure_context,
|
||||
unminify_js,
|
||||
Some(font_context),
|
||||
initial_https_state,
|
||||
),
|
||||
ongoing_navigation: Default::default(),
|
||||
script_chan,
|
||||
|
||||
@@ -39,7 +39,7 @@ use crate::dom::bindings::error::{ErrorInfo, ErrorResult};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::DomGlobal;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::bindings::structuredclone;
|
||||
use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox};
|
||||
@@ -215,7 +215,6 @@ pub(crate) struct DedicatedWorkerGlobalScope {
|
||||
control_receiver: Receiver<DedicatedWorkerControlMsg>,
|
||||
#[no_trace]
|
||||
queued_worker_tasks: DomRefCell<Vec<MessageData>>,
|
||||
debugger_global: Dom<DebuggerGlobalScope>,
|
||||
}
|
||||
|
||||
impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
|
||||
@@ -280,7 +279,6 @@ impl DedicatedWorkerGlobalScope {
|
||||
control_receiver: Receiver<DedicatedWorkerControlMsg>,
|
||||
insecure_requests_policy: InsecureRequestsPolicy,
|
||||
font_context: Option<Arc<FontContext>>,
|
||||
debugger_global: &DebuggerGlobalScope,
|
||||
) -> DedicatedWorkerGlobalScope {
|
||||
DedicatedWorkerGlobalScope {
|
||||
workerglobalscope: WorkerGlobalScope::new_inherited(
|
||||
@@ -305,7 +303,6 @@ impl DedicatedWorkerGlobalScope {
|
||||
browsing_context,
|
||||
control_receiver,
|
||||
queued_worker_tasks: Default::default(),
|
||||
debugger_global: Dom::from_ref(debugger_global),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,9 +347,13 @@ impl DedicatedWorkerGlobalScope {
|
||||
control_receiver,
|
||||
insecure_requests_policy,
|
||||
font_context,
|
||||
debugger_global,
|
||||
));
|
||||
DedicatedWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(cx, scope)
|
||||
let scope = DedicatedWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(cx, scope);
|
||||
scope
|
||||
.upcast::<WorkerGlobalScope>()
|
||||
.init_debugger_global(debugger_global, cx);
|
||||
|
||||
scope
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#run-a-worker>
|
||||
@@ -671,20 +672,9 @@ impl DedicatedWorkerGlobalScope {
|
||||
}
|
||||
// FIXME(#26324): `self.worker` is None in devtools messages.
|
||||
match msg {
|
||||
MixedMessage::Devtools(msg) => match msg {
|
||||
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, _bool_val) => {},
|
||||
DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
|
||||
self.debugger_global.fire_eval(
|
||||
cx,
|
||||
code.into(),
|
||||
id,
|
||||
Some(self.upcast::<WorkerGlobalScope>().worker_id()),
|
||||
frame_actor_id,
|
||||
reply,
|
||||
);
|
||||
},
|
||||
_ => debug!("got an unusable devtools control message inside the worker!"),
|
||||
},
|
||||
MixedMessage::Devtools(msg) => self
|
||||
.upcast::<WorkerGlobalScope>()
|
||||
.handle_devtools_message(msg, cx),
|
||||
MixedMessage::Worker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
|
||||
let _ar = AutoWorkerReset::new(self, linked_worker);
|
||||
self.handle_script_event(msg, cx);
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::thread::{self, JoinHandle};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crossbeam_channel::{Receiver, Sender, after};
|
||||
use devtools_traits::{DebuggerValue, DevtoolScriptControlMsg, EvaluateJSReply};
|
||||
use devtools_traits::DevtoolScriptControlMsg;
|
||||
use dom_struct::dom_struct;
|
||||
use fonts::FontContext;
|
||||
use js::jsapi::{JS_AddInterruptCallback, JSContext};
|
||||
@@ -34,7 +34,7 @@ use crate::dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding;
|
||||
use crate::dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWorkerGlobalScopeMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WorkerBinding::WorkerType;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::bindings::structuredclone;
|
||||
use crate::dom::bindings::trace::CustomTraceable;
|
||||
@@ -182,8 +182,6 @@ pub(crate) struct ServiceWorkerGlobalScope {
|
||||
/// currently only used to signal shutdown.
|
||||
#[no_trace]
|
||||
control_receiver: Receiver<ServiceWorkerControlMsg>,
|
||||
|
||||
debugger_global: Option<Dom<DebuggerGlobalScope>>,
|
||||
}
|
||||
|
||||
impl WorkerEventLoopMethods for ServiceWorkerGlobalScope {
|
||||
@@ -242,7 +240,6 @@ impl ServiceWorkerGlobalScope {
|
||||
control_receiver: Receiver<ServiceWorkerControlMsg>,
|
||||
closing: Arc<AtomicBool>,
|
||||
font_context: Arc<FontContext>,
|
||||
debugger_global: Option<&DebuggerGlobalScope>,
|
||||
) -> ServiceWorkerGlobalScope {
|
||||
ServiceWorkerGlobalScope {
|
||||
workerglobalscope: WorkerGlobalScope::new_inherited(
|
||||
@@ -265,7 +262,6 @@ impl ServiceWorkerGlobalScope {
|
||||
swmanager_sender,
|
||||
scope_url,
|
||||
control_receiver,
|
||||
debugger_global: debugger_global.map(Dom::from_ref),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +279,7 @@ impl ServiceWorkerGlobalScope {
|
||||
control_receiver: Receiver<ServiceWorkerControlMsg>,
|
||||
closing: Arc<AtomicBool>,
|
||||
font_context: Arc<FontContext>,
|
||||
debugger_global: Option<&DebuggerGlobalScope>,
|
||||
debugger_global: &DebuggerGlobalScope,
|
||||
cx: &mut js::context::JSContext,
|
||||
) -> DomRoot<ServiceWorkerGlobalScope> {
|
||||
let scope = Box::new(ServiceWorkerGlobalScope::new_inherited(
|
||||
@@ -299,9 +295,13 @@ impl ServiceWorkerGlobalScope {
|
||||
control_receiver,
|
||||
closing,
|
||||
font_context,
|
||||
debugger_global,
|
||||
));
|
||||
ServiceWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(cx, scope)
|
||||
let scope = ServiceWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(cx, scope);
|
||||
scope
|
||||
.upcast::<WorkerGlobalScope>()
|
||||
.init_debugger_global(debugger_global, cx);
|
||||
|
||||
scope
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/ServiceWorker/#run-service-worker-algorithm>
|
||||
@@ -347,27 +347,23 @@ impl ServiceWorkerGlobalScope {
|
||||
pipeline_id,
|
||||
} = worker_load_origin;
|
||||
|
||||
let debugger_global =
|
||||
let debugger_global = DebuggerGlobalScope::new(
|
||||
pipeline_id,
|
||||
init.to_devtools_sender.clone(),
|
||||
init.from_devtools_sender
|
||||
.clone()
|
||||
.map(|from_devtools_sender| {
|
||||
let debugger_global = DebuggerGlobalScope::new(
|
||||
pipeline_id,
|
||||
init.to_devtools_sender.clone(),
|
||||
from_devtools_sender,
|
||||
init.mem_profiler_chan.clone(),
|
||||
init.time_profiler_chan.clone(),
|
||||
init.script_to_constellation_chan.clone(),
|
||||
init.script_to_embedder_chan.clone(),
|
||||
init.resource_threads.clone(),
|
||||
init.storage_threads.clone(),
|
||||
#[cfg(feature = "webgpu")]
|
||||
Arc::new(IdentityHub::default()),
|
||||
cx,
|
||||
);
|
||||
debugger_global.execute(cx);
|
||||
debugger_global
|
||||
});
|
||||
.expect("Guaranteed by update_serviceworker"),
|
||||
init.mem_profiler_chan.clone(),
|
||||
init.time_profiler_chan.clone(),
|
||||
init.script_to_constellation_chan.clone(),
|
||||
init.script_to_embedder_chan.clone(),
|
||||
init.resource_threads.clone(),
|
||||
init.storage_threads.clone(),
|
||||
#[cfg(feature = "webgpu")]
|
||||
Arc::new(IdentityHub::default()),
|
||||
cx,
|
||||
);
|
||||
debugger_global.execute(cx);
|
||||
|
||||
// Service workers are time limited
|
||||
// https://w3c.github.io/ServiceWorker/#service-worker-lifetime
|
||||
@@ -390,21 +386,19 @@ impl ServiceWorkerGlobalScope {
|
||||
control_receiver,
|
||||
closing,
|
||||
font_context,
|
||||
debugger_global.as_deref(),
|
||||
&debugger_global,
|
||||
cx,
|
||||
);
|
||||
|
||||
let worker_scope = global.upcast::<WorkerGlobalScope>();
|
||||
let global_scope = global.upcast::<GlobalScope>();
|
||||
|
||||
if let Some(debugger_global) = debugger_global.as_deref() {
|
||||
debugger_global.fire_add_debuggee(
|
||||
cx,
|
||||
global_scope,
|
||||
pipeline_id,
|
||||
Some(worker_scope.worker_id()),
|
||||
);
|
||||
}
|
||||
debugger_global.fire_add_debuggee(
|
||||
cx,
|
||||
global_scope,
|
||||
pipeline_id,
|
||||
Some(worker_scope.worker_id()),
|
||||
);
|
||||
|
||||
let referrer = referrer_url
|
||||
.map(Referrer::ReferrerUrl)
|
||||
@@ -495,27 +489,9 @@ impl ServiceWorkerGlobalScope {
|
||||
|
||||
fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut js::context::JSContext) -> bool {
|
||||
match msg {
|
||||
MixedMessage::Devtools(msg) => match msg {
|
||||
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, _wants_updates) => {},
|
||||
DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
|
||||
if let Some(debugger_global) = self.debugger_global.as_deref() {
|
||||
debugger_global.fire_eval(
|
||||
cx,
|
||||
code.into(),
|
||||
id,
|
||||
Some(self.upcast::<WorkerGlobalScope>().worker_id()),
|
||||
frame_actor_id,
|
||||
reply,
|
||||
);
|
||||
} else {
|
||||
let _ = reply.send(EvaluateJSReply {
|
||||
value: DebuggerValue::VoidValue,
|
||||
has_exception: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
_ => debug!("got an unusable devtools control message inside the worker!"),
|
||||
},
|
||||
MixedMessage::Devtools(msg) => self
|
||||
.upcast::<WorkerGlobalScope>()
|
||||
.handle_devtools_message(msg, cx),
|
||||
MixedMessage::ServiceWorker(msg) => {
|
||||
self.handle_script_event(msg, cx);
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ use dom_struct::dom_struct;
|
||||
use encoding_rs::UTF_8;
|
||||
use fonts::FontContext;
|
||||
use headers::{HeaderMapExt, ReferrerPolicy as ReferrerPolicyHeader};
|
||||
use js::jsapi::JSContext as RawJSContext;
|
||||
use js::jsapi::{Heap, JSContext as RawJSContext, Value};
|
||||
use js::realm::CurrentRealm;
|
||||
use js::rust::{HandleValue, MutableHandleValue, ParentRuntime};
|
||||
use mime::Mime;
|
||||
@@ -24,8 +24,12 @@ use net_traits::policy_container::PolicyContainer;
|
||||
use net_traits::request::{
|
||||
CredentialsMode, Destination, InsecureRequestsPolicy, ParserMetadata, RequestBuilder, RequestId,
|
||||
};
|
||||
use net_traits::response::HttpsState;
|
||||
use net_traits::{FetchMetadata, Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming};
|
||||
use profile_traits::mem::{ProcessReports, perform_memory_report};
|
||||
use script_bindings::conversions::{SafeToJSValConvertible, root_from_handlevalue};
|
||||
use script_bindings::reflector::DomObject;
|
||||
use script_bindings::root::rooted_heap_handle;
|
||||
use servo_base::cross_process_instant::CrossProcessInstant;
|
||||
use servo_base::generic_channel::{GenericSend, GenericSender, RoutedReceiver};
|
||||
use servo_base::id::{PipelineId, PipelineNamespace};
|
||||
@@ -59,6 +63,7 @@ use crate::dom::bindings::trace::RootedTraceableBox;
|
||||
use crate::dom::bindings::utils::define_all_exposed_interfaces;
|
||||
use crate::dom::crypto::Crypto;
|
||||
use crate::dom::csp::{GlobalCspReporting, Violation, parse_csp_list_from_metadata};
|
||||
use crate::dom::debugger::debuggerglobalscope::DebuggerGlobalScope;
|
||||
use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
|
||||
use crate::dom::global_scope_script_execution::{ErrorReporting, RethrowErrors};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
@@ -319,6 +324,13 @@ pub(crate) struct WorkerGlobalScope {
|
||||
/// <https://w3c.github.io/reporting/#windoworworkerglobalscope-endpoints>
|
||||
#[no_trace]
|
||||
endpoints_list: DomRefCell<Vec<ReportingEndpoint>>,
|
||||
|
||||
/// The debugger global object associated with this worker global.
|
||||
/// All traced members of DOM objects must be same-compartment with the
|
||||
/// realm being traced, so this is the debugger global object wrapped into
|
||||
/// this global's compartment.
|
||||
#[ignore_malloc_size_of = "Measured by the JS engine"]
|
||||
debugger_global: Heap<Value>,
|
||||
}
|
||||
|
||||
impl WorkerGlobalScope {
|
||||
@@ -361,6 +373,7 @@ impl WorkerGlobalScope {
|
||||
init.inherited_secure_context,
|
||||
init.unminify_js,
|
||||
font_context,
|
||||
HttpsState::None,
|
||||
),
|
||||
microtask_queue: runtime.microtask_queue.clone(),
|
||||
worker_id: init.worker_id,
|
||||
@@ -384,6 +397,7 @@ impl WorkerGlobalScope {
|
||||
reporting_observer_list: Default::default(),
|
||||
report_list: Default::default(),
|
||||
endpoints_list: Default::default(),
|
||||
debugger_global: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1054,6 +1068,51 @@ impl WorkerGlobalScope {
|
||||
factory.abort_pending_upgrades();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn init_debugger_global(
|
||||
&self,
|
||||
debugger_global: &DebuggerGlobalScope,
|
||||
cx: &mut js::context::JSContext,
|
||||
) {
|
||||
let mut realm = enter_auto_realm(cx, self);
|
||||
let cx = &mut realm.current_realm();
|
||||
|
||||
// Convert the debugger global’s reflector to a Value, wrapping it from its originating realm (debugger realm)
|
||||
// into the active realm (debuggee realm) so that it can be passed across compartments.
|
||||
rooted!(&in(cx) let mut wrapped_global: Value);
|
||||
debugger_global.reflector().safe_to_jsval(
|
||||
cx.into(),
|
||||
wrapped_global.handle_mut(),
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
self.debugger_global.set(*wrapped_global);
|
||||
}
|
||||
|
||||
pub(super) fn handle_devtools_message(
|
||||
&self,
|
||||
msg: DevtoolScriptControlMsg,
|
||||
cx: &mut js::context::JSContext,
|
||||
) {
|
||||
match msg {
|
||||
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, _wants_updates) => {},
|
||||
DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
|
||||
let debugger_global_handle = rooted_heap_handle(self, |this| &this.debugger_global);
|
||||
let debugger_global =
|
||||
root_from_handlevalue::<DebuggerGlobalScope>(debugger_global_handle, cx.into())
|
||||
.expect("must be a debugger global scope");
|
||||
|
||||
debugger_global.fire_eval(
|
||||
cx,
|
||||
code.into(),
|
||||
id,
|
||||
Some(self.worker_id()),
|
||||
frame_actor_id,
|
||||
reply,
|
||||
);
|
||||
},
|
||||
_ => debug!("got an unusable devtools control message inside the worker!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(unsafe_code)]
|
||||
|
||||
@@ -12,6 +12,7 @@ use embedder_traits::{JavaScriptEvaluationError, ScriptToEmbedderChan};
|
||||
use js::context::JSContext;
|
||||
use net_traits::ResourceThreads;
|
||||
use net_traits::image_cache::ImageCache;
|
||||
use net_traits::response::HttpsState;
|
||||
use profile_traits::{mem, time};
|
||||
use script_traits::Painter;
|
||||
use servo_base::generic_channel::{GenericCallback, GenericSender};
|
||||
@@ -124,6 +125,7 @@ impl WorkletGlobalScope {
|
||||
inherited_secure_context,
|
||||
false,
|
||||
None, // font_context
|
||||
HttpsState::None,
|
||||
),
|
||||
base_url,
|
||||
to_script_thread_sender: init.to_script_thread_sender.clone(),
|
||||
|
||||
@@ -27,10 +27,24 @@ mod servo_dangerous_style_shadow_root;
|
||||
mod servo_layout_element;
|
||||
mod servo_layout_node;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub use iterators::*;
|
||||
use layout_api::LayoutDomTypeBundle;
|
||||
pub use servo_dangerous_style_document::*;
|
||||
pub use servo_dangerous_style_element::*;
|
||||
pub use servo_dangerous_style_node::*;
|
||||
pub use servo_dangerous_style_shadow_root::*;
|
||||
pub use servo_layout_element::*;
|
||||
pub use servo_layout_node::*;
|
||||
|
||||
pub struct ServoLayoutDomTypeBundle<'dom> {
|
||||
phantom: PhantomData<&'dom ()>,
|
||||
}
|
||||
|
||||
impl<'dom> LayoutDomTypeBundle<'dom> for ServoLayoutDomTypeBundle<'dom> {
|
||||
type ConcreteLayoutElement = ServoLayoutElement<'dom>;
|
||||
type ConcreteLayoutNode = ServoLayoutNode<'dom>;
|
||||
type ConcreteDangerousStyleNode = ServoDangerousStyleNode<'dom>;
|
||||
type ConcreteDangerousStyleElement = ServoDangerousStyleElement<'dom>;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ use crate::dom::html::htmlslotelement::HTMLSlotElement;
|
||||
use crate::dom::node::{Node, NodeFlags};
|
||||
use crate::layout_dom::{
|
||||
DOMDescendantIterator, ServoDangerousStyleNode, ServoDangerousStyleShadowRoot,
|
||||
ServoLayoutElement, ServoLayoutNode,
|
||||
ServoLayoutDomTypeBundle, ServoLayoutElement, ServoLayoutNode,
|
||||
};
|
||||
|
||||
/// A wrapper around [`LayoutDom<_, Element>`] to be used with `stylo` and `selectors`.
|
||||
@@ -81,9 +81,9 @@ impl<'dom> From<LayoutDom<'dom, Element>> for ServoDangerousStyleElement<'dom> {
|
||||
}
|
||||
|
||||
impl<'dom> DangerousStyleElement<'dom> for ServoDangerousStyleElement<'dom> {
|
||||
type ConcreteLayoutElement = ServoLayoutElement<'dom>;
|
||||
type ConcreteTypeBundle = ServoLayoutDomTypeBundle<'dom>;
|
||||
|
||||
fn layout_element(&self) -> Self::ConcreteLayoutElement {
|
||||
fn layout_element(&self) -> ServoLayoutElement<'dom> {
|
||||
self.element.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ use super::{ServoDangerousStyleDocument, ServoDangerousStyleShadowRoot};
|
||||
use crate::dom::bindings::error::Error;
|
||||
use crate::dom::bindings::root::LayoutDom;
|
||||
use crate::dom::node::{Node, NodeFlags};
|
||||
use crate::layout_dom::{ServoDangerousStyleElement, ServoLayoutNode};
|
||||
use crate::layout_dom::{ServoDangerousStyleElement, ServoLayoutDomTypeBundle, ServoLayoutNode};
|
||||
|
||||
/// A wrapper around [`LayoutDom<_, Node>`] to be used with `stylo` and `selectors`.
|
||||
///
|
||||
@@ -75,9 +75,9 @@ impl<'dom> From<LayoutDom<'dom, Node>> for ServoDangerousStyleNode<'dom> {
|
||||
}
|
||||
|
||||
impl<'dom> DangerousStyleNode<'dom> for ServoDangerousStyleNode<'dom> {
|
||||
type ConcreteLayoutNode = ServoLayoutNode<'dom>;
|
||||
type ConcreteTypeBundle = ServoLayoutDomTypeBundle<'dom>;
|
||||
|
||||
fn layout_node(&self) -> Self::ConcreteLayoutNode {
|
||||
fn layout_node(&self) -> ServoLayoutNode<'dom> {
|
||||
self.node.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ use crate::dom::bindings::root::LayoutDom;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::node::{Node, NodeFlags};
|
||||
use crate::layout_dom::{
|
||||
ServoDangerousStyleElement, ServoDangerousStyleShadowRoot, ServoLayoutNode,
|
||||
ServoDangerousStyleElement, ServoDangerousStyleShadowRoot, ServoLayoutDomTypeBundle,
|
||||
ServoLayoutNode,
|
||||
};
|
||||
|
||||
impl fmt::Debug for LayoutDom<'_, Element> {
|
||||
@@ -72,8 +73,7 @@ impl<'dom> From<LayoutDom<'dom, Element>> for ServoLayoutElement<'dom> {
|
||||
}
|
||||
|
||||
impl<'dom> LayoutElement<'dom> for ServoLayoutElement<'dom> {
|
||||
type ConcreteLayoutNode = ServoLayoutNode<'dom>;
|
||||
type ConcreteStyleElement = ServoDangerousStyleElement<'dom>;
|
||||
type ConcreteTypeBundle = ServoLayoutDomTypeBundle<'dom>;
|
||||
|
||||
fn with_pseudo(&self, pseudo_element: PseudoElement) -> Option<Self> {
|
||||
if pseudo_element.is_eager() &&
|
||||
@@ -174,7 +174,7 @@ impl<'dom> LayoutElement<'dom> for ServoLayoutElement<'dom> {
|
||||
},
|
||||
PseudoElementCascadeType::Precomputed => context
|
||||
.stylist
|
||||
.precomputed_values_for_pseudo::<Self::ConcreteStyleElement>(
|
||||
.precomputed_values_for_pseudo::<ServoDangerousStyleElement<'dom>>(
|
||||
&context.guards,
|
||||
&pseudo_element,
|
||||
Some(base_style),
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::dom::bindings::root::LayoutDom;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::node::{Node, NodeFlags, NodeTypeIdWrapper};
|
||||
use crate::layout_dom::{
|
||||
ServoDangerousStyleElement, ServoDangerousStyleNode, ServoLayoutNodeChildrenIterator,
|
||||
ServoDangerousStyleNode, ServoLayoutDomTypeBundle, ServoLayoutNodeChildrenIterator,
|
||||
};
|
||||
|
||||
impl fmt::Debug for LayoutDom<'_, Node> {
|
||||
@@ -113,10 +113,7 @@ impl<'dom> From<LayoutDom<'dom, Node>> for ServoLayoutNode<'dom> {
|
||||
}
|
||||
|
||||
impl<'dom> LayoutNode<'dom> for ServoLayoutNode<'dom> {
|
||||
type ConcreteDangerousStyleNode = ServoDangerousStyleNode<'dom>;
|
||||
type ConcreteDangerousStyleElement = ServoDangerousStyleElement<'dom>;
|
||||
type ConcreteLayoutElement = ServoLayoutElement<'dom>;
|
||||
type ChildIterator = ServoLayoutNodeChildrenIterator<'dom>;
|
||||
type ConcreteTypeBundle = ServoLayoutDomTypeBundle<'dom>;
|
||||
|
||||
fn with_pseudo(&self, pseudo_element_type: PseudoElement) -> Option<Self> {
|
||||
Some(
|
||||
@@ -126,7 +123,7 @@ impl<'dom> LayoutNode<'dom> for ServoLayoutNode<'dom> {
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn dangerous_style_node(self) -> Self::ConcreteDangerousStyleNode {
|
||||
unsafe fn dangerous_style_node(self) -> ServoDangerousStyleNode<'dom> {
|
||||
self.node.into()
|
||||
}
|
||||
|
||||
@@ -224,11 +221,11 @@ impl<'dom> LayoutNode<'dom> for ServoLayoutNode<'dom> {
|
||||
}
|
||||
}
|
||||
|
||||
fn flat_tree_children(&self) -> LayoutIterator<ServoLayoutNodeChildrenIterator<'dom>> {
|
||||
fn flat_tree_children(&self) -> impl Iterator<Item = Self> {
|
||||
LayoutIterator(ServoLayoutNodeChildrenIterator::new_for_flat_tree(*self))
|
||||
}
|
||||
|
||||
fn dom_children(&self) -> LayoutIterator<ServoLayoutNodeChildrenIterator<'dom>> {
|
||||
fn dom_children(&self) -> impl Iterator<Item = Self> {
|
||||
LayoutIterator(ServoLayoutNodeChildrenIterator::new_for_dom_tree(*self))
|
||||
}
|
||||
|
||||
|
||||
@@ -3439,6 +3439,7 @@ impl ScriptThread {
|
||||
incomplete.load_data.inherited_secure_context,
|
||||
incomplete.theme,
|
||||
self.this.clone(),
|
||||
metadata.https_state,
|
||||
);
|
||||
self.debugger_global
|
||||
.fire_add_debuggee(cx, window.upcast(), incomplete.pipeline_id, None);
|
||||
@@ -3600,7 +3601,6 @@ impl ScriptThread {
|
||||
),
|
||||
);
|
||||
|
||||
document.set_https_state(metadata.https_state);
|
||||
document.set_navigation_start(incomplete.navigation_start);
|
||||
|
||||
if is_html_document == IsHTMLDocument::NonHTMLDocument {
|
||||
|
||||
@@ -425,7 +425,7 @@ DOMInterfaces = {
|
||||
},
|
||||
|
||||
"HTMLBodyElement": {
|
||||
"canGc": ["SetBackground"]
|
||||
'implicitCxSetters': True,
|
||||
},
|
||||
|
||||
'HTMLButtonElement': {
|
||||
@@ -480,7 +480,7 @@ DOMInterfaces = {
|
||||
},
|
||||
|
||||
'HTMLFontElement': {
|
||||
'canGc': ['SetSize']
|
||||
'implicitCxSetters': True,
|
||||
},
|
||||
|
||||
'HTMLFormControlsCollection': {
|
||||
@@ -492,10 +492,18 @@ DOMInterfaces = {
|
||||
'cx': ['CheckValidity', 'ReportValidity'],
|
||||
},
|
||||
|
||||
'HTMLFrameSetElement': {
|
||||
'implicitCxSetters': True,
|
||||
},
|
||||
|
||||
'HTMLIFrameElement': {
|
||||
'cx': ['Sandbox', 'SetSrcdoc'],
|
||||
},
|
||||
|
||||
'HTMLHRElement': {
|
||||
'implicitCxSetters': True,
|
||||
},
|
||||
|
||||
'HTMLImageElement': {
|
||||
'cx': ['Decode', 'Image', 'ReportValidity', 'SetCrossOrigin'],
|
||||
},
|
||||
@@ -584,14 +592,20 @@ DOMInterfaces = {
|
||||
'DeleteTFoot',
|
||||
'DeleteTHead',
|
||||
'InsertRow',
|
||||
'SetCaption',
|
||||
'SetTFoot',
|
||||
'SetTHead'
|
||||
],
|
||||
'implicitCxSetters': True,
|
||||
},
|
||||
|
||||
'HTMLTableCellElement': {
|
||||
'implicitCxSetters': True,
|
||||
},
|
||||
'HTMLTableColElement': {
|
||||
'implicitCxSetters': True,
|
||||
},
|
||||
|
||||
'HTMLTableRowElement': {
|
||||
'cx': ['DeleteCell', 'InsertCell']
|
||||
'cx': ['DeleteCell', 'InsertCell'],
|
||||
'implicitCxSetters': True,
|
||||
},
|
||||
|
||||
'HTMLTableSectionElement': {
|
||||
|
||||
@@ -72,6 +72,11 @@ from configuration import (
|
||||
)
|
||||
|
||||
AUTOGENERATED_WARNING_COMMENT = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
|
||||
|
||||
# DFS-ordered prototype ID ranges, populated by GlobalGenRoots.PrototypeList()
|
||||
# and consumed by CGIDLInterface to generate PROTO_FIRST/PROTO_LAST constants.
|
||||
_proto_ranges: dict[str, tuple[int, int]] = {}
|
||||
|
||||
ALLOWED_WARNING_LIST = [
|
||||
'non_camel_case_types',
|
||||
'non_upper_case_globals',
|
||||
@@ -3395,6 +3400,7 @@ let val = PrivateValue(ptr::null());
|
||||
JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, &val);
|
||||
"""
|
||||
|
||||
name = self.descriptor.name
|
||||
return CGGeneric(f"""
|
||||
let raw = Root::new(MaybeUnreflectedDom::from_box(object));
|
||||
|
||||
@@ -3409,6 +3415,7 @@ assert!(!canonical_proto.is_null());
|
||||
|
||||
{create}
|
||||
let root = raw.reflect_with(obj.get());
|
||||
root.reflector().set_proto_id(PrototypeList::ID::{name} as u16);
|
||||
|
||||
{unforgeable}
|
||||
|
||||
@@ -3441,6 +3448,7 @@ class CGWrapGlobalMethod(CGAbstractMethod):
|
||||
members = [f"{function}::<D>(cx.into(), obj.handle(), {array.variableName()}.get(), obj.handle());"
|
||||
for (function, array) in pairs if array.length() > 0]
|
||||
membersStr = "\n".join(members)
|
||||
name = self.descriptor.name
|
||||
|
||||
return CGGeneric(f"""
|
||||
unsafe {{
|
||||
@@ -3459,6 +3467,7 @@ unsafe {{
|
||||
assert!(!obj.is_null());
|
||||
|
||||
let root = raw.reflect_with(obj.get());
|
||||
root.reflector().set_proto_id(PrototypeList::ID::{name} as u16);
|
||||
|
||||
let _ac = JSAutoRealm::new(cx.raw_cx(), obj.get());
|
||||
rooted!(&in(cx) let mut canonical_proto = ptr::null_mut::<JSObject>());
|
||||
@@ -3503,12 +3512,16 @@ class CGIDLInterface(CGThing):
|
||||
check = f"ptr::eq(class, unsafe {{ {bindingModule}::Class.get() }})"
|
||||
else:
|
||||
check = f"ptr::eq(class, unsafe {{ &{bindingModule}::Class.get().dom_class }})"
|
||||
# Get DFS-ordered ID range for this interface (set by PrototypeList generation).
|
||||
proto_first, proto_last = _proto_ranges.get(name, (0, 65535))
|
||||
return f"""
|
||||
impl IDLInterface for {name} {{
|
||||
#[inline]
|
||||
fn derives(class: &'static DOMClass) -> bool {{
|
||||
{check}
|
||||
}}
|
||||
const PROTO_FIRST: u16 = {proto_first};
|
||||
const PROTO_LAST: u16 = {proto_last};
|
||||
}}
|
||||
"""
|
||||
|
||||
@@ -9142,8 +9155,51 @@ class GlobalGenRoots():
|
||||
@staticmethod
|
||||
def PrototypeList(config: Configuration) -> CGThing:
|
||||
# Prototype ID enum.
|
||||
# Assign IDs in DFS preorder of the inheritance tree so that
|
||||
# all descendants of a type occupy a contiguous ID range.
|
||||
# This enables O(1) is::<T>() checks via range comparison.
|
||||
interfaces = config.getDescriptors(isCallback=False, isNamespace=False)
|
||||
protos = [d.name for d in interfaces]
|
||||
|
||||
# Build a tree: parent_name -> sorted list of child names
|
||||
children: dict[str | None, list[str]] = {}
|
||||
name_set = set()
|
||||
for d in interfaces:
|
||||
name = d.name
|
||||
name_set.add(name)
|
||||
parent_name = d.prototypeChain[-2] if len(d.prototypeChain) >= 2 else None
|
||||
children.setdefault(parent_name, []).append(name)
|
||||
|
||||
# Sort children alphabetically for determinism within each level
|
||||
for key in children:
|
||||
children[key].sort()
|
||||
|
||||
# DFS preorder traversal
|
||||
protos: list[str] = []
|
||||
# Track range for each prototype: (first_id, last_id)
|
||||
proto_ranges: dict[str, tuple[int, int]] = {}
|
||||
|
||||
def dfs(name: str) -> None:
|
||||
first_id = len(protos)
|
||||
protos.append(name)
|
||||
for child in children.get(name, []):
|
||||
dfs(child)
|
||||
proto_ranges[name] = (first_id, len(protos) - 1)
|
||||
|
||||
# Start from roots (interfaces with no parent in our set)
|
||||
roots = sorted(children.get(None, []))
|
||||
for root in roots:
|
||||
dfs(root)
|
||||
|
||||
# Any interfaces not in the tree (shouldn't happen, but be safe)
|
||||
for d in interfaces:
|
||||
if d.name not in proto_ranges:
|
||||
first_id = len(protos)
|
||||
protos.append(d.name)
|
||||
proto_ranges[d.name] = (first_id, first_id)
|
||||
|
||||
# Store ranges at module level for use by CGIDLInterface.
|
||||
global _proto_ranges
|
||||
_proto_ranges = proto_ranges
|
||||
constructors = sorted([MakeNativeName(d.name)
|
||||
for d in config.getDescriptors(hasInterfaceObject=True)
|
||||
if d.shouldHaveGetConstructorObjectMethod()])
|
||||
|
||||
@@ -51,6 +51,11 @@ impl<T: ToJSValConvertible + ?Sized> SafeToJSValConvertible for T {
|
||||
pub trait IDLInterface {
|
||||
/// Returns whether the given DOM class derives that interface.
|
||||
fn derives(_: &'static DOMClass) -> bool;
|
||||
|
||||
/// First prototype ID in the DFS-ordered range for this interface and its descendants.
|
||||
const PROTO_FIRST: u16 = 0;
|
||||
/// Last prototype ID in the DFS-ordered range for this interface and its descendants.
|
||||
const PROTO_LAST: u16 = u16::MAX;
|
||||
}
|
||||
|
||||
/// A trait to mark an IDL interface as deriving from another one.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
use std::mem;
|
||||
|
||||
use crate::conversions::{DerivedFrom, IDLInterface, get_dom_class};
|
||||
use crate::conversions::{DerivedFrom, IDLInterface};
|
||||
use crate::reflector::DomObject;
|
||||
use crate::script_runtime::runtime_is_alive;
|
||||
|
||||
@@ -26,8 +26,8 @@ pub trait Castable: IDLInterface + DomObject + Sized {
|
||||
"Attempting to interact with DOM objects after JS runtime has shut down."
|
||||
);
|
||||
|
||||
let class = unsafe { get_dom_class(self.reflector().get_jsobject().get()).unwrap() };
|
||||
T::derives(class)
|
||||
let id = self.reflector().proto_id();
|
||||
id >= T::PROTO_FIRST && id <= T::PROTO_LAST
|
||||
}
|
||||
|
||||
/// Cast a DOM object upwards to one of the interfaces it derives from.
|
||||
|
||||
@@ -42,6 +42,8 @@ pub struct Reflector<T = ()> {
|
||||
object: Heap<*mut JSObject>,
|
||||
/// Associated memory size (of rust side). Used for memory reporting to SM.
|
||||
size: T,
|
||||
/// Cached prototype ID for fast type checks.
|
||||
proto_id: Cell<u16>,
|
||||
}
|
||||
|
||||
unsafe impl<T> js::gc::Traceable for Reflector<T> {
|
||||
@@ -62,6 +64,18 @@ impl<T> Reflector<T> {
|
||||
unsafe { HandleObject::from_raw(self.object.handle()) }
|
||||
}
|
||||
|
||||
/// Get the cached prototype ID.
|
||||
#[inline]
|
||||
pub fn proto_id(&self) -> u16 {
|
||||
self.proto_id.get()
|
||||
}
|
||||
|
||||
/// Set the cached prototype ID.
|
||||
#[inline]
|
||||
pub fn set_proto_id(&self, id: u16) {
|
||||
self.proto_id.set(id);
|
||||
}
|
||||
|
||||
/// Initialize the reflector. (May be called only once.)
|
||||
///
|
||||
/// # Safety
|
||||
@@ -88,6 +102,7 @@ impl<T: AssociatedMemorySize> Reflector<T> {
|
||||
pub fn new() -> Reflector<T> {
|
||||
Reflector {
|
||||
object: Heap::default(),
|
||||
proto_id: Cell::new(u16::MAX),
|
||||
size: T::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::{fmt, mem, ptr};
|
||||
|
||||
use js::gc::Traceable as JSTraceable;
|
||||
use js::jsapi::{JSObject, JSTracer};
|
||||
use js::gc::{Handle, Traceable as JSTraceable};
|
||||
use js::jsapi::{Heap, JSObject, JSTracer};
|
||||
use js::rust::GCMethods;
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use style::thread_state;
|
||||
|
||||
@@ -469,3 +470,17 @@ where
|
||||
unsafe { &*(self as *const [Dom<T>] as *const [&T]) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a handle to a Heap member of a reflected DOM object.
|
||||
/// The provided callback acts as a projection of the rooted-ness of
|
||||
/// the provided DOM object; it must return a reference to a Heap
|
||||
/// member of the DOM object.
|
||||
pub fn rooted_heap_handle<'a, T: DomObject, U: GCMethods + Copy>(
|
||||
object: &'a T,
|
||||
f: impl Fn(&'a T) -> &'a Heap<U>,
|
||||
) -> Handle<'a, U> {
|
||||
// SAFETY: Heap::handle is safe to call when the Heap is a member
|
||||
// of a rooted object. Our safety invariants for DOM objects
|
||||
// ensure that a &T is obtained via a root of T.
|
||||
unsafe { Handle::from_raw(f(object).handle()) }
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ use servo_geometry::{
|
||||
};
|
||||
use servo_media::ServoMedia;
|
||||
use servo_media::player::context::GlContext;
|
||||
use servo_wakelock::NoOpWakeLockProvider;
|
||||
use servo_wakelock::DefaultWakeLockDelegate;
|
||||
use storage::new_storage_threads;
|
||||
use storage_traits::StorageThreads;
|
||||
use style::global_style_data::StyleThreadPool;
|
||||
@@ -930,8 +930,11 @@ impl Servo {
|
||||
protocols.clone(),
|
||||
);
|
||||
|
||||
let (private_storage_threads, public_storage_threads) =
|
||||
new_storage_threads(mem_profiler_chan.clone(), opts.config_dir.clone());
|
||||
let (private_storage_threads, public_storage_threads) = new_storage_threads(
|
||||
mem_profiler_chan.clone(),
|
||||
opts.config_dir.clone(),
|
||||
opts.temporary_storage,
|
||||
);
|
||||
|
||||
create_constellation(
|
||||
embedder_to_constellation_receiver,
|
||||
@@ -1191,7 +1194,7 @@ fn create_constellation(
|
||||
wgpu_image_map: paint.webgpu_image_map(),
|
||||
async_runtime,
|
||||
privileged_urls,
|
||||
wake_lock_provider: Box::new(NoOpWakeLockProvider),
|
||||
wake_lock_provider: Box::new(DefaultWakeLockDelegate),
|
||||
};
|
||||
|
||||
let layout_factory = Arc::new(LayoutFactoryImpl());
|
||||
|
||||
@@ -12,6 +12,7 @@ use embedder_traits::user_contents::UserContentManagerId;
|
||||
use embedder_traits::{
|
||||
AnimationState, FocusSequenceNumber, JSValue, JavaScriptEvaluationError,
|
||||
JavaScriptEvaluationId, MediaSessionEvent, ScriptToEmbedderChan, Theme, ViewportDetails,
|
||||
WakeLockType,
|
||||
};
|
||||
use encoding_rs::Encoding;
|
||||
use euclid::default::Size2D as UntypedSize2D;
|
||||
@@ -37,7 +38,6 @@ use servo_base::id::{
|
||||
use servo_canvas_traits::canvas::{CanvasId, CanvasMsg};
|
||||
use servo_canvas_traits::webgl::WebGLChan;
|
||||
use servo_url::{ImmutableOrigin, OriginSnapshot, ServoUrl};
|
||||
use servo_wakelock::WakeLockType;
|
||||
use storage_traits::StorageThreads;
|
||||
use storage_traits::webstorage_thread::WebStorageType;
|
||||
use strum::IntoStaticStr;
|
||||
|
||||
@@ -1148,3 +1148,25 @@ impl UrlRequest {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of wake lock to acquire or release.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub enum WakeLockType {
|
||||
Screen,
|
||||
}
|
||||
|
||||
/// Trait for platform-specific wake lock support.
|
||||
///
|
||||
/// Implementations are responsible for interacting with the OS to prevent
|
||||
/// the screen (or other resources) from sleeping while a wake lock is held.
|
||||
pub trait WakeLockDelegate: Send + Sync {
|
||||
/// Acquire a wake lock of the given type, preventing the associated
|
||||
/// resource from sleeping. Called when the aggregate lock count transitions
|
||||
/// from 0 to 1. Returns an error if the OS fails to grant the lock.
|
||||
fn acquire(&self, type_: WakeLockType) -> Result<(), Box<dyn std::error::Error>>;
|
||||
|
||||
/// Release a previously acquired wake lock of the given type, allowing
|
||||
/// the resource to sleep. Called when the aggregate lock count transitions
|
||||
/// from N to 0.
|
||||
fn release(&self, type_: WakeLockType) -> Result<(), Box<dyn std::error::Error>>;
|
||||
}
|
||||
|
||||
40
components/shared/layout/layout_dom.rs
Normal file
40
components/shared/layout/layout_dom.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
/* 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/. */
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use crate::{DangerousStyleElement, DangerousStyleNode, LayoutElement, LayoutNode};
|
||||
|
||||
/// A trait that holds all the concrete implementations of the Layout DOM traits. This is
|
||||
/// useful because it means that other types (specifically the implementation of the `Layout`
|
||||
/// trait) can be parameterized over a single type (`LayoutDomTypeBundle`) rather than all of
|
||||
/// the various Layout DOM trait implementations.
|
||||
pub trait LayoutDomTypeBundle<'dom> {
|
||||
/// The concrete implementation of [`LayoutNode`] from `script`.
|
||||
type ConcreteLayoutNode: LayoutNode<'dom>;
|
||||
/// The concrete implementation of [`LayoutElement`] from `script`.
|
||||
type ConcreteLayoutElement: LayoutElement<'dom>;
|
||||
/// The concrete implementation of [`DangerousStyleNode`] from `script`.
|
||||
type ConcreteDangerousStyleNode: DangerousStyleNode<'dom>;
|
||||
/// The concrete implementation of [`DangerousStyleElement`] from `script`.
|
||||
type ConcreteDangerousStyleElement: DangerousStyleElement<'dom>;
|
||||
}
|
||||
|
||||
// The type aliases below simplify extracting the concrete types out of the type bundle. It will be
|
||||
// possible to simplify this once default associated types have landed and are stable:
|
||||
// https://github.com/rust-lang/rust/issues/29661.
|
||||
|
||||
/// Type alias to extract `ConcreteLayoutNode` from a `LayoutDomTypeBundle` implementation.
|
||||
pub type LayoutNodeOf<'dom, T> = <T as LayoutDomTypeBundle<'dom>>::ConcreteLayoutNode;
|
||||
|
||||
/// Type alias to extract `ConcreteLayoutElement` from a `LayoutDomTypeBundle` implementation.
|
||||
pub type LayoutElementOf<'dom, T> = <T as LayoutDomTypeBundle<'dom>>::ConcreteLayoutElement;
|
||||
|
||||
/// Type alias to extract `ConcreteDangerousStyleNode` from a `LayoutDomTypeBundle` implementation.
|
||||
pub type DangerousStyleNodeOf<'dom, T> =
|
||||
<T as LayoutDomTypeBundle<'dom>>::ConcreteDangerousStyleNode;
|
||||
|
||||
/// Type alias to extract `ConcreteDangerousStyleElement` from a `LayoutDomTypeBundle` implementation.
|
||||
pub type DangerousStyleElementOf<'dom, T> =
|
||||
<T as LayoutDomTypeBundle<'dom>>::ConcreteDangerousStyleElement;
|
||||
@@ -16,7 +16,8 @@ use style::dom::TElement;
|
||||
use style::properties::ComputedValues;
|
||||
use style::selector_parser::{PseudoElement, SelectorImpl};
|
||||
|
||||
use crate::{LayoutDataTrait, LayoutNode, LayoutNodeType, PseudoElementChain, StyleData};
|
||||
use crate::layout_dom::{DangerousStyleElementOf, LayoutElementOf, LayoutNodeOf};
|
||||
use crate::{LayoutDataTrait, LayoutDomTypeBundle, LayoutNodeType, PseudoElementChain, StyleData};
|
||||
|
||||
/// A trait that exposes a DOM element to layout. Implementors of this trait must abide by certain
|
||||
/// safety requirements. Layout will only ever access and mutate each element from a single thread
|
||||
@@ -28,12 +29,8 @@ use crate::{LayoutDataTrait, LayoutNode, LayoutNodeType, PseudoElementChain, Sty
|
||||
/// that API is marked as `unsafe` here. In general [`DangerousStyleElement`] should only be used
|
||||
/// when interfacing with the `stylo` and `selectors`.
|
||||
pub trait LayoutElement<'dom>: Copy + Debug + Send + Sync {
|
||||
/// An associated type that refers to the concrete implementation of [`DangerousStyleElement`]
|
||||
/// implemented in `script`.
|
||||
type ConcreteStyleElement: DangerousStyleElement<'dom>;
|
||||
/// An associated type that refers to the concrete implementation of [`LayoutNode`]
|
||||
/// implemented in `script`.
|
||||
type ConcreteLayoutNode: LayoutNode<'dom>;
|
||||
/// The concrete implementation of [`LayoutDomTypeBundle`] implemented in `script`.
|
||||
type ConcreteTypeBundle: LayoutDomTypeBundle<'dom>;
|
||||
|
||||
/// Creates a new `LayoutElement` for the same `LayoutElement`
|
||||
/// with a different pseudo-element type.
|
||||
@@ -53,7 +50,7 @@ pub trait LayoutElement<'dom>: Copy + Debug + Send + Sync {
|
||||
|
||||
/// Return this [`LayoutElement`] as a [`LayoutNode`], preserving the internal
|
||||
/// pseudo-element chain.
|
||||
fn as_node(&self) -> Self::ConcreteLayoutNode;
|
||||
fn as_node(&self) -> LayoutNodeOf<'dom, Self::ConcreteTypeBundle>;
|
||||
|
||||
/// Returns access to a version of this LayoutElement that can be used by stylo
|
||||
/// and selectors. This is dangerous as it allows more access to ancestor nodes
|
||||
@@ -65,7 +62,9 @@ pub trait LayoutElement<'dom>: Copy + Debug + Send + Sync {
|
||||
/// This should only ever be called from the main script thread. It is never
|
||||
/// okay to explicitly create a node for style while any layout worker threads
|
||||
/// are running.
|
||||
unsafe fn dangerous_style_element(self) -> Self::ConcreteStyleElement;
|
||||
unsafe fn dangerous_style_element(
|
||||
self,
|
||||
) -> DangerousStyleElementOf<'dom, Self::ConcreteTypeBundle>;
|
||||
|
||||
/// Initialize this node with empty style and opaque layout data.
|
||||
fn initialize_style_and_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self);
|
||||
@@ -144,9 +143,8 @@ pub trait LayoutElement<'dom>: Copy + Debug + Send + Sync {
|
||||
pub trait DangerousStyleElement<'dom>:
|
||||
TElement + ::selectors::Element<Impl = SelectorImpl> + Send + Sync
|
||||
{
|
||||
/// The concrete implementation of [`LayoutElement`] implemented in `script`.
|
||||
type ConcreteLayoutElement: LayoutElement<'dom>;
|
||||
/// The concrete implementation of [`LayoutNode`] implemented in `script`.
|
||||
/// The concrete implementation of [`LayoutDomTypeBundle`] implemented in `script`.
|
||||
type ConcreteTypeBundle: LayoutDomTypeBundle<'dom>;
|
||||
/// Get a handle to the original "safe" version of this element, a [`LayoutElement`].
|
||||
fn layout_element(&self) -> Self::ConcreteLayoutElement;
|
||||
fn layout_element(&self) -> LayoutElementOf<'dom, Self::ConcreteTypeBundle>;
|
||||
}
|
||||
|
||||
@@ -14,15 +14,15 @@ use servo_arc::Arc;
|
||||
use servo_base::id::{BrowsingContextId, PipelineId};
|
||||
use servo_url::ServoUrl;
|
||||
use style::context::SharedStyleContext;
|
||||
use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, TNode};
|
||||
use style::dom::{NodeInfo, OpaqueNode, TNode};
|
||||
use style::properties::ComputedValues;
|
||||
use style::selector_parser::PseudoElement;
|
||||
|
||||
use crate::layout_element::{DangerousStyleElement, LayoutElement};
|
||||
use crate::layout_dom::{DangerousStyleNodeOf, LayoutElementOf, LayoutNodeOf};
|
||||
use crate::pseudo_element_chain::PseudoElementChain;
|
||||
use crate::{
|
||||
GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutDataTrait, LayoutNodeType,
|
||||
SVGElementData, SharedSelection,
|
||||
GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutDataTrait, LayoutDomTypeBundle,
|
||||
LayoutNodeType, SVGElementData, SharedSelection,
|
||||
};
|
||||
|
||||
/// A trait that exposes a DOM nodes to layout. Implementors of this trait must abide by certain
|
||||
@@ -35,14 +35,8 @@ use crate::{
|
||||
/// that API is marked as `unsafe` here. In general [`DangerousStyleNode`] should only be used
|
||||
/// when interfacing with the `stylo` and `selectors`.
|
||||
pub trait LayoutNode<'dom>: Copy + Debug + NodeInfo + Send + Sync {
|
||||
/// The concrete implementation of [`DangerousStyleNode`] implemented in `script`.
|
||||
type ConcreteDangerousStyleNode: DangerousStyleNode<'dom>;
|
||||
/// The concrete implementation of [`DangerousStyleElement`] implemented in `script`.
|
||||
type ConcreteDangerousStyleElement: DangerousStyleElement<'dom>;
|
||||
/// The concrete implementation of [`ConcreteLayoutElement`] implemented in `script`.
|
||||
type ConcreteLayoutElement: LayoutElement<'dom>;
|
||||
/// The concrete implementation of [`ChildIterator`] implemented in `script`.
|
||||
type ChildIterator: Iterator<Item = Self> + Sized;
|
||||
/// The concrete implementation of [`LayoutDomTypeBundle`] implemented in `script`.
|
||||
type ConcreteTypeBundle: LayoutDomTypeBundle<'dom>;
|
||||
|
||||
/// Creates a new `LayoutNode` for the same `LayoutNode` with a different pseudo-element type.
|
||||
///
|
||||
@@ -70,7 +64,7 @@ pub trait LayoutNode<'dom>: Copy + Debug + NodeInfo + Send + Sync {
|
||||
/// This should only ever be called from the main script thread. It is never
|
||||
/// okay to explicitly create a node for style while any layout worker threads
|
||||
/// are running.
|
||||
unsafe fn dangerous_style_node(self) -> Self::ConcreteDangerousStyleNode;
|
||||
unsafe fn dangerous_style_node(self) -> DangerousStyleNodeOf<'dom, Self::ConcreteTypeBundle>;
|
||||
|
||||
/// Returns access to the DOM parent node of this node. This *does not* take
|
||||
/// into account shadow tree children and slottables. For that use
|
||||
@@ -115,18 +109,18 @@ pub trait LayoutNode<'dom>: Copy + Debug + NodeInfo + Send + Sync {
|
||||
/// takes into account shadow tree children and slottables.
|
||||
///
|
||||
/// [flat tree]: https://drafts.csswg.org/css-shadow-1/#flat-tree
|
||||
fn flat_tree_children(&self) -> LayoutIterator<Self::ChildIterator>;
|
||||
fn flat_tree_children(&self) -> impl Iterator<Item = Self> + Sized;
|
||||
|
||||
/// Returns an iterator over this node's children in the DOM. This
|
||||
/// *does not* take shadow roots and assigned slottables into account.
|
||||
/// For that use [`Self::flat_tree_children`].
|
||||
fn dom_children(&self) -> LayoutIterator<Self::ChildIterator>;
|
||||
fn dom_children(&self) -> impl Iterator<Item = Self> + Sized;
|
||||
|
||||
/// Returns a [`LayoutElement`] if this is an element in the HTML namespace, None otherwise.
|
||||
fn as_html_element(&self) -> Option<Self::ConcreteLayoutElement>;
|
||||
fn as_html_element(&self) -> Option<LayoutElementOf<'dom, Self::ConcreteTypeBundle>>;
|
||||
|
||||
/// Returns a [`LayoutElement`] if this is an element.
|
||||
fn as_element(&self) -> Option<Self::ConcreteLayoutElement>;
|
||||
fn as_element(&self) -> Option<LayoutElementOf<'dom, Self::ConcreteTypeBundle>>;
|
||||
|
||||
/// Returns the computed style for the given node, properly handling pseudo-elements. For
|
||||
/// elements this returns their style and for other nodes, this returns the style of the parent
|
||||
@@ -236,8 +230,8 @@ pub trait LayoutNode<'dom>: Copy + Debug + NodeInfo + Send + Sync {
|
||||
/// If you are not interfacing with `stylo` and `selectors` you *should not* use this
|
||||
/// type, unless you know what you are doing.
|
||||
pub trait DangerousStyleNode<'dom>: TNode + Sized + NodeInfo + Send + Sync {
|
||||
/// The concrete implementation of [`LayoutNode`] implemented in `script`.
|
||||
type ConcreteLayoutNode: LayoutNode<'dom>;
|
||||
/// The concrete implementation of [`LayoutDomTypeBundle`] implemented in `script`.
|
||||
type ConcreteTypeBundle: LayoutDomTypeBundle<'dom>;
|
||||
/// Get a handle to the original "safe" version of this node, a [`LayoutNode`] implementation.
|
||||
fn layout_node(&self) -> Self::ConcreteLayoutNode;
|
||||
fn layout_node(&self) -> LayoutNodeOf<'dom, Self::ConcreteTypeBundle>;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
mod layout_damage;
|
||||
mod layout_dom;
|
||||
mod layout_element;
|
||||
mod layout_node;
|
||||
mod pseudo_element_chain;
|
||||
@@ -29,6 +30,10 @@ use embedder_traits::{Cursor, ScriptToEmbedderChan, Theme, UntrustedNodeAddress,
|
||||
use euclid::{Point2D, Rect};
|
||||
use fonts::{FontContext, TextByteRange, WebFontDocumentContext};
|
||||
pub use layout_damage::LayoutDamage;
|
||||
pub use layout_dom::{
|
||||
DangerousStyleElementOf, DangerousStyleNodeOf, LayoutDomTypeBundle, LayoutElementOf,
|
||||
LayoutNodeOf,
|
||||
};
|
||||
pub use layout_element::{DangerousStyleElement, LayoutElement};
|
||||
pub use layout_node::{DangerousStyleNode, LayoutNode};
|
||||
use libc::c_void;
|
||||
|
||||
@@ -642,19 +642,25 @@ impl RegistryEngine for SqliteEngine {
|
||||
}
|
||||
|
||||
pub trait ClientStorageThreadFactory {
|
||||
fn new(config_dir: Option<PathBuf>) -> Self;
|
||||
fn new(config_dir: Option<PathBuf>, temporary_storage: bool) -> Self;
|
||||
}
|
||||
|
||||
impl ClientStorageThreadFactory for ClientStorageThreadHandle {
|
||||
fn new(config_dir: Option<PathBuf>) -> ClientStorageThreadHandle {
|
||||
fn new(config_dir: Option<PathBuf>, temporary_storage: bool) -> ClientStorageThreadHandle {
|
||||
let (generic_sender, generic_receiver) = generic_channel::channel().unwrap();
|
||||
|
||||
let storage_dir = config_dir
|
||||
let base_dir = config_dir
|
||||
.unwrap_or_else(|| {
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
tmp_dir.path().to_path_buf()
|
||||
})
|
||||
.join("clientstorage");
|
||||
let storage_dir = if temporary_storage {
|
||||
let unique_id = uuid::Uuid::new_v4().to_string();
|
||||
base_dir.join("temporary").join(unique_id)
|
||||
} else {
|
||||
base_dir.join("default_v1")
|
||||
};
|
||||
std::fs::create_dir_all(&storage_dir)
|
||||
.expect("Failed to create ClientStorage storage directory");
|
||||
let sender_clone = generic_sender.clone();
|
||||
|
||||
@@ -16,10 +16,11 @@ use crate::{ClientStorageThreadFactory, IndexedDBThreadFactory, WebStorageThread
|
||||
fn new_storage_thread_group(
|
||||
mem_profiler_chan: MemProfilerChan,
|
||||
config_dir: Option<PathBuf>,
|
||||
temporary_storage: bool,
|
||||
label: &str,
|
||||
) -> StorageThreads {
|
||||
let client_storage: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(config_dir.clone());
|
||||
ClientStorageThreadFactory::new(config_dir.clone(), temporary_storage);
|
||||
let idb: GenericSender<IndexedDBThreadMsg> = IndexedDBThreadFactory::new(
|
||||
config_dir.clone(),
|
||||
mem_profiler_chan.clone(),
|
||||
@@ -37,10 +38,16 @@ fn new_storage_thread_group(
|
||||
pub fn new_storage_threads(
|
||||
mem_profiler_chan: MemProfilerChan,
|
||||
config_dir: Option<PathBuf>,
|
||||
temporary_storage: bool,
|
||||
) -> (StorageThreads, StorageThreads) {
|
||||
let private_storage_threads =
|
||||
new_storage_thread_group(mem_profiler_chan.clone(), config_dir.clone(), "private");
|
||||
let public_storage_threads = new_storage_thread_group(mem_profiler_chan, config_dir, "public");
|
||||
let private_storage_threads = new_storage_thread_group(
|
||||
mem_profiler_chan.clone(),
|
||||
config_dir.clone(),
|
||||
temporary_storage,
|
||||
"private",
|
||||
);
|
||||
let public_storage_threads =
|
||||
new_storage_thread_group(mem_profiler_chan, config_dir, temporary_storage, "public");
|
||||
|
||||
(private_storage_threads, public_storage_threads)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,11 @@ fn install_test_namespace() {
|
||||
}
|
||||
|
||||
fn registry_db_path(tmp_dir: &tempfile::TempDir) -> PathBuf {
|
||||
tmp_dir.path().join("clientstorage").join("reg.sqlite")
|
||||
tmp_dir
|
||||
.path()
|
||||
.join("clientstorage")
|
||||
.join("default_v1")
|
||||
.join("reg.sqlite")
|
||||
}
|
||||
|
||||
fn open_registry(tmp_dir: &tempfile::TempDir) -> Connection {
|
||||
@@ -42,7 +46,7 @@ fn obtain_bottle_map(
|
||||
|
||||
#[test]
|
||||
fn test_exit() {
|
||||
let handle: ClientStorageThreadHandle = ClientStorageThreadFactory::new(None);
|
||||
let handle: ClientStorageThreadHandle = ClientStorageThreadFactory::new(None, false);
|
||||
|
||||
let (sender, receiver) = generic_channel::channel().unwrap();
|
||||
handle
|
||||
@@ -60,7 +64,7 @@ fn test_workflow() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let url = ServoUrl::parse("https://example.com").unwrap();
|
||||
|
||||
@@ -124,7 +128,7 @@ fn test_repeated_local_obtain_reuses_same_logical_rows() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let origin = ServoUrl::parse("https://example.com").unwrap().origin();
|
||||
let webview = WebViewId::new(servo_base::id::TEST_PAINTER_ID);
|
||||
@@ -179,7 +183,7 @@ fn test_repeated_session_obtain_reuses_same_logical_rows() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let origin = ServoUrl::parse("https://example.com").unwrap().origin();
|
||||
let webview = WebViewId::new(servo_base::id::TEST_PAINTER_ID);
|
||||
@@ -235,7 +239,7 @@ fn test_local_persistence_and_estimate() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let origin = ServoUrl::parse("https://example.com").unwrap().origin();
|
||||
let webview = WebViewId::new(servo_base::id::TEST_PAINTER_ID);
|
||||
@@ -287,7 +291,7 @@ fn test_storage_manager_operations_fail_for_opaque_origins() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let origin = ServoUrl::parse("data:text/plain,hello").unwrap().origin();
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ fn shutdown_storage_group(threads: &StorageThreads) {
|
||||
fn test_new_storage_threads_create_independent_groups() {
|
||||
let mem_profiler_chan = profile_mem::Profiler::create();
|
||||
let (private_storage_threads, public_storage_threads) =
|
||||
storage::new_storage_threads(mem_profiler_chan, None);
|
||||
storage::new_storage_threads(mem_profiler_chan, None, false);
|
||||
|
||||
shutdown_storage_group(&private_storage_threads);
|
||||
shutdown_storage_group(&public_storage_threads);
|
||||
|
||||
@@ -22,7 +22,7 @@ impl WebStorageTest {
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let config_dir = tmp_dir.path().to_path_buf();
|
||||
let mem_profiler_chan = profile_mem::Profiler::create();
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, Some(config_dir));
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, Some(config_dir), false);
|
||||
|
||||
Self {
|
||||
tmp_dir: Some(tmp_dir),
|
||||
@@ -32,7 +32,7 @@ impl WebStorageTest {
|
||||
|
||||
pub(crate) fn new_in_memory() -> Self {
|
||||
let mem_profiler_chan = profile_mem::Profiler::create();
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, None);
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, None, false);
|
||||
|
||||
Self {
|
||||
tmp_dir: None,
|
||||
@@ -44,7 +44,7 @@ impl WebStorageTest {
|
||||
let tmp_dir = self.tmp_dir.take();
|
||||
let config_dir = tmp_dir.as_ref().map(|d| d.path().to_path_buf());
|
||||
let mem_profiler_chan = profile_mem::Profiler::create();
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, config_dir);
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, config_dir, false);
|
||||
|
||||
Self {
|
||||
tmp_dir: tmp_dir,
|
||||
|
||||
@@ -14,4 +14,5 @@ name = "servo_wakelock"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
embedder_traits = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
|
||||
@@ -4,43 +4,21 @@
|
||||
|
||||
//! Platform abstraction for the Screen Wake Lock API.
|
||||
//!
|
||||
//! Defines [`WakeLockProvider`], a trait for acquiring and releasing OS-level
|
||||
//! Defines [`WakeLockDelegate`], a trait for acquiring and releasing OS-level
|
||||
//! wake locks. Platform-specific implementations will be added in follow-up
|
||||
//! work. For now, [`NoOpWakeLockProvider`] is the only implementation and
|
||||
//! work. For now, [`DefaultWakeLockDelegate`] is the only implementation and
|
||||
//! does nothing.
|
||||
//!
|
||||
//! <https://w3c.github.io/screen-wake-lock/>
|
||||
use std::error::Error;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use embedder_traits::{WakeLockDelegate, WakeLockType};
|
||||
|
||||
/// The type of wake lock to acquire or release.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub enum WakeLockType {
|
||||
Screen,
|
||||
}
|
||||
|
||||
/// Trait for platform-specific wake lock support.
|
||||
///
|
||||
/// Implementations are responsible for interacting with the OS to prevent
|
||||
/// the screen (or other resources) from sleeping while a wake lock is held.
|
||||
pub trait WakeLockProvider: Send + Sync {
|
||||
/// Acquire a wake lock of the given type, preventing the associated
|
||||
/// resource from sleeping. Called when the aggregate lock count transitions
|
||||
/// from 0 to 1. Returns an error if the OS fails to grant the lock.
|
||||
fn acquire(&self, type_: WakeLockType) -> Result<(), Box<dyn Error>>;
|
||||
|
||||
/// Release a previously acquired wake lock of the given type, allowing
|
||||
/// the resource to sleep. Called when the aggregate lock count transitions
|
||||
/// from N to 0.
|
||||
fn release(&self, type_: WakeLockType) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
/// A no-op [`WakeLockProvider`] used when no platform implementation is
|
||||
/// A no-op [`WakeLockDelegate`] used when no platform implementation is
|
||||
/// available. All operations succeed silently.
|
||||
pub struct NoOpWakeLockProvider;
|
||||
pub struct DefaultWakeLockDelegate;
|
||||
|
||||
impl WakeLockProvider for NoOpWakeLockProvider {
|
||||
impl WakeLockDelegate for DefaultWakeLockDelegate {
|
||||
fn acquire(&self, _type_: WakeLockType) -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -378,6 +378,10 @@ struct CmdArgs {
|
||||
#[bpaf(argument("~/.config/servo"))]
|
||||
config_dir: Option<PathBuf>,
|
||||
|
||||
/// Use temporary storage (data on disk will not persist across restarts).
|
||||
#[bpaf(long)]
|
||||
temporary_storage: bool,
|
||||
|
||||
///
|
||||
/// Run as a content process and connect to the given pipe.
|
||||
#[bpaf(argument("servo-ipc-channel.abcdefg"))]
|
||||
@@ -634,6 +638,7 @@ fn parse_arguments_helper(args_without_binary: Args) -> ArgumentParsingResult {
|
||||
fs::create_dir_all(config_dir).expect("Could not create config_dir");
|
||||
}
|
||||
});
|
||||
let temporary_storage = cmd_args.temporary_storage;
|
||||
if let Some(ref time_profiler_trace_path) = cmd_args.profiler_trace_path {
|
||||
let mut path = PathBuf::from(time_profiler_trace_path);
|
||||
path.pop();
|
||||
@@ -706,6 +711,7 @@ fn parse_arguments_helper(args_without_binary: Args) -> ArgumentParsingResult {
|
||||
random_pipeline_closure_probability: cmd_args.random_pipeline_closure_probability,
|
||||
random_pipeline_closure_seed: cmd_args.random_pipeline_closure_seed,
|
||||
config_dir,
|
||||
temporary_storage,
|
||||
shaders_path: cmd_args.shaders,
|
||||
certificate_path: cmd_args
|
||||
.certificate_path
|
||||
|
||||
@@ -136,6 +136,9 @@ def run_tests(default_binary_path: str, multiprocess: bool, **kwargs: Any) -> in
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="servo-") as config_dir:
|
||||
kwargs["binary_args"] += ["--config-dir", config_dir]
|
||||
# Temporary workaround to avoid shared storage across parallel processes.
|
||||
# Can be removed once per-process config dirs are supported.
|
||||
kwargs["binary_args"] += ["--temporary-storage"]
|
||||
|
||||
wptrunner.run_tests(**kwargs)
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@ macro_rules! sizeof_checker (
|
||||
);
|
||||
|
||||
// Update the sizes here
|
||||
sizeof_checker!(size_event_target, EventTarget, 48);
|
||||
sizeof_checker!(size_node, Node, 152);
|
||||
sizeof_checker!(size_element, Element, 344);
|
||||
sizeof_checker!(size_htmlelement, HTMLElement, 360);
|
||||
sizeof_checker!(size_div, HTMLDivElement, 360);
|
||||
sizeof_checker!(size_span, HTMLSpanElement, 360);
|
||||
sizeof_checker!(size_text, Text, 184);
|
||||
sizeof_checker!(size_characterdata, CharacterData, 184);
|
||||
sizeof_checker!(size_event_target, EventTarget, 56);
|
||||
sizeof_checker!(size_node, Node, 160);
|
||||
sizeof_checker!(size_element, Element, 352);
|
||||
sizeof_checker!(size_htmlelement, HTMLElement, 368);
|
||||
sizeof_checker!(size_div, HTMLDivElement, 368);
|
||||
sizeof_checker!(size_span, HTMLSpanElement, 368);
|
||||
sizeof_checker!(size_text, Text, 192);
|
||||
sizeof_checker!(size_characterdata, CharacterData, 192);
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[data-url.html]
|
||||
[Test data URL and scripts errors]
|
||||
expected: FAIL
|
||||
@@ -1,7 +0,0 @@
|
||||
[window-onerror-runtime-error-throw.html]
|
||||
[correct line number passed to window.onerror]
|
||||
expected: FAIL
|
||||
|
||||
[correct url passed to window.onerror]
|
||||
expected: FAIL
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[fire-selectionchange-event-on-textcontrol-element-on-pressing-backspace.html]
|
||||
[selectionchange event fired on an input element]
|
||||
expected: FAIL
|
||||
@@ -1,6 +0,0 @@
|
||||
[onselectionchange-on-distinct-text-controls.html]
|
||||
[selectionchange event on each input element fires independently]
|
||||
expected: FAIL
|
||||
|
||||
[selectionchange event on each textarea element fires independently]
|
||||
expected: FAIL
|
||||
@@ -1,13 +0,0 @@
|
||||
[selectionchange-bubble.html]
|
||||
expected: TIMEOUT
|
||||
[selectionchange bubbles from input]
|
||||
expected: TIMEOUT
|
||||
|
||||
[selectionchange bubbles from input when focused]
|
||||
expected: NOTRUN
|
||||
|
||||
[selectionchange bubbles from textarea]
|
||||
expected: NOTRUN
|
||||
|
||||
[selectionchange bubbles from textarea when focused]
|
||||
expected: NOTRUN
|
||||
@@ -1,3 +0,0 @@
|
||||
[selectionchange-on-shadow-dom.html]
|
||||
[selectionchange event fired on a shadow dom bubble to the document]
|
||||
expected: FAIL
|
||||
@@ -1,132 +0,0 @@
|
||||
[selectionchange.html]
|
||||
[Modifying selectionStart value of the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Modifying selectionEnd value of the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setSelectionRange() on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling select() on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selectionStart value twice on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selectionEnd value twice on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selection range twice on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling select() twice on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() after select() on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() repeatedly on the input element]
|
||||
expected: FAIL
|
||||
|
||||
[Modifying selectionStart value of the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Modifying selectionEnd value of the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setSelectionRange() on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling select() on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selectionStart value twice on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selectionEnd value twice on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selection range twice on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling select() twice on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() after select() on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() repeatedly on the disconnected input element]
|
||||
expected: FAIL
|
||||
|
||||
[Modifying selectionStart value of the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Modifying selectionEnd value of the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setSelectionRange() on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling select() on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selectionStart value twice on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selectionEnd value twice on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selection range twice on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling select() twice on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() after select() on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() repeatedly on the textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Modifying selectionStart value of the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Modifying selectionEnd value of the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setSelectionRange() on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling select() on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selectionStart value twice on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selectionEnd value twice on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Setting the same selection range twice on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling select() twice on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() after select() on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
|
||||
[Calling setRangeText() repeatedly on the disconnected textarea element]
|
||||
expected: FAIL
|
||||
@@ -2,8 +2,3 @@
|
||||
expected: ERROR
|
||||
|
||||
[report-error-cross-origin.sub.any.worker.html]
|
||||
[WorkerGlobalScope error event: lineno]
|
||||
expected: FAIL
|
||||
|
||||
[WorkerGlobalScope error event: filename]
|
||||
expected: FAIL
|
||||
|
||||
@@ -2,8 +2,3 @@
|
||||
expected: ERROR
|
||||
|
||||
[report-error-redirect-to-cross-origin.sub.any.worker.html]
|
||||
[WorkerGlobalScope error event: lineno]
|
||||
expected: FAIL
|
||||
|
||||
[WorkerGlobalScope error event: filename]
|
||||
expected: FAIL
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
[report-error-setTimeout-cross-origin.sub.any.worker.html]
|
||||
[WorkerGlobalScope error event: lineno]
|
||||
expected: FAIL
|
||||
|
||||
[WorkerGlobalScope error event: filename]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[report-error-setTimeout-cross-origin.sub.any.sharedworker.html]
|
||||
expected: ERROR
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
[report-error-setTimeout-redirect-to-cross-origin.sub.any.worker.html]
|
||||
[WorkerGlobalScope error event: lineno]
|
||||
expected: FAIL
|
||||
|
||||
[WorkerGlobalScope error event: filename]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[report-error-setTimeout-redirect-to-cross-origin.sub.any.sharedworker.html]
|
||||
expected: ERROR
|
||||
|
||||
Reference in New Issue
Block a user