aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/atoms/static_atoms.txt3
-rw-r--r--components/config/prefs.rs12
-rw-r--r--components/constellation/Cargo.toml50
-rw-r--r--components/devtools/Cargo.toml1
-rw-r--r--components/devtools/actors/browsing_context.rs181
-rw-r--r--components/devtools/actors/console.rs179
-rw-r--r--components/devtools/actors/inspector.rs16
-rw-r--r--components/devtools/actors/root.rs13
-rw-r--r--components/devtools/actors/worker.rs130
-rw-r--r--components/devtools/lib.rs312
-rw-r--r--components/devtools_traits/lib.rs20
-rw-r--r--components/layout/animation.rs308
-rw-r--r--components/layout_thread/lib.rs62
-rw-r--r--components/layout_thread_2020/lib.rs27
-rw-r--r--components/net/Cargo.toml34
-rw-r--r--components/script/Cargo.toml84
-rw-r--r--components/script/devtools.rs2
-rw-r--r--components/script/dom/bindings/trace.rs55
-rw-r--r--components/script/dom/console.rs22
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs14
-rw-r--r--components/script/dom/document.rs8
-rw-r--r--components/script/dom/event.rs1
-rw-r--r--components/script/dom/fakexrdevice.rs1
-rw-r--r--components/script/dom/htmlelement.rs21
-rw-r--r--components/script/dom/location.rs254
-rw-r--r--components/script/dom/macros.rs2
-rw-r--r--components/script/dom/mod.rs3
-rw-r--r--components/script/dom/serviceworkerregistration.rs2
-rw-r--r--components/script/dom/vertexarrayobject.rs23
-rw-r--r--components/script/dom/webgl2renderingcontext.rs117
-rw-r--r--components/script/dom/webglbuffer.rs21
-rw-r--r--components/script/dom/webglframebuffer.rs13
-rw-r--r--components/script/dom/webglprogram.rs13
-rw-r--r--components/script/dom/webglquery.rs13
-rw-r--r--components/script/dom/webglrenderbuffer.rs13
-rw-r--r--components/script/dom/webglrenderingcontext.rs671
-rw-r--r--components/script/dom/webglsampler.rs13
-rw-r--r--components/script/dom/webglshader.rs13
-rw-r--r--components/script/dom/webglsync.rs13
-rw-r--r--components/script/dom/webgltexture.rs13
-rw-r--r--components/script/dom/webgltransformfeedback.rs13
-rw-r--r--components/script/dom/webglvertexarrayobject.rs6
-rw-r--r--components/script/dom/webglvertexarrayobjectoes.rs6
-rw-r--r--components/script/dom/webidls/ElementContentEditable.webidl6
-rw-r--r--components/script/dom/webidls/EventHandler.webidl2
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl262
-rw-r--r--components/script/dom/webidls/WebGLRenderingContext.webidl117
-rw-r--r--components/script/dom/webidls/XRFrame.webidl1
-rw-r--r--components/script/dom/webidls/XRHand.webidl41
-rw-r--r--components/script/dom/webidls/XRInputSource.webidl3
-rw-r--r--components/script/dom/webidls/XRJointPose.webidl10
-rw-r--r--components/script/dom/webidls/XRJointSpace.webidl8
-rw-r--r--components/script/dom/window.rs12
-rw-r--r--components/script/dom/worker.rs33
-rw-r--r--components/script/dom/workerglobalscope.rs3
-rw-r--r--components/script/dom/xrframe.rs34
-rw-r--r--components/script/dom/xrhand.rs88
-rw-r--r--components/script/dom/xrinputsource.rs21
-rw-r--r--components/script/dom/xrjointpose.rs48
-rw-r--r--components/script/dom/xrjointspace.rs60
-rw-r--r--components/script/dom/xrspace.rs5
-rw-r--r--components/script/dom/xrsystem.rs3
-rw-r--r--components/script/script_thread.rs190
-rw-r--r--components/script/serviceworker_manager.rs15
-rw-r--r--components/script_traits/lib.rs29
-rw-r--r--components/style/Cargo.toml3
-rw-r--r--components/style/README.md2
-rw-r--r--components/style/animation.rs304
-rw-r--r--components/style/context.rs44
-rw-r--r--components/style/lib.rs2
-rw-r--r--components/style/matching.rs129
-rw-r--r--components/style/rule_tree/core.rs3
-rw-r--r--components/style/rule_tree/mod.rs2
-rw-r--r--components/webdriver_server/lib.rs2
74 files changed, 2732 insertions, 1528 deletions
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt
index 27d45e44d88..ebf4a2c27be 100644
--- a/components/atoms/static_atoms.txt
+++ b/components/atoms/static_atoms.txt
@@ -129,7 +129,9 @@ time
timeupdate
toggle
track
+transitioncancel
transitionend
+transitionrun
unhandledrejection
unload
url
@@ -141,5 +143,6 @@ webkitAnimationEnd
webkitAnimationIteration
webkitAnimationStart
webkitTransitionEnd
+webkitTransitionRun
week
width
diff --git a/components/config/prefs.rs b/components/config/prefs.rs
index 2561ebf937f..b6f2030ad9c 100644
--- a/components/config/prefs.rs
+++ b/components/config/prefs.rs
@@ -297,8 +297,16 @@ mod gen {
enabled: bool,
#[serde(default)]
test: bool,
- #[serde(default)]
- glwindow: bool,
+ glwindow: {
+ #[serde(default)]
+ enabled: bool,
+ #[serde(rename = "dom.webxr.glwindow.red-cyan")]
+ red_cyan: bool,
+ },
+ hands: {
+ #[serde(default)]
+ enabled: bool,
+ },
layers: {
enabled: bool,
}
diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml
index 29be9649c02..2fed3e7b6c8 100644
--- a/components/constellation/Cargo.toml
+++ b/components/constellation/Cargo.toml
@@ -11,40 +11,40 @@ name = "constellation"
path = "lib.rs"
[dependencies]
-background_hang_monitor = { path = "../background_hang_monitor"}
+background_hang_monitor = { path = "../background_hang_monitor" }
backtrace = "0.3"
bluetooth_traits = { path = "../bluetooth_traits" }
-canvas_traits = {path = "../canvas_traits"}
-compositing = {path = "../compositing"}
+canvas_traits = { path = "../canvas_traits" }
+compositing = { path = "../compositing" }
crossbeam-channel = "0.4"
-debugger = {path = "../debugger"}
-devtools_traits = {path = "../devtools_traits"}
-euclid = "0.20"
+debugger = { path = "../debugger" }
+devtools_traits = { path = "../devtools_traits" }
embedder_traits = { path = "../embedder_traits" }
-gfx = {path = "../gfx"}
-gfx_traits = {path = "../gfx_traits"}
+euclid = "0.20"
+gfx = { path = "../gfx" }
+gfx_traits = { path = "../gfx_traits" }
http = "0.1"
ipc-channel = "0.14"
-layout_traits = {path = "../layout_traits"}
keyboard-types = "0.4.3"
+layout_traits = { path = "../layout_traits" }
log = "0.4"
-media = {path = "../media"}
-metrics = {path = "../metrics"}
-msg = {path = "../msg"}
-net = {path = "../net"}
-net_traits = {path = "../net_traits"}
-profile_traits = {path = "../profile_traits"}
-script_traits = {path = "../script_traits"}
+media = { path = "../media" }
+metrics = { path = "../metrics" }
+msg = { path = "../msg" }
+net = { path = "../net" }
+net_traits = { path = "../net_traits" }
+profile_traits = { path = "../profile_traits" }
+script_traits = { path = "../script_traits" }
serde = "1.0"
-style_traits = {path = "../style_traits"}
-servo_config = {path = "../config"}
-servo_geometry = {path = "../geometry"}
-servo_rand = {path = "../rand"}
-servo_remutex = {path = "../remutex"}
-servo_url = {path = "../url"}
-webgpu = {path = "../webgpu"}
-webrender_api = {git = "https://github.com/servo/webrender"}
-webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
+servo_config = { path = "../config" }
+servo_geometry = { path = "../geometry" }
+servo_rand = {path = "../rand" }
+servo_remutex = { path = "../remutex" }
+servo_url = { path = "../url" }
+style_traits = { path = "../style_traits" }
+webgpu = { path = "../webgpu" }
+webrender_api = { git = "https://github.com/servo/webrender" }
+webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
[target.'cfg(all(not(target_os = "windows"), not(target_os = "ios"), not(target_os="android"), not(target_arch="arm"), not(target_arch="aarch64")))'.dependencies]
gaol = "0.2.1"
diff --git a/components/devtools/Cargo.toml b/components/devtools/Cargo.toml
index 69d440f0f7a..8b7c6d6e199 100644
--- a/components/devtools/Cargo.toml
+++ b/components/devtools/Cargo.toml
@@ -22,5 +22,6 @@ log = "0.4"
msg = {path = "../msg"}
serde = "1.0"
serde_json = "1.0"
+servo_url = { path = "../url" }
time = "0.1"
uuid = {version = "0.8", features = ["v4"]}
diff --git a/components/devtools/actors/browsing_context.rs b/components/devtools/actors/browsing_context.rs
index bdc468f9f84..b90d84d04bd 100644
--- a/components/devtools/actors/browsing_context.rs
+++ b/components/devtools/actors/browsing_context.rs
@@ -8,10 +8,22 @@
//! Supports dynamic attaching and detaching which control notifications of navigation, etc.
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
-use crate::actors::console::ConsoleActor;
+use crate::actors::emulation::EmulationActor;
+use crate::actors::inspector::InspectorActor;
+use crate::actors::performance::PerformanceActor;
+use crate::actors::profiler::ProfilerActor;
+use crate::actors::root::RootActor;
+use crate::actors::stylesheets::StyleSheetsActor;
+use crate::actors::thread::ThreadActor;
+use crate::actors::timeline::TimelineActor;
use crate::protocol::JsonPacketStream;
use devtools_traits::DevtoolScriptControlMsg::{self, WantsLiveNotifications};
+use devtools_traits::DevtoolsPageInfo;
+use devtools_traits::NavigationState;
+use ipc_channel::ipc::IpcSender;
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use serde_json::{Map, Value};
+use std::cell::{Cell, RefCell};
use std::net::TcpStream;
#[derive(Serialize)]
@@ -108,8 +120,8 @@ pub struct BrowsingContextActorMsg {
pub struct BrowsingContextActor {
pub name: String,
- pub title: String,
- pub url: String,
+ pub title: RefCell<String>,
+ pub url: RefCell<String>,
pub console: String,
pub emulation: String,
pub inspector: String,
@@ -118,6 +130,10 @@ pub struct BrowsingContextActor {
pub performance: String,
pub styleSheets: String,
pub thread: String,
+ pub streams: RefCell<Vec<TcpStream>>,
+ pub browsing_context_id: BrowsingContextId,
+ pub active_pipeline: Cell<PipelineId>,
+ pub script_chan: IpcSender<DevtoolScriptControlMsg>,
}
impl Actor for BrowsingContextActor {
@@ -127,7 +143,7 @@ impl Actor for BrowsingContextActor {
fn handle_message(
&self,
- registry: &ActorRegistry,
+ _registry: &ActorRegistry,
msg_type: &str,
msg: &Map<String, Value>,
stream: &mut TcpStream,
@@ -137,10 +153,9 @@ impl Actor for BrowsingContextActor {
if let Some(options) = msg.get("options").and_then(|o| o.as_object()) {
if let Some(val) = options.get("performReload") {
if val.as_bool().unwrap_or(false) {
- let console_actor = registry.find::<ConsoleActor>(&self.console);
- let _ = console_actor
+ let _ = self
.script_chan
- .send(DevtoolScriptControlMsg::Reload(console_actor.pipeline));
+ .send(DevtoolScriptControlMsg::Reload(self.active_pipeline.get()));
}
}
}
@@ -159,38 +174,31 @@ impl Actor for BrowsingContextActor {
javascriptEnabled: true,
traits: AttachedTraits {
reconfigure: false,
- frames: false,
+ frames: true,
logInPage: false,
canRewind: false,
watchpoints: false,
},
};
- let console_actor = registry.find::<ConsoleActor>(&self.console);
- console_actor
- .streams
- .borrow_mut()
- .push(stream.try_clone().unwrap());
+ self.streams.borrow_mut().push(stream.try_clone().unwrap());
stream.write_json_packet(&msg);
- console_actor
- .script_chan
- .send(WantsLiveNotifications(console_actor.pipeline, true))
+ self.script_chan
+ .send(WantsLiveNotifications(self.active_pipeline.get(), true))
.unwrap();
ActorMessageStatus::Processed
},
- //FIXME: The current implementation won't work for multiple connections. Need to ensure 105
+ //FIXME: The current implementation won't work for multiple connections. Need to ensure
// that the correct stream is removed.
"detach" => {
let msg = BrowsingContextDetachedReply {
from: self.name(),
type_: "detached".to_owned(),
};
- let console_actor = registry.find::<ConsoleActor>(&self.console);
- console_actor.streams.borrow_mut().pop();
+ self.streams.borrow_mut().pop();
stream.write_json_packet(&msg);
- console_actor
- .script_chan
- .send(WantsLiveNotifications(console_actor.pipeline, false))
+ self.script_chan
+ .send(WantsLiveNotifications(self.active_pipeline.get(), false))
.unwrap();
ActorMessageStatus::Processed
},
@@ -199,10 +207,11 @@ impl Actor for BrowsingContextActor {
let msg = ListFramesReply {
from: self.name(),
frames: vec![FrameMsg {
- id: 0, //FIXME should match outerwindow id
+ //FIXME: shouldn't ignore pipeline namespace field
+ id: self.active_pipeline.get().index.0.get(),
parentID: 0,
- url: self.url.clone(),
- title: self.title.clone(),
+ url: self.url.borrow().clone(),
+ title: self.title.borrow().clone(),
}],
};
stream.write_json_packet(&msg);
@@ -224,16 +233,82 @@ impl Actor for BrowsingContextActor {
}
impl BrowsingContextActor {
+ pub(crate) fn new(
+ console: String,
+ id: BrowsingContextId,
+ page_info: DevtoolsPageInfo,
+ pipeline: PipelineId,
+ script_sender: IpcSender<DevtoolScriptControlMsg>,
+ actors: &mut ActorRegistry,
+ ) -> BrowsingContextActor {
+ let emulation = EmulationActor::new(actors.new_name("emulation"));
+
+ let name = actors.new_name("target");
+
+ let inspector = InspectorActor {
+ name: actors.new_name("inspector"),
+ walker: RefCell::new(None),
+ pageStyle: RefCell::new(None),
+ highlighter: RefCell::new(None),
+ script_chan: script_sender.clone(),
+ browsing_context: name.clone(),
+ };
+
+ let timeline =
+ TimelineActor::new(actors.new_name("timeline"), pipeline, script_sender.clone());
+
+ let profiler = ProfilerActor::new(actors.new_name("profiler"));
+ let performance = PerformanceActor::new(actors.new_name("performance"));
+
+ // the strange switch between styleSheets and stylesheets is due
+ // to an inconsistency in devtools. See Bug #1498893 in bugzilla
+ let styleSheets = StyleSheetsActor::new(actors.new_name("stylesheets"));
+ let thread = ThreadActor::new(actors.new_name("context"));
+
+ let DevtoolsPageInfo { title, url } = page_info;
+ let target = BrowsingContextActor {
+ name: name,
+ script_chan: script_sender,
+ title: RefCell::new(String::from(title)),
+ url: RefCell::new(url.into_string()),
+ console: console,
+ emulation: emulation.name(),
+ inspector: inspector.name(),
+ timeline: timeline.name(),
+ profiler: profiler.name(),
+ performance: performance.name(),
+ styleSheets: styleSheets.name(),
+ thread: thread.name(),
+ streams: RefCell::new(Vec::new()),
+ browsing_context_id: id,
+ active_pipeline: Cell::new(pipeline),
+ };
+
+ actors.register(Box::new(emulation));
+ actors.register(Box::new(inspector));
+ actors.register(Box::new(timeline));
+ actors.register(Box::new(profiler));
+ actors.register(Box::new(performance));
+ actors.register(Box::new(styleSheets));
+ actors.register(Box::new(thread));
+
+ let root = actors.find_mut::<RootActor>("root");
+ root.tabs.push(target.name.clone());
+ target
+ }
+
pub fn encodable(&self) -> BrowsingContextActorMsg {
BrowsingContextActorMsg {
actor: self.name(),
traits: BrowsingContextTraits {
isBrowsingContext: true,
},
- title: self.title.clone(),
- url: self.url.clone(),
- browsingContextId: 0, //FIXME should come from constellation
- outerWindowID: 0, //FIXME: this should probably be the pipeline id
+ title: self.title.borrow().clone(),
+ url: self.url.borrow().clone(),
+ //FIXME: shouldn't ignore pipeline namespace field
+ browsingContextId: self.browsing_context_id.index.0.get(),
+ //FIXME: shouldn't ignore pipeline namespace field
+ outerWindowID: self.active_pipeline.get().index.0.get(),
consoleActor: self.console.clone(),
emulationActor: self.emulation.clone(),
inspectorActor: self.inspector.clone(),
@@ -243,4 +318,52 @@ impl BrowsingContextActor {
styleSheetsActor: self.styleSheets.clone(),
}
}
+
+ pub(crate) fn navigate(&self, state: NavigationState) {
+ let (pipeline, title, url, state) = match state {
+ NavigationState::Start(url) => (None, None, url, "start"),
+ NavigationState::Stop(pipeline, info) => {
+ (Some(pipeline), Some(info.title), info.url, "stop")
+ },
+ };
+ if let Some(p) = pipeline {
+ self.active_pipeline.set(p);
+ }
+ *self.url.borrow_mut() = url.as_str().to_owned();
+ if let Some(ref t) = title {
+ *self.title.borrow_mut() = t.clone();
+ }
+
+ let msg = TabNavigated {
+ from: self.name(),
+ type_: "tabNavigated".to_owned(),
+ url: url.as_str().to_owned(),
+ title: title,
+ nativeConsoleAPI: true,
+ state: state.to_owned(),
+ isFrameSwitching: false,
+ };
+ for stream in &mut *self.streams.borrow_mut() {
+ stream.write_json_packet(&msg);
+ }
+ }
+
+ pub(crate) fn title_changed(&self, pipeline: PipelineId, title: String) {
+ if pipeline != self.active_pipeline.get() {
+ return;
+ }
+ *self.title.borrow_mut() = title;
+ }
+}
+
+#[derive(Serialize)]
+struct TabNavigated {
+ from: String,
+ #[serde(rename = "type")]
+ type_: String,
+ url: String,
+ title: Option<String>,
+ nativeConsoleAPI: bool,
+ state: String,
+ isFrameSwitching: bool,
}
diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs
index 845e39075b1..2a8b016b93d 100644
--- a/components/devtools/actors/console.rs
+++ b/components/devtools/actors/console.rs
@@ -8,19 +8,23 @@
//! inspection, JS evaluation, autocompletion) in Servo.
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
+use crate::actors::browsing_context::BrowsingContextActor;
use crate::actors::object::ObjectActor;
+use crate::actors::worker::WorkerActor;
use crate::protocol::JsonPacketStream;
-use crate::{ConsoleAPICall, ConsoleMessage, ConsoleMsg, PageErrorMsg};
+use crate::UniqueId;
use devtools_traits::CachedConsoleMessage;
+use devtools_traits::ConsoleMessage;
use devtools_traits::EvaluateJSReply::{ActorValue, BooleanValue, StringValue};
use devtools_traits::EvaluateJSReply::{NullValue, NumberValue, VoidValue};
use devtools_traits::{
CachedConsoleMessageTypes, ConsoleAPI, DevtoolScriptControlMsg, LogLevel, PageError,
};
use ipc_channel::ipc::{self, IpcSender};
-use msg::constellation_msg::PipelineId;
+use msg::constellation_msg::TEST_PIPELINE_ID;
use serde_json::{self, Map, Number, Value};
-use std::cell::RefCell;
+use std::cell::{RefCell, RefMut};
+use std::collections::HashMap;
use std::net::TcpStream;
use time::precise_time_ns;
use uuid::Uuid;
@@ -104,15 +108,52 @@ struct SetPreferencesReply {
updated: Vec<String>,
}
-pub struct ConsoleActor {
+pub(crate) enum Root {
+ BrowsingContext(String),
+ DedicatedWorker(String),
+}
+
+pub(crate) struct ConsoleActor {
pub name: String,
- pub pipeline: PipelineId,
- pub script_chan: IpcSender<DevtoolScriptControlMsg>,
- pub streams: RefCell<Vec<TcpStream>>,
- pub cached_events: RefCell<Vec<CachedConsoleMessage>>,
+ pub root: Root,
+ pub cached_events: RefCell<HashMap<UniqueId, Vec<CachedConsoleMessage>>>,
}
impl ConsoleActor {
+ fn script_chan<'a>(
+ &self,
+ registry: &'a ActorRegistry,
+ ) -> &'a IpcSender<DevtoolScriptControlMsg> {
+ match &self.root {
+ Root::BrowsingContext(bc) => &registry.find::<BrowsingContextActor>(bc).script_chan,
+ Root::DedicatedWorker(worker) => &registry.find::<WorkerActor>(worker).script_chan,
+ }
+ }
+
+ fn streams_mut<'a>(&self, registry: &'a ActorRegistry) -> RefMut<'a, Vec<TcpStream>> {
+ match &self.root {
+ Root::BrowsingContext(bc) => registry
+ .find::<BrowsingContextActor>(bc)
+ .streams
+ .borrow_mut(),
+ Root::DedicatedWorker(worker) => {
+ registry.find::<WorkerActor>(worker).streams.borrow_mut()
+ },
+ }
+ }
+
+ fn current_unique_id(&self, registry: &ActorRegistry) -> UniqueId {
+ match &self.root {
+ Root::BrowsingContext(bc) => UniqueId::Pipeline(
+ registry
+ .find::<BrowsingContextActor>(bc)
+ .active_pipeline
+ .get(),
+ ),
+ Root::DedicatedWorker(w) => UniqueId::Worker(registry.find::<WorkerActor>(w).id),
+ }
+ }
+
fn evaluateJS(
&self,
registry: &ActorRegistry,
@@ -120,9 +161,15 @@ impl ConsoleActor {
) -> Result<EvaluateJSReply, ()> {
let input = msg.get("text").unwrap().as_str().unwrap().to_owned();
let (chan, port) = ipc::channel().unwrap();
- self.script_chan
+ // FIXME: redesign messages so we don't have to fake pipeline ids when
+ // communicating with workers.
+ let pipeline = match self.current_unique_id(registry) {
+ UniqueId::Pipeline(p) => p,
+ UniqueId::Worker(_) => TEST_PIPELINE_ID,
+ };
+ self.script_chan(registry)
.send(DevtoolScriptControlMsg::EvaluateJS(
- self.pipeline,
+ pipeline,
input.clone(),
chan,
))
@@ -191,21 +238,35 @@ impl ConsoleActor {
std::result::Result::Ok(reply)
}
- pub(crate) fn handle_page_error(&self, page_error: PageError) {
+ pub(crate) fn handle_page_error(
+ &self,
+ page_error: PageError,
+ id: UniqueId,
+ registry: &ActorRegistry,
+ ) {
self.cached_events
.borrow_mut()
+ .entry(id.clone())
+ .or_insert(vec![])
.push(CachedConsoleMessage::PageError(page_error.clone()));
- let msg = PageErrorMsg {
- from: self.name(),
- type_: "pageError".to_owned(),
- pageError: page_error,
- };
- for stream in &mut *self.streams.borrow_mut() {
- stream.write_json_packet(&msg);
+ if id == self.current_unique_id(registry) {
+ let msg = PageErrorMsg {
+ from: self.name(),
+ type_: "pageError".to_owned(),
+ pageError: page_error,
+ };
+ for stream in &mut *self.streams_mut(registry) {
+ stream.write_json_packet(&msg);
+ }
}
}
- pub(crate) fn handle_console_api(&self, console_message: ConsoleMessage) {
+ pub(crate) fn handle_console_api(
+ &self,
+ console_message: ConsoleMessage,
+ id: UniqueId,
+ registry: &ActorRegistry,
+ ) {
let level = match console_message.logLevel {
LogLevel::Debug => "debug",
LogLevel::Info => "info",
@@ -216,6 +277,8 @@ impl ConsoleActor {
.to_owned();
self.cached_events
.borrow_mut()
+ .entry(id.clone())
+ .or_insert(vec![])
.push(CachedConsoleMessage::ConsoleAPI(ConsoleAPI {
type_: "ConsoleAPI".to_owned(),
level: level.clone(),
@@ -226,20 +289,22 @@ impl ConsoleActor {
private: false,
arguments: vec![console_message.message.clone()],
}));
- let msg = ConsoleAPICall {
- from: self.name(),
- type_: "consoleAPICall".to_owned(),
- message: ConsoleMsg {
- level: level,
- timeStamp: precise_time_ns(),
- arguments: vec![console_message.message],
- filename: console_message.filename,
- lineNumber: console_message.lineNumber,
- columnNumber: console_message.columnNumber,
- },
- };
- for stream in &mut *self.streams.borrow_mut() {
- stream.write_json_packet(&msg);
+ if id == self.current_unique_id(registry) {
+ let msg = ConsoleAPICall {
+ from: self.name(),
+ type_: "consoleAPICall".to_owned(),
+ message: ConsoleMsg {
+ level: level,
+ timeStamp: precise_time_ns(),
+ arguments: vec![console_message.message],
+ filename: console_message.filename,
+ lineNumber: console_message.lineNumber,
+ columnNumber: console_message.columnNumber,
+ },
+ };
+ for stream in &mut *self.streams_mut(registry) {
+ stream.write_json_packet(&msg);
+ }
}
}
}
@@ -257,6 +322,13 @@ impl Actor for ConsoleActor {
stream: &mut TcpStream,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
+ "clearMessagesCache" => {
+ self.cached_events
+ .borrow_mut()
+ .remove(&self.current_unique_id(registry));
+ ActorMessageStatus::Processed
+ },
+
"getCachedMessages" => {
let str_types = msg
.get("messageTypes")
@@ -276,7 +348,13 @@ impl Actor for ConsoleActor {
};
}
let mut messages = vec![];
- for event in self.cached_events.borrow().iter() {
+ for event in self
+ .cached_events
+ .borrow()
+ .get(&self.current_unique_id(registry))
+ .unwrap_or(&vec![])
+ .iter()
+ {
let include = match event {
CachedConsoleMessage::PageError(_)
if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) =>
@@ -365,6 +443,13 @@ impl Actor for ConsoleActor {
// Emit an eager reply so that the client starts listening
// for an async event with the resultID
stream.write_json_packet(&early_reply);
+
+ if msg.get("eager").and_then(|v| v.as_bool()).unwrap_or(false) {
+ // We don't support the side-effect free evaluation that eager evalaution
+ // really needs.
+ return Ok(ActorMessageStatus::Processed);
+ }
+
let reply = self.evaluateJS(&registry, &msg).unwrap();
let msg = EvaluateJSEvent {
from: self.name(),
@@ -395,3 +480,29 @@ impl Actor for ConsoleActor {
})
}
}
+
+#[derive(Serialize)]
+struct ConsoleAPICall {
+ from: String,
+ #[serde(rename = "type")]
+ type_: String,
+ message: ConsoleMsg,
+}
+
+#[derive(Serialize)]
+struct ConsoleMsg {
+ level: String,
+ timeStamp: u64,
+ arguments: Vec<String>,
+ filename: String,
+ lineNumber: usize,
+ columnNumber: usize,
+}
+
+#[derive(Serialize)]
+struct PageErrorMsg {
+ from: String,
+ #[serde(rename = "type")]
+ type_: String,
+ pageError: PageError,
+}
diff --git a/components/devtools/actors/inspector.rs b/components/devtools/actors/inspector.rs
index cd3e5bf323c..d2f0929ac89 100644
--- a/components/devtools/actors/inspector.rs
+++ b/components/devtools/actors/inspector.rs
@@ -6,6 +6,7 @@
//! (http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/inspector.js).
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
+use crate::actors::browsing_context::BrowsingContextActor;
use crate::protocol::JsonPacketStream;
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement, GetRootNode};
use devtools_traits::DevtoolScriptControlMsg::{GetLayout, ModifyAttribute};
@@ -22,7 +23,7 @@ pub struct InspectorActor {
pub pageStyle: RefCell<Option<String>>,
pub highlighter: RefCell<Option<String>>,
pub script_chan: IpcSender<DevtoolScriptControlMsg>,
- pub pipeline: PipelineId,
+ pub browsing_context: String,
}
#[derive(Serialize)]
@@ -596,13 +597,15 @@ impl Actor for InspectorActor {
_msg: &Map<String, Value>,
stream: &mut TcpStream,
) -> Result<ActorMessageStatus, ()> {
+ let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context);
+ let pipeline = browsing_context.active_pipeline.get();
Ok(match msg_type {
"getWalker" => {
if self.walker.borrow().is_none() {
let walker = WalkerActor {
name: registry.new_name("walker"),
script_chan: self.script_chan.clone(),
- pipeline: self.pipeline,
+ pipeline: pipeline,
};
let mut walker_name = self.walker.borrow_mut();
*walker_name = Some(walker.name());
@@ -610,13 +613,10 @@ impl Actor for InspectorActor {
}
let (tx, rx) = ipc::channel().unwrap();
- self.script_chan
- .send(GetRootNode(self.pipeline, tx))
- .unwrap();
+ self.script_chan.send(GetRootNode(pipeline, tx)).unwrap();
let root_info = rx.recv().unwrap().ok_or(())?;
- let node =
- root_info.encode(registry, false, self.script_chan.clone(), self.pipeline);
+ let node = root_info.encode(registry, false, self.script_chan.clone(), pipeline);
let msg = GetWalkerReply {
from: self.name(),
@@ -634,7 +634,7 @@ impl Actor for InspectorActor {
let style = PageStyleActor {
name: registry.new_name("pageStyle"),
script_chan: self.script_chan.clone(),
- pipeline: self.pipeline,
+ pipeline: pipeline,
};
let mut pageStyle = self.pageStyle.borrow_mut();
*pageStyle = Some(style.name());
diff --git a/components/devtools/actors/root.rs b/components/devtools/actors/root.rs
index da7483ffb34..0010afd3b9f 100644
--- a/components/devtools/actors/root.rs
+++ b/components/devtools/actors/root.rs
@@ -10,6 +10,7 @@ use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg};
use crate::actors::device::DeviceActor;
use crate::actors::performance::PerformanceActor;
+use crate::actors::worker::{WorkerActor, WorkerMsg};
use crate::protocol::{ActorDescription, JsonPacketStream};
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -73,11 +74,6 @@ struct ListWorkersReply {
}
#[derive(Serialize)]
-struct WorkerMsg {
- id: u32,
-}
-
-#[derive(Serialize)]
struct ListServiceWorkerRegistrationsReply {
from: String,
registrations: Vec<u32>, // TODO: follow actual JSON structure.
@@ -110,6 +106,7 @@ struct GetProcessResponse {
pub struct RootActor {
pub tabs: Vec<String>,
+ pub workers: Vec<String>,
pub performance: String,
pub device: String,
pub preference: String,
@@ -203,7 +200,11 @@ impl Actor for RootActor {
"listWorkers" => {
let reply = ListWorkersReply {
from: self.name(),
- workers: vec![],
+ workers: self
+ .workers
+ .iter()
+ .map(|name| registry.find::<WorkerActor>(name).encodable())
+ .collect(),
};
stream.write_json_packet(&reply);
ActorMessageStatus::Processed
diff --git a/components/devtools/actors/worker.rs b/components/devtools/actors/worker.rs
index 082d719de20..fd578d0d3dc 100644
--- a/components/devtools/actors/worker.rs
+++ b/components/devtools/actors/worker.rs
@@ -3,14 +3,49 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
-use devtools_traits::WorkerId;
+use crate::protocol::JsonPacketStream;
+use devtools_traits::DevtoolScriptControlMsg::WantsLiveNotifications;
+use devtools_traits::{DevtoolScriptControlMsg, WorkerId};
+use ipc_channel::ipc::IpcSender;
+use msg::constellation_msg::TEST_PIPELINE_ID;
use serde_json::{Map, Value};
+use servo_url::ServoUrl;
+use std::cell::RefCell;
use std::net::TcpStream;
+#[derive(Clone, Copy)]
+#[allow(dead_code)]
+pub enum WorkerType {
+ Dedicated = 0,
+ Shared = 1,
+ Service = 2,
+}
+
pub struct WorkerActor {
pub name: String,
pub console: String,
+ pub thread: String,
pub id: WorkerId,
+ pub url: ServoUrl,
+ pub type_: WorkerType,
+ pub script_chan: IpcSender<DevtoolScriptControlMsg>,
+ pub streams: RefCell<Vec<TcpStream>>,
+}
+
+impl WorkerActor {
+ pub(crate) fn encodable(&self) -> WorkerMsg {
+ WorkerMsg {
+ actor: self.name.clone(),
+ consoleActor: self.console.clone(),
+ threadActor: self.thread.clone(),
+ id: self.id.0.to_string(),
+ url: self.url.to_string(),
+ traits: WorkerTraits {
+ isParentInterceptEnabled: false,
+ },
+ type_: self.type_ as u32,
+ }
+ }
}
impl Actor for WorkerActor {
@@ -19,11 +54,94 @@ impl Actor for WorkerActor {
}
fn handle_message(
&self,
- _: &ActorRegistry,
- _: &str,
- _: &Map<String, Value>,
- _: &mut TcpStream,
+ _registry: &ActorRegistry,
+ msg_type: &str,
+ _msg: &Map<String, Value>,
+ stream: &mut TcpStream,
) -> Result<ActorMessageStatus, ()> {
- Ok(ActorMessageStatus::Processed)
+ Ok(match msg_type {
+ "attach" => {
+ let msg = AttachedReply {
+ from: self.name(),
+ type_: "attached".to_owned(),
+ url: self.url.as_str().to_owned(),
+ };
+ self.streams.borrow_mut().push(stream.try_clone().unwrap());
+ stream.write_json_packet(&msg);
+ // FIXME: fix messages to not require forging a pipeline for worker messages
+ self.script_chan
+ .send(WantsLiveNotifications(TEST_PIPELINE_ID, true))
+ .unwrap();
+ ActorMessageStatus::Processed
+ },
+
+ "connect" => {
+ let msg = ConnectReply {
+ from: self.name(),
+ type_: "connected".to_owned(),
+ threadActor: self.thread.clone(),
+ consoleActor: self.console.clone(),
+ };
+ stream.write_json_packet(&msg);
+ ActorMessageStatus::Processed
+ },
+
+ "detach" => {
+ let msg = DetachedReply {
+ from: self.name(),
+ type_: "detached".to_string(),
+ };
+ // FIXME: we should ensure we're removing the correct stream.
+ self.streams.borrow_mut().pop();
+ stream.write_json_packet(&msg);
+ self.script_chan
+ .send(WantsLiveNotifications(TEST_PIPELINE_ID, false))
+ .unwrap();
+ ActorMessageStatus::Processed
+ },
+
+ _ => ActorMessageStatus::Ignored,
+ })
}
}
+
+#[derive(Serialize)]
+struct DetachedReply {
+ from: String,
+ #[serde(rename = "type")]
+ type_: String,
+}
+
+#[derive(Serialize)]
+struct AttachedReply {
+ from: String,
+ #[serde(rename = "type")]
+ type_: String,
+ url: String,
+}
+
+#[derive(Serialize)]
+struct ConnectReply {
+ from: String,
+ #[serde(rename = "type")]
+ type_: String,
+ threadActor: String,
+ consoleActor: String,
+}
+
+#[derive(Serialize)]
+struct WorkerTraits {
+ isParentInterceptEnabled: bool,
+}
+
+#[derive(Serialize)]
+pub(crate) struct WorkerMsg {
+ actor: String,
+ consoleActor: String,
+ threadActor: String,
+ id: String,
+ url: String,
+ traits: WorkerTraits,
+ #[serde(rename = "type")]
+ type_: u32,
+}
diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs
index 661d6ac94e1..2227be98549 100644
--- a/components/devtools/lib.rs
+++ b/components/devtools/lib.rs
@@ -19,31 +19,27 @@ extern crate serde;
use crate::actor::{Actor, ActorRegistry};
use crate::actors::browsing_context::BrowsingContextActor;
-use crate::actors::console::ConsoleActor;
+use crate::actors::console::{ConsoleActor, Root};
use crate::actors::device::DeviceActor;
-use crate::actors::emulation::EmulationActor;
use crate::actors::framerate::FramerateActor;
-use crate::actors::inspector::InspectorActor;
use crate::actors::network_event::{EventActor, NetworkEventActor, ResponseStartMsg};
use crate::actors::performance::PerformanceActor;
use crate::actors::preference::PreferenceActor;
use crate::actors::process::ProcessActor;
-use crate::actors::profiler::ProfilerActor;
use crate::actors::root::RootActor;
-use crate::actors::stylesheets::StyleSheetsActor;
use crate::actors::thread::ThreadActor;
-use crate::actors::timeline::TimelineActor;
-use crate::actors::worker::WorkerActor;
+use crate::actors::worker::{WorkerActor, WorkerType};
use crate::protocol::JsonPacketStream;
use crossbeam_channel::{unbounded, Receiver, Sender};
use devtools_traits::{ChromeToDevtoolsControlMsg, ConsoleMessage, DevtoolsControlMsg};
-use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo, LogLevel, NetworkEvent};
+use devtools_traits::{
+ DevtoolScriptControlMsg, DevtoolsPageInfo, LogLevel, NavigationState, NetworkEvent,
+};
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::{EmbedderMsg, EmbedderProxy, PromptDefinition, PromptOrigin, PromptResult};
use ipc_channel::ipc::{self, IpcSender};
-use msg::constellation_msg::PipelineId;
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use std::borrow::ToOwned;
-use std::cell::RefCell;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;
use std::net::{Shutdown, TcpListener, TcpStream};
@@ -74,30 +70,10 @@ mod actors {
}
mod protocol;
-#[derive(Serialize)]
-struct ConsoleAPICall {
- from: String,
- #[serde(rename = "type")]
- type_: String,
- message: ConsoleMsg,
-}
-
-#[derive(Serialize)]
-struct ConsoleMsg {
- level: String,
- timeStamp: u64,
- arguments: Vec<String>,
- filename: String,
- lineNumber: usize,
- columnNumber: usize,
-}
-
-#[derive(Serialize)]
-struct PageErrorMsg {
- from: String,
- #[serde(rename = "type")]
- type_: String,
- pageError: PageError,
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+enum UniqueId {
+ Pipeline(PipelineId),
+ Worker(WorkerId),
}
#[derive(Serialize)]
@@ -181,6 +157,7 @@ fn run_server(
let root = Box::new(RootActor {
tabs: vec![],
+ workers: vec![],
device: device.name(),
performance: performance.name(),
preference: preference.name(),
@@ -198,10 +175,11 @@ fn run_server(
let mut accepted_connections: Vec<TcpStream> = Vec::new();
- let mut actor_pipelines: HashMap<PipelineId, String> = HashMap::new();
+ let mut browsing_contexts: HashMap<BrowsingContextId, String> = HashMap::new();
+ let mut pipelines: HashMap<PipelineId, BrowsingContextId> = HashMap::new();
let mut actor_requests: HashMap<String, String> = HashMap::new();
- let mut actor_workers: HashMap<(PipelineId, WorkerId), String> = HashMap::new();
+ let mut actor_workers: HashMap<WorkerId, String> = HashMap::new();
/// Process the input from a single devtools client until EOF.
fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) {
@@ -243,129 +221,139 @@ fn run_server(
framerate_actor.add_tick(tick);
}
+ fn handle_navigate(
+ actors: Arc<Mutex<ActorRegistry>>,
+ browsing_contexts: &HashMap<BrowsingContextId, String>,
+ browsing_context: BrowsingContextId,
+ state: NavigationState,
+ ) {
+ let actor_name = browsing_contexts.get(&browsing_context).unwrap();
+ actors
+ .lock()
+ .unwrap()
+ .find::<BrowsingContextActor>(actor_name)
+ .navigate(state);
+ }
+
+ fn handle_title_changed(
+ actors: Arc<Mutex<ActorRegistry>>,
+ pipelines: &HashMap<PipelineId, BrowsingContextId>,
+ browsing_contexts: &HashMap<BrowsingContextId, String>,
+ pipeline: PipelineId,
+ title: String,
+ ) {
+ let bc = match pipelines.get(&pipeline) {
+ Some(bc) => bc,
+ None => return,
+ };
+ let name = match browsing_contexts.get(&bc) {
+ Some(name) => name,
+ None => return,
+ };
+ let actors = actors.lock().unwrap();
+ let browsing_context = actors.find::<BrowsingContextActor>(name);
+ browsing_context.title_changed(pipeline, title);
+ }
+
// We need separate actor representations for each script global that exists;
// clients can theoretically connect to multiple globals simultaneously.
// TODO: move this into the root or target modules?
fn handle_new_global(
actors: Arc<Mutex<ActorRegistry>>,
- ids: (PipelineId, Option<WorkerId>),
+ ids: (BrowsingContextId, PipelineId, Option<WorkerId>),
script_sender: IpcSender<DevtoolScriptControlMsg>,
- actor_pipelines: &mut HashMap<PipelineId, String>,
- actor_workers: &mut HashMap<(PipelineId, WorkerId), String>,
+ browsing_contexts: &mut HashMap<BrowsingContextId, String>,
+ pipelines: &mut HashMap<PipelineId, BrowsingContextId>,
+ actor_workers: &mut HashMap<WorkerId, String>,
page_info: DevtoolsPageInfo,
) {
let mut actors = actors.lock().unwrap();
- let (pipeline, worker_id) = ids;
-
- //TODO: move all this actor creation into a constructor method on BrowsingContextActor
- let (
- target,
- console,
- emulation,
- inspector,
- timeline,
- profiler,
- performance,
- styleSheets,
- thread,
- ) = {
- let console = ConsoleActor {
- name: actors.new_name("console"),
- script_chan: script_sender.clone(),
- pipeline: pipeline,
- streams: RefCell::new(Vec::new()),
- cached_events: RefCell::new(Vec::new()),
- };
-
- let emulation = EmulationActor::new(actors.new_name("emulation"));
-
- let inspector = InspectorActor {
- name: actors.new_name("inspector"),
- walker: RefCell::new(None),
- pageStyle: RefCell::new(None),
- highlighter: RefCell::new(None),
- script_chan: script_sender.clone(),
- pipeline: pipeline,
- };
+ let (browsing_context, pipeline, worker_id) = ids;
- let timeline = TimelineActor::new(actors.new_name("timeline"), pipeline, script_sender);
+ let console_name = actors.new_name("console");
- let profiler = ProfilerActor::new(actors.new_name("profiler"));
- let performance = PerformanceActor::new(actors.new_name("performance"));
+ let parent_actor = if let Some(id) = worker_id {
+ assert!(pipelines.get(&pipeline).is_some());
+ assert!(browsing_contexts.get(&browsing_context).is_some());
- // the strange switch between styleSheets and stylesheets is due
- // to an inconsistency in devtools. See Bug #1498893 in bugzilla
- let styleSheets = StyleSheetsActor::new(actors.new_name("stylesheets"));
let thread = ThreadActor::new(actors.new_name("context"));
+ let thread_name = thread.name();
+ actors.register(Box::new(thread));
- let DevtoolsPageInfo { title, url } = page_info;
- let target = BrowsingContextActor {
- name: actors.new_name("target"),
- title: String::from(title),
- url: url.into_string(),
- console: console.name(),
- emulation: emulation.name(),
- inspector: inspector.name(),
- timeline: timeline.name(),
- profiler: profiler.name(),
- performance: performance.name(),
- styleSheets: styleSheets.name(),
- thread: thread.name(),
+ let worker_name = actors.new_name("worker");
+ let worker = WorkerActor {
+ name: worker_name.clone(),
+ console: console_name.clone(),
+ thread: thread_name,
+ id: id,
+ url: page_info.url.clone(),
+ type_: WorkerType::Dedicated,
+ script_chan: script_sender,
+ streams: Default::default(),
};
-
let root = actors.find_mut::<RootActor>("root");
- root.tabs.push(target.name.clone());
-
- (
- target,
- console,
- emulation,
- inspector,
- timeline,
- profiler,
- performance,
- styleSheets,
- thread,
+ root.workers.push(worker.name.clone());
+
+ actor_workers.insert(id, worker_name.clone());
+ actors.register(Box::new(worker));
+
+ Root::DedicatedWorker(worker_name)
+ } else {
+ pipelines.insert(pipeline, browsing_context);
+ Root::BrowsingContext(
+ if let Some(actor) = browsing_contexts.get(&browsing_context) {
+ actor.to_owned()
+ } else {
+ let browsing_context_actor = BrowsingContextActor::new(
+ console_name.clone(),
+ browsing_context,
+ page_info,
+ pipeline,
+ script_sender,
+ &mut *actors,
+ );
+ let name = browsing_context_actor.name();
+ browsing_contexts.insert(browsing_context, name.clone());
+ actors.register(Box::new(browsing_context_actor));
+ name
+ },
)
};
- if let Some(id) = worker_id {
- let worker = WorkerActor {
- name: actors.new_name("worker"),
- console: console.name(),
- id: id,
- };
- actor_workers.insert((pipeline, id), worker.name.clone());
- actors.register(Box::new(worker));
- }
+ let console = ConsoleActor {
+ name: console_name,
+ cached_events: Default::default(),
+ root: parent_actor,
+ };
- actor_pipelines.insert(pipeline, target.name.clone());
- actors.register(Box::new(target));
actors.register(Box::new(console));
- actors.register(Box::new(emulation));
- actors.register(Box::new(inspector));
- actors.register(Box::new(timeline));
- actors.register(Box::new(profiler));
- actors.register(Box::new(performance));
- actors.register(Box::new(styleSheets));
- actors.register(Box::new(thread));
}
fn handle_page_error(
actors: Arc<Mutex<ActorRegistry>>,
id: PipelineId,
+ worker_id: Option<WorkerId>,
page_error: PageError,
- actor_pipelines: &HashMap<PipelineId, String>,
+ browsing_contexts: &HashMap<BrowsingContextId, String>,
+ actor_workers: &HashMap<WorkerId, String>,
+ pipelines: &HashMap<PipelineId, BrowsingContextId>,
) {
- let console_actor_name =
- match find_console_actor(actors.clone(), id, None, &HashMap::new(), actor_pipelines) {
- Some(name) => name,
- None => return,
- };
+ let console_actor_name = match find_console_actor(
+ actors.clone(),
+ id,
+ worker_id,
+ actor_workers,
+ browsing_contexts,
+ pipelines,
+ ) {
+ Some(name) => name,
+ None => return,
+ };
let actors = actors.lock().unwrap();
let console_actor = actors.find::<ConsoleActor>(&console_actor_name);
- console_actor.handle_page_error(page_error);
+ let id = worker_id.map_or(UniqueId::Pipeline(id), UniqueId::Worker);
+ console_actor.handle_page_error(page_error, id, &*actors);
}
fn handle_console_message(
@@ -373,37 +361,42 @@ fn run_server(
id: PipelineId,
worker_id: Option<WorkerId>,
console_message: ConsoleMessage,
- actor_pipelines: &HashMap<PipelineId, String>,
- actor_workers: &HashMap<(PipelineId, WorkerId), String>,
+ browsing_contexts: &HashMap<BrowsingContextId, String>,
+ actor_workers: &HashMap<WorkerId, String>,
+ pipelines: &HashMap<PipelineId, BrowsingContextId>,
) {
let console_actor_name = match find_console_actor(
actors.clone(),
id,
worker_id,
actor_workers,
- actor_pipelines,
+ browsing_contexts,
+ pipelines,
) {
Some(name) => name,
None => return,
};
let actors = actors.lock().unwrap();
let console_actor = actors.find::<ConsoleActor>(&console_actor_name);
- console_actor.handle_console_api(console_message);
+ let id = worker_id.map_or(UniqueId::Pipeline(id), UniqueId::Worker);
+ console_actor.handle_console_api(console_message, id, &*actors);
}
fn find_console_actor(
actors: Arc<Mutex<ActorRegistry>>,
- id: PipelineId,
+ pipeline: PipelineId,
worker_id: Option<WorkerId>,
- actor_workers: &HashMap<(PipelineId, WorkerId), String>,
- actor_pipelines: &HashMap<PipelineId, String>,
+ actor_workers: &HashMap<WorkerId, String>,
+ browsing_contexts: &HashMap<BrowsingContextId, String>,
+ pipelines: &HashMap<PipelineId, BrowsingContextId>,
) -> Option<String> {
let actors = actors.lock().unwrap();
if let Some(worker_id) = worker_id {
- let actor_name = (*actor_workers).get(&(id, worker_id))?;
+ let actor_name = actor_workers.get(&worker_id)?;
Some(actors.find::<WorkerActor>(actor_name).console.clone())
} else {
- let actor_name = (*actor_pipelines).get(&id)?;
+ let id = pipelines.get(&pipeline)?;
+ let actor_name = browsing_contexts.get(id)?;
Some(
actors
.find::<BrowsingContextActor>(actor_name)
@@ -416,9 +409,10 @@ fn run_server(
fn handle_network_event(
actors: Arc<Mutex<ActorRegistry>>,
mut connections: Vec<TcpStream>,
- actor_pipelines: &HashMap<PipelineId, String>,
+ browsing_contexts: &HashMap<BrowsingContextId, String>,
actor_requests: &mut HashMap<String, String>,
- actor_workers: &HashMap<(PipelineId, WorkerId), String>,
+ actor_workers: &HashMap<WorkerId, String>,
+ pipelines: &HashMap<PipelineId, BrowsingContextId>,
pipeline_id: PipelineId,
request_id: String,
network_event: NetworkEvent,
@@ -428,7 +422,8 @@ fn run_server(
pipeline_id,
None,
actor_workers,
- actor_pipelines,
+ browsing_contexts,
+ pipelines,
) {
Some(name) => name,
None => return,
@@ -589,6 +584,7 @@ fn run_server(
.expect("Thread spawning failed");
while let Ok(msg) = receiver.recv() {
+ debug!("{:?}", msg);
match msg {
DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::AddClient(stream)) => {
let actors = actors.clone();
@@ -602,6 +598,16 @@ fn run_server(
actor_name,
tick,
)) => handle_framerate_tick(actors.clone(), actor_name, tick),
+ DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::TitleChanged(
+ pipeline,
+ title,
+ )) => handle_title_changed(
+ actors.clone(),
+ &pipelines,
+ &browsing_contexts,
+ pipeline,
+ title,
+ ),
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::NewGlobal(
ids,
script_sender,
@@ -610,10 +616,15 @@ fn run_server(
actors.clone(),
ids,
script_sender,
- &mut actor_pipelines,
+ &mut browsing_contexts,
+ &mut pipelines,
&mut actor_workers,
pageinfo,
),
+ DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::Navigate(
+ browsing_context,
+ state,
+ )) => handle_navigate(actors.clone(), &browsing_contexts, browsing_context, state),
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ConsoleAPI(
id,
console_message,
@@ -623,13 +634,22 @@ fn run_server(
id,
worker_id,
console_message,
- &actor_pipelines,
+ &browsing_contexts,
&actor_workers,
+ &pipelines,
),
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportPageError(
id,
page_error,
- )) => handle_page_error(actors.clone(), id, page_error, &actor_pipelines),
+ )) => handle_page_error(
+ actors.clone(),
+ id,
+ None,
+ page_error,
+ &browsing_contexts,
+ &actor_workers,
+ &pipelines,
+ ),
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportCSSError(
id,
css_error,
@@ -646,8 +666,9 @@ fn run_server(
id,
None,
console_message,
- &actor_pipelines,
+ &browsing_contexts,
&actor_workers,
+ &pipelines,
)
},
DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::NetworkEvent(
@@ -667,9 +688,10 @@ fn run_server(
handle_network_event(
actors.clone(),
connections,
- &actor_pipelines,
+ &browsing_contexts,
&mut actor_requests,
&actor_workers,
+ &pipelines,
pipeline_id,
request_id,
network_event,
diff --git a/components/devtools_traits/lib.rs b/components/devtools_traits/lib.rs
index 5396d64fade..7196c3a5b32 100644
--- a/components/devtools_traits/lib.rs
+++ b/components/devtools_traits/lib.rs
@@ -21,7 +21,7 @@ extern crate serde;
use http::method::Method;
use http::HeaderMap;
use ipc_channel::ipc::IpcSender;
-use msg::constellation_msg::PipelineId;
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use servo_url::ServoUrl;
use std::net::TcpStream;
use time::{self, Duration, Tm};
@@ -29,7 +29,7 @@ use uuid::Uuid;
// Information would be attached to NewGlobal to be received and show in devtools.
// Extend these fields if we need more information.
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DevtoolsPageInfo {
pub title: String,
pub url: ServoUrl,
@@ -65,16 +65,27 @@ pub enum ChromeToDevtoolsControlMsg {
NetworkEvent(String, NetworkEvent),
}
+/// The state of a page navigation.
+#[derive(Debug, Deserialize, Serialize)]
+pub enum NavigationState {
+ /// A browsing context is about to navigate to a given URL.
+ Start(ServoUrl),
+ /// A browsing context has completed navigating to the provided pipeline.
+ Stop(PipelineId, DevtoolsPageInfo),
+}
+
#[derive(Debug, Deserialize, Serialize)]
/// Events that the devtools server must act upon.
pub enum ScriptToDevtoolsControlMsg {
/// A new global object was created, associated with a particular pipeline.
/// The means of communicating directly with it are provided.
NewGlobal(
- (PipelineId, Option<WorkerId>),
+ (BrowsingContextId, PipelineId, Option<WorkerId>),
IpcSender<DevtoolScriptControlMsg>,
DevtoolsPageInfo,
),
+ /// The given browsing context is performing a navigation.
+ Navigate(BrowsingContextId, NavigationState),
/// A particular page has invoked the console API.
ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
/// An animation frame with the given timestamp was processed in a script thread.
@@ -86,6 +97,9 @@ pub enum ScriptToDevtoolsControlMsg {
/// Report a page error for the given pipeline
ReportPageError(PipelineId, PageError),
+
+ /// Report a page title change
+ TitleChanged(PipelineId, String),
}
/// Serialized JS return values
diff --git a/components/layout/animation.rs b/components/layout/animation.rs
index 9dc59da1937..79a90f397a7 100644
--- a/components/layout/animation.rs
+++ b/components/layout/animation.rs
@@ -8,157 +8,183 @@ use crate::context::LayoutContext;
use crate::display_list::items::OpaqueNode;
use crate::flow::{Flow, GetBaseFlow};
use crate::opaque_node::OpaqueNodeMethods;
-use crossbeam_channel::Receiver;
use fxhash::{FxHashMap, FxHashSet};
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use script_traits::UntrustedNodeAddress;
-use script_traits::{AnimationState, ConstellationControlMsg, LayoutMsg as ConstellationMsg};
-use style::animation::{update_style_for_animation, Animation};
+use script_traits::{
+ AnimationState, ConstellationControlMsg, LayoutMsg as ConstellationMsg, TransitionEventType,
+};
+use servo_arc::Arc;
+use style::animation::{
+ update_style_for_animation, Animation, ElementAnimationState, PropertyAnimation,
+};
use style::dom::TElement;
use style::font_metrics::ServoMetricsProvider;
use style::selector_parser::RestyleDamage;
use style::timer::Timer;
-/// Processes any new animations that were discovered after style recalculation.
-/// Also expire any old animations that have completed, inserting them into
-/// `expired_animations`.
-pub fn update_animation_state<E>(
+/// Collect newly transitioning nodes, which is used by the script process during
+/// forced, synchronous reflows to root DOM nodes for the duration of their transitions.
+pub fn collect_newly_transitioning_nodes(
+ animation_states: &FxHashMap<OpaqueNode, ElementAnimationState>,
+ mut out: Option<&mut Vec<UntrustedNodeAddress>>,
+) {
+ // This extends the output vector with an iterator that contains a copy of the node
+ // address for every new animation. This is a bit goofy, but the script thread
+ // currently stores a rooted node for every property that is transitioning.
+ if let Some(ref mut out) = out {
+ out.extend(animation_states.iter().flat_map(|(node, state)| {
+ let num_transitions = state
+ .new_animations
+ .iter()
+ .filter(|animation| animation.is_transition())
+ .count();
+ std::iter::repeat(node.to_untrusted_node_address()).take(num_transitions)
+ }));
+ }
+}
+
+/// Processes any new animations that were discovered after style recalculation. Also
+/// finish any animations that have completed, inserting them into `finished_animations`.
+pub fn update_animation_states(
constellation_chan: &IpcSender<ConstellationMsg>,
script_chan: &IpcSender<ConstellationControlMsg>,
- running_animations: &mut FxHashMap<OpaqueNode, Vec<Animation>>,
- expired_animations: &mut FxHashMap<OpaqueNode, Vec<Animation>>,
- mut keys_to_remove: FxHashSet<OpaqueNode>,
- mut newly_transitioning_nodes: Option<&mut Vec<UntrustedNodeAddress>>,
- new_animations_receiver: &Receiver<Animation>,
+ animation_states: &mut FxHashMap<OpaqueNode, ElementAnimationState>,
+ invalid_nodes: FxHashSet<OpaqueNode>,
pipeline_id: PipelineId,
timer: &Timer,
-) where
- E: TElement,
-{
- let mut new_running_animations = vec![];
- while let Ok(animation) = new_animations_receiver.try_recv() {
- let mut should_push = true;
- if let Animation::Keyframes(ref node, _, ref name, ref state) = animation {
- // If the animation was already present in the list for the
- // node, just update its state, else push the new animation to
- // run.
- if let Some(ref mut animations) = running_animations.get_mut(node) {
- // TODO: This being linear is probably not optimal.
- for anim in animations.iter_mut() {
- if let Animation::Keyframes(_, _, ref anim_name, ref mut anim_state) = *anim {
- if *name == *anim_name {
- debug!("update_animation_state: Found other animation {}", name);
- anim_state.update_from_other(&state, timer);
- should_push = false;
- break;
- }
- }
- }
- }
- }
-
- if should_push {
- new_running_animations.push(animation);
+) {
+ let had_running_animations = animation_states
+ .values()
+ .any(|state| !state.running_animations.is_empty());
+
+ // Cancel all animations on any invalid nodes. These entries will later
+ // be removed from the list of states, because their states will become
+ // empty.
+ for node in &invalid_nodes {
+ if let Some(mut state) = animation_states.remove(node) {
+ state.cancel_all_animations();
}
}
- if running_animations.is_empty() && new_running_animations.is_empty() {
- // Nothing to do. Return early so we don't flood the compositor with
- // `ChangeRunningAnimationsState` messages.
- return;
+ let now = timer.seconds();
+ let mut have_running_animations = false;
+ for (node, animation_state) in animation_states.iter_mut() {
+ update_animation_state(script_chan, animation_state, pipeline_id, now, *node);
+ have_running_animations =
+ have_running_animations || !animation_state.running_animations.is_empty();
}
- let now = timer.seconds();
- // Expire old running animations.
- //
- // TODO: Do not expunge Keyframes animations, since we need that state if
- // the animation gets re-triggered. Probably worth splitting in two
- // different maps, or at least using a linked list?
- for (key, running_animations) in running_animations.iter_mut() {
- let mut animations_still_running = vec![];
- for mut running_animation in running_animations.drain(..) {
- let still_running = !running_animation.is_expired() &&
- match running_animation {
- Animation::Transition(_, started_at, ref property_animation) => {
- now < started_at + (property_animation.duration)
- },
- Animation::Keyframes(_, _, _, ref mut state) => {
- // This animation is still running, or we need to keep
- // iterating.
- now < state.started_at + state.duration || state.tick()
- },
- };
-
- debug!(
- "update_animation_state({:?}): {:?}",
- still_running, running_animation
- );
+ // Remove empty states from our collection of states in order to free
+ // up space as soon as we are no longer tracking any animations for
+ // a node.
+ animation_states.retain(|_, state| !state.is_empty());
- if still_running {
- animations_still_running.push(running_animation);
- continue;
- }
+ let present = match (had_running_animations, have_running_animations) {
+ (true, false) => AnimationState::NoAnimationsPresent,
+ (false, true) => AnimationState::AnimationsPresent,
+ _ => return,
+ };
+ constellation_chan
+ .send(ConstellationMsg::ChangeRunningAnimationsState(
+ pipeline_id,
+ present,
+ ))
+ .unwrap();
+}
- if let Animation::Transition(node, _, ref property_animation) = running_animation {
- script_chan
- .send(ConstellationControlMsg::TransitionEnd(
- node.to_untrusted_node_address(),
- property_animation.property_name().into(),
- property_animation.duration,
- ))
- .unwrap();
- }
+pub fn update_animation_state(
+ script_channel: &IpcSender<ConstellationControlMsg>,
+ animation_state: &mut ElementAnimationState,
+ pipeline_id: PipelineId,
+ now: f64,
+ node: OpaqueNode,
+) {
+ let send_transition_event = |property_animation: &PropertyAnimation, event_type| {
+ script_channel
+ .send(ConstellationControlMsg::TransitionEvent {
+ pipeline_id,
+ event_type,
+ node: node.to_untrusted_node_address(),
+ property_name: property_animation.property_name().into(),
+ elapsed_time: property_animation.duration,
+ })
+ .unwrap()
+ };
- debug!("expiring animation for {:?}", running_animation);
- expired_animations
- .entry(*key)
- .or_insert_with(Vec::new)
- .push(running_animation);
- }
+ handle_cancelled_animations(animation_state, send_transition_event);
+ handle_running_animations(animation_state, now, send_transition_event);
+ handle_new_animations(animation_state, send_transition_event);
+}
+
+/// Walk through the list of running animations and remove all of the ones that
+/// have ended.
+pub fn handle_running_animations(
+ animation_state: &mut ElementAnimationState,
+ now: f64,
+ mut send_transition_event: impl FnMut(&PropertyAnimation, TransitionEventType),
+) {
+ let mut running_animations =
+ std::mem::replace(&mut animation_state.running_animations, Vec::new());
+ for mut running_animation in running_animations.drain(..) {
+ let still_running = !running_animation.is_expired() &&
+ match running_animation {
+ Animation::Transition(_, started_at, ref property_animation) => {
+ now < started_at + (property_animation.duration)
+ },
+ Animation::Keyframes(_, _, _, ref mut state) => {
+ // This animation is still running, or we need to keep
+ // iterating.
+ now < state.started_at + state.duration || state.tick()
+ },
+ };
- if animations_still_running.is_empty() {
- keys_to_remove.insert(*key);
+ // If the animation is still running, add it back to the list of running animations.
+ if still_running {
+ animation_state.running_animations.push(running_animation);
} else {
- *running_animations = animations_still_running
+ debug!("Finishing transition: {:?}", running_animation);
+ if let Animation::Transition(_, _, ref property_animation) = running_animation {
+ send_transition_event(property_animation, TransitionEventType::TransitionEnd);
+ }
+ animation_state.finished_animations.push(running_animation);
}
}
+}
- for key in keys_to_remove {
- running_animations.remove(&key).unwrap();
+/// Send events for cancelled animations. Currently this only handles cancelled
+/// transitions, but eventually this should handle cancelled CSS animations as
+/// well.
+pub fn handle_cancelled_animations(
+ animation_state: &mut ElementAnimationState,
+ mut send_transition_event: impl FnMut(&PropertyAnimation, TransitionEventType),
+) {
+ for animation in animation_state.cancelled_animations.drain(..) {
+ match animation {
+ Animation::Transition(_, _, ref property_animation) => {
+ send_transition_event(property_animation, TransitionEventType::TransitionCancel)
+ },
+ Animation::Keyframes(..) => {
+ warn!("Got unexpected animation in finished transitions list.")
+ },
+ }
}
+}
- // Add new running animations.
- for new_running_animation in new_running_animations {
- if new_running_animation.is_transition() {
- match newly_transitioning_nodes {
- Some(ref mut nodes) => {
- nodes.push(new_running_animation.node().to_untrusted_node_address());
- },
- None => {
- warn!("New transition encountered from compositor-initiated layout.");
- },
- }
+pub fn handle_new_animations(
+ animation_state: &mut ElementAnimationState,
+ mut send_transition_event: impl FnMut(&PropertyAnimation, TransitionEventType),
+) {
+ for animation in animation_state.new_animations.drain(..) {
+ match animation {
+ Animation::Transition(_, _, ref property_animation) => {
+ send_transition_event(property_animation, TransitionEventType::TransitionRun)
+ },
+ Animation::Keyframes(..) => {},
}
-
- running_animations
- .entry(*new_running_animation.node())
- .or_insert_with(Vec::new)
- .push(new_running_animation)
+ animation_state.running_animations.push(animation);
}
-
- let animation_state = if running_animations.is_empty() {
- AnimationState::NoAnimationsPresent
- } else {
- AnimationState::AnimationsPresent
- };
-
- constellation_chan
- .send(ConstellationMsg::ChangeRunningAnimationsState(
- pipeline_id,
- animation_state,
- ))
- .unwrap();
}
/// Recalculates style for a set of animations. This does *not* run with the DOM
@@ -167,46 +193,48 @@ pub fn update_animation_state<E>(
pub fn recalc_style_for_animations<E>(
context: &LayoutContext,
flow: &mut dyn Flow,
- animations: &FxHashMap<OpaqueNode, Vec<Animation>>,
+ animation_states: &FxHashMap<OpaqueNode, ElementAnimationState>,
) -> FxHashSet<OpaqueNode>
where
E: TElement,
{
- let mut invalid_nodes = animations.keys().cloned().collect();
- do_recalc_style_for_animations::<E>(context, flow, animations, &mut invalid_nodes);
+ let mut invalid_nodes = animation_states.keys().cloned().collect();
+ do_recalc_style_for_animations::<E>(context, flow, animation_states, &mut invalid_nodes);
invalid_nodes
}
fn do_recalc_style_for_animations<E>(
context: &LayoutContext,
flow: &mut dyn Flow,
- animations: &FxHashMap<OpaqueNode, Vec<Animation>>,
+ animation_states: &FxHashMap<OpaqueNode, ElementAnimationState>,
invalid_nodes: &mut FxHashSet<OpaqueNode>,
) where
E: TElement,
{
let mut damage = RestyleDamage::empty();
flow.mutate_fragments(&mut |fragment| {
- if let Some(ref animations) = animations.get(&fragment.node) {
- invalid_nodes.remove(&fragment.node);
- for animation in animations.iter() {
- let old_style = fragment.style.clone();
- update_style_for_animation::<E>(
- &context.style_context,
- animation,
- &mut fragment.style,
- &ServoMetricsProvider,
- );
- let difference =
- RestyleDamage::compute_style_difference(&old_style, &fragment.style);
- damage |= difference.damage;
- }
+ let animations = match animation_states.get(&fragment.node) {
+ Some(state) => &state.running_animations,
+ None => return,
+ };
+
+ invalid_nodes.remove(&fragment.node);
+ for animation in animations.iter() {
+ let old_style = fragment.style.clone();
+ update_style_for_animation::<E>(
+ &context.style_context,
+ animation,
+ Arc::make_mut(&mut fragment.style),
+ &ServoMetricsProvider,
+ );
+ let difference = RestyleDamage::compute_style_difference(&old_style, &fragment.style);
+ damage |= difference.damage;
}
});
let base = flow.mut_base();
base.restyle_damage.insert(damage);
for kid in base.children.iter_mut() {
- do_recalc_style_for_animations::<E>(context, kid, animations, invalid_nodes)
+ do_recalc_style_for_animations::<E>(context, kid, animation_states, invalid_nodes)
}
}
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index 2338fba1f3a..4a346315e8a 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -25,7 +25,7 @@ mod dom_wrapper;
use crate::dom_wrapper::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode};
use app_units::Au;
-use crossbeam_channel::{unbounded, Receiver, Sender};
+use crossbeam_channel::{Receiver, Sender};
use embedder_traits::resources::{self, Resource};
use euclid::{default::Size2D as UntypedSize2D, Point2D, Rect, Scale, Size2D};
use fnv::FnvHashMap;
@@ -99,9 +99,9 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, MutexGuard};
use std::thread;
use std::time::Duration;
-use style::animation::Animation;
+use style::animation::ElementAnimationState;
+use style::context::SharedStyleContext;
use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters};
-use style::context::{SharedStyleContext, ThreadLocalStyleContextCreationInfo};
use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TDocument, TElement, TNode};
use style::driver;
use style::error_reporting::RustLogReporter;
@@ -185,13 +185,6 @@ pub struct LayoutThread {
/// This can be used to easily check for invalid stale data.
generation: Cell<u32>,
- /// A channel on which new animations that have been triggered by style recalculation can be
- /// sent.
- new_animations_sender: Sender<Animation>,
-
- /// Receives newly-discovered animations.
- new_animations_receiver: Receiver<Animation>,
-
/// The number of Web fonts that have been requested but not yet loaded.
outstanding_web_fonts: Arc<AtomicUsize>,
@@ -201,11 +194,8 @@ pub struct LayoutThread {
/// The document-specific shared lock used for author-origin stylesheets
document_shared_lock: Option<SharedRwLock>,
- /// The list of currently-running animations.
- running_animations: ServoArc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
-
- /// The list of animations that have expired since the last style recalculation.
- expired_animations: ServoArc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
+ /// The animation state for all of our nodes.
+ animation_states: ServoArc<RwLock<FxHashMap<OpaqueNode, ElementAnimationState>>>,
/// A counter for epoch messages
epoch: Cell<Epoch>,
@@ -538,9 +528,6 @@ impl LayoutThread {
window_size.device_pixel_ratio,
);
- // Create the channel on which new animations can be sent.
- let (new_animations_sender, new_animations_receiver) = unbounded();
-
// Proxy IPC messages from the pipeline to the layout thread.
let pipeline_receiver = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(pipeline_port);
@@ -569,13 +556,10 @@ impl LayoutThread {
font_cache_sender: ipc_font_cache_sender,
parallel_flag: true,
generation: Cell::new(0),
- new_animations_sender: new_animations_sender,
- new_animations_receiver: new_animations_receiver,
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
root_flow: RefCell::new(None),
document_shared_lock: None,
- running_animations: ServoArc::new(RwLock::new(Default::default())),
- expired_animations: ServoArc::new(RwLock::new(Default::default())),
+ animation_states: ServoArc::new(RwLock::new(Default::default())),
// Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR
epoch: Cell::new(Epoch(1)),
viewport_size: Size2D::new(Au(0), Au(0)),
@@ -642,9 +626,6 @@ impl LayoutThread {
snapshot_map: &'a SnapshotMap,
origin: ImmutableOrigin,
) -> LayoutContext<'a> {
- let thread_local_style_context_creation_data =
- ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
-
LayoutContext {
id: self.id,
origin,
@@ -653,10 +634,8 @@ impl LayoutThread {
options: GLOBAL_STYLE_DATA.options.clone(),
guards,
visited_styles_enabled: false,
- running_animations: self.running_animations.clone(),
- expired_animations: self.expired_animations.clone(),
+ animation_states: self.animation_states.clone(),
registered_speculative_painters: &self.registered_painters,
- local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
timer: self.timer.clone(),
traversal_flags: TraversalFlags::empty(),
snapshot_map: snapshot_map,
@@ -877,7 +856,13 @@ impl LayoutThread {
self.paint_time_metrics.set_navigation_start(time);
},
Msg::GetRunningAnimations(sender) => {
- let _ = sender.send(self.running_animations.read().len());
+ let running_animation_count = self
+ .animation_states
+ .read()
+ .values()
+ .map(|state| state.running_animations.len())
+ .sum();
+ let _ = sender.send(running_animation_count);
},
}
@@ -1732,7 +1717,7 @@ impl LayoutThread {
let invalid_nodes = {
// Perform an abbreviated style recalc that operates without access to the DOM.
- let animations = self.running_animations.read();
+ let animation_states = self.animation_states.read();
profile(
profile_time::ProfilerCategory::LayoutStyleRecalc,
self.profiler_metadata(),
@@ -1741,7 +1726,7 @@ impl LayoutThread {
animation::recalc_style_for_animations::<ServoLayoutElement>(
&layout_context,
FlowRef::deref_mut(&mut root_flow),
- &animations,
+ &animation_states,
)
},
)
@@ -1777,15 +1762,18 @@ impl LayoutThread {
.map(|nodes| nodes.lock().unwrap());
let newly_transitioning_nodes =
newly_transitioning_nodes.as_mut().map(|nodes| &mut **nodes);
- // Kick off animations if any were triggered, expire completed ones.
- animation::update_animation_state::<ServoLayoutElement>(
+ let mut animation_states = self.animation_states.write();
+
+ animation::collect_newly_transitioning_nodes(
+ &animation_states,
+ newly_transitioning_nodes,
+ );
+
+ animation::update_animation_states(
&self.constellation_chan,
&self.script_chan,
- &mut *self.running_animations.write(),
- &mut *self.expired_animations.write(),
+ &mut *animation_states,
invalid_nodes,
- newly_transitioning_nodes,
- &self.new_animations_receiver,
self.id,
&self.timer,
);
diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs
index fc7ae221e03..1a0d99cdb27 100644
--- a/components/layout_thread_2020/lib.rs
+++ b/components/layout_thread_2020/lib.rs
@@ -23,7 +23,7 @@ mod dom_wrapper;
use crate::dom_wrapper::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode};
use app_units::Au;
-use crossbeam_channel::{unbounded, Receiver, Sender};
+use crossbeam_channel::{Receiver, Sender};
use embedder_traits::resources::{self, Resource};
use euclid::{default::Size2D as UntypedSize2D, Point2D, Rect, Scale, Size2D};
use fnv::FnvHashMap;
@@ -81,9 +81,9 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, MutexGuard};
use std::thread;
use std::time::Duration;
-use style::animation::Animation;
-use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters};
-use style::context::{SharedStyleContext, ThreadLocalStyleContextCreationInfo};
+use style::context::{
+ QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext,
+};
use style::dom::{TDocument, TElement, TNode};
use style::driver;
use style::error_reporting::RustLogReporter;
@@ -159,13 +159,6 @@ pub struct LayoutThread {
/// This can be used to easily check for invalid stale data.
generation: Cell<u32>,
- /// A channel on which new animations that have been triggered by style recalculation can be
- /// sent.
- new_animations_sender: Sender<Animation>,
-
- /// Receives newly-discovered animations.
- _new_animations_receiver: Receiver<Animation>,
-
/// The number of Web fonts that have been requested but not yet loaded.
outstanding_web_fonts: Arc<AtomicUsize>,
@@ -499,9 +492,6 @@ impl LayoutThread {
window_size.device_pixel_ratio,
);
- // Create the channel on which new animations can be sent.
- let (new_animations_sender, new_animations_receiver) = unbounded();
-
// Proxy IPC messages from the pipeline to the layout thread.
let pipeline_receiver = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(pipeline_port);
@@ -528,8 +518,6 @@ impl LayoutThread {
font_cache_receiver: font_cache_receiver,
font_cache_sender: ipc_font_cache_sender,
generation: Cell::new(0),
- new_animations_sender: new_animations_sender,
- _new_animations_receiver: new_animations_receiver,
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
box_tree_root: Default::default(),
fragment_tree_root: Default::default(),
@@ -596,9 +584,6 @@ impl LayoutThread {
snapshot_map: &'a SnapshotMap,
origin: ImmutableOrigin,
) -> LayoutContext<'a> {
- let thread_local_style_context_creation_data =
- ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
-
LayoutContext {
id: self.id,
origin,
@@ -607,10 +592,8 @@ impl LayoutThread {
options: GLOBAL_STYLE_DATA.options.clone(),
guards,
visited_styles_enabled: false,
- running_animations: Default::default(),
- expired_animations: Default::default(),
+ animation_states: Default::default(),
registered_speculative_painters: &self.registered_painters,
- local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
timer: self.timer.clone(),
traversal_flags: TraversalFlags::empty(),
snapshot_map: snapshot_map,
diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml
index d1248453c10..64f40d55689 100644
--- a/components/net/Cargo.toml
+++ b/components/net/Cargo.toml
@@ -18,19 +18,19 @@ doctest = false
base64 = "0.10.1"
brotli = "3"
bytes = "0.4"
-content-security-policy = {version = "0.4.0", features = ["serde"]}
-cookie_rs = {package = "cookie", version = "0.11"}
+content-security-policy = { version = "0.4.0", features = ["serde"] }
+cookie_rs = { package = "cookie", version = "0.11" }
crossbeam-channel = "0.4"
data-url = "0.1.0"
-devtools_traits = {path = "../devtools_traits"}
+devtools_traits = { path = "../devtools_traits" }
embedder_traits = { path = "../embedder_traits" }
flate2 = "1"
futures = "0.1"
headers = "0.2"
http = "0.1"
hyper = "0.12"
-hyper_serde = "0.11"
hyper-openssl = "0.7"
+hyper_serde = "0.11"
immeta = "0.4"
ipc-channel = "0.14"
lazy_static = "1"
@@ -39,31 +39,31 @@ log = "0.4"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = "0.1"
mime = "0.3"
-mime_guess = "2.0.0-alpha.6"
-msg = {path = "../msg"}
-net_traits = {path = "../net_traits"}
+mime_guess = "2.0.0"
+msg = { path = "../msg" }
+net_traits = { path = "../net_traits" }
openssl = "0.10"
openssl-sys = "0.9"
percent-encoding = "2.0"
-pixels = {path = "../pixels"}
-profile_traits = {path = "../profile_traits"}
+pixels = { path = "../pixels" }
+profile_traits = { path = "../profile_traits" }
rayon = "1"
serde = "1.0"
serde_json = "1.0"
-servo_allocator = {path = "../allocator"}
-servo_arc = {path = "../servo_arc"}
-servo_config = {path = "../config"}
-servo_url = {path = "../url"}
-tokio = "0.1"
+servo_allocator = { path = "../allocator" }
+servo_arc = { path = "../servo_arc" }
+servo_config = { path = "../config" }
+servo_url = { path = "../url" }
time = "0.1.17"
+tokio = "0.1"
url = "2.0"
-uuid = {version = "0.8", features = ["v4"]}
-webrender_api = {git = "https://github.com/servo/webrender"}
+uuid = { version = "0.8", features = ["v4"] }
+webrender_api = { git = "https://github.com/servo/webrender" }
ws = { version = "0.9", features = ["ssl"] }
[dev-dependencies]
-std_test_override = { path = "../std_test_override" }
futures = "0.1"
+std_test_override = { path = "../std_test_override" }
tokio-openssl = "0.3"
[[test]]
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 2ed136079b6..f4d8808c869 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -30,25 +30,25 @@ phf_shared = "0.8"
serde_json = "1.0"
[dependencies]
-accountable-refcell = {version = "0.2.0", optional = true}
+accountable-refcell = { version = "0.2.0", optional = true }
app_units = "0.7"
-backtrace = {version = "0.3", optional = true}
+backtrace = { version = "0.3", optional = true }
base64 = "0.10.1"
bincode = "1"
bitflags = "1.0"
-bluetooth_traits = {path = "../bluetooth_traits"}
-canvas_traits = {path = "../canvas_traits"}
+bluetooth_traits = { path = "../bluetooth_traits" }
+canvas_traits = { path = "../canvas_traits" }
caseless = "0.2"
-content-security-policy = {version = "0.4.0", features = ["serde"]}
-cookie = "0.11"
chrono = "0.4"
+content-security-policy = { version = "0.4.0", features = ["serde"] }
+cookie = "0.11"
crossbeam-channel = "0.4"
cssparser = "0.27"
-deny_public_fields = {path = "../deny_public_fields"}
-devtools_traits = {path = "../devtools_traits"}
-dom_struct = {path = "../dom_struct"}
-domobject_derive = {path = "../domobject_derive"}
-embedder_traits = {path = "../embedder_traits"}
+deny_public_fields = { path = "../deny_public_fields" }
+devtools_traits = { path = "../devtools_traits" }
+dom_struct = { path = "../dom_struct" }
+domobject_derive = { path = "../domobject_derive" }
+embedder_traits = { path = "../embedder_traits" }
encoding_rs = "0.8"
enum-iterator = "0.3"
euclid = "0.20"
@@ -62,61 +62,61 @@ image = "0.23"
indexmap = "1.0.2"
ipc-channel = "0.14"
itertools = "0.8"
-jstraceable_derive = {path = "../jstraceable_derive"}
-js = {package = "mozjs", git = "https://github.com/servo/rust-mozjs"}
+js = { package = "mozjs", git = "https://github.com/servo/rust-mozjs" }
+jstraceable_derive = { path = "../jstraceable_derive" }
keyboard-types = "0.4.4"
lazy_static = "1"
libc = "0.2"
log = "0.4"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = "0.1"
-media = {path = "../media"}
-metrics = {path = "../metrics"}
-mitochondria = "1.1.2"
+media = { path = "../media" }
+metrics = { path = "../metrics" }
mime = "0.3.13"
-mime_guess = "2.0.0-alpha.6"
-msg = {path = "../msg"}
-net_traits = {path = "../net_traits"}
+mime_guess = "2.0.0"
+mitochondria = "1.1.2"
+msg = { path = "../msg" }
+net_traits = { path = "../net_traits" }
num-traits = "0.2"
parking_lot = "0.9"
percent-encoding = "2.0"
phf = "0.8"
-pixels = {path = "../pixels"}
-profile_traits = {path = "../profile_traits"}
+pixels = { path = "../pixels" }
+profile_traits = { path = "../profile_traits" }
ref_filter_map = "1.0.1"
ref_slice = "1.0"
regex = "1.1"
-script_layout_interface = {path = "../script_layout_interface"}
-script_plugins = {path = "../script_plugins"}
-script_traits = {path = "../script_traits"}
+script_layout_interface = { path = "../script_layout_interface" }
+script_plugins = { path = "../script_plugins" }
+script_traits = { path = "../script_traits" }
selectors = { path = "../selectors" }
-serde = {version = "1", features = ["derive"]}
+serde = { version = "1", features = ["derive"] }
serde_bytes = "0.11"
-servo_allocator = {path = "../allocator"}
-servo_arc = {path = "../servo_arc"}
-servo_atoms = {path = "../atoms"}
-servo_config = {path = "../config"}
-servo_geometry = {path = "../geometry" }
-servo-media = {git = "https://github.com/servo/media"}
-servo_rand = {path = "../rand"}
-servo_url = {path = "../url"}
-sparkle = "0.1"
+servo-media = { git = "https://github.com/servo/media" }
+servo_allocator = { path = "../allocator" }
+servo_arc = { path = "../servo_arc" }
+servo_atoms = { path = "../atoms" }
+servo_config = { path = "../config" }
+servo_geometry = { path = "../geometry" }
+servo_rand = { path = "../rand" }
+servo_url = { path = "../url" }
smallvec = { version = "0.6", features = ["std", "union"] }
-style = {path = "../style", features = ["servo"]}
-style_traits = {path = "../style_traits"}
+sparkle = "0.1"
+style = { path = "../style", features = ["servo"] }
+style_traits = { path = "../style_traits" }
swapper = "0.1"
-tendril = {version = "0.4.1", features = ["encoding_rs"]}
+tendril = { version = "0.4.1", features = ["encoding_rs"] }
time = "0.1.12"
unicode-bidi = "0.3.4"
unicode-segmentation = "1.1.0"
url = "2.0"
utf-8 = "0.7"
-uuid = {version = "0.8", features = ["v4", "serde"]}
-xml5ever = "0.16"
+uuid = { version = "0.8", features = ["v4", "serde"] }
webdriver = "0.40"
-webgpu = {path = "../webgpu"}
-webrender_api = {git = "https://github.com/servo/webrender"}
-webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
+webgpu = { path = "../webgpu" }
+webrender_api = { git = "https://github.com/servo/webrender" }
+webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
+xml5ever = "0.16"
[target.'cfg(not(target_os = "ios"))'.dependencies]
mozangle = "0.2"
diff --git a/components/script/devtools.rs b/components/script/devtools.rs
index 49d855ff20f..2aad7d101c7 100644
--- a/components/script/devtools.rs
+++ b/components/script/devtools.rs
@@ -34,7 +34,7 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
let cx = global.get_cx();
let _ac = enter_realm(global);
rooted!(in(*cx) let mut rval = UndefinedValue());
- global.evaluate_js_on_global_with_result(&eval, rval.handle_mut());
+ global.evaluate_script_on_global_with_result(&eval, "<eval>", rval.handle_mut(), 1);
if rval.is_undefined() {
EvaluateJSReply::VoidValue
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 97fffe52853..c2543cc984b 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -157,8 +157,8 @@ use webgpu::{
WebGPUPipelineLayout, WebGPUQueue, WebGPUShaderModule,
};
use webrender_api::{DocumentId, ImageKey};
-use webxr_api::Ray;
use webxr_api::SwapChainId as WebXRSwapChainId;
+use webxr_api::{Finger, Hand, Ray};
unsafe_no_jsmanaged_fields!(Tm);
@@ -554,6 +554,7 @@ unsafe_no_jsmanaged_fields!(
webxr_api::Frame,
webxr_api::InputSource,
webxr_api::InputId,
+ webxr_api::Joint,
webxr_api::HitTestId,
webxr_api::HitTestResult
);
@@ -881,6 +882,58 @@ where
}
}
+unsafe impl<J> JSTraceable for Hand<J>
+where
+ J: JSTraceable,
+{
+ #[inline]
+ unsafe fn trace(&self, trc: *mut JSTracer) {
+ // exhaustive match so we don't miss new fields
+ let Hand {
+ ref wrist,
+ ref thumb_metacarpal,
+ ref thumb_phalanx_proximal,
+ ref thumb_phalanx_distal,
+ ref thumb_phalanx_tip,
+ ref index,
+ ref middle,
+ ref ring,
+ ref little,
+ } = *self;
+ wrist.trace(trc);
+ thumb_metacarpal.trace(trc);
+ thumb_phalanx_proximal.trace(trc);
+ thumb_phalanx_distal.trace(trc);
+ thumb_phalanx_tip.trace(trc);
+ index.trace(trc);
+ middle.trace(trc);
+ ring.trace(trc);
+ little.trace(trc);
+ }
+}
+
+unsafe impl<J> JSTraceable for Finger<J>
+where
+ J: JSTraceable,
+{
+ #[inline]
+ unsafe fn trace(&self, trc: *mut JSTracer) {
+ // exhaustive match so we don't miss new fields
+ let Finger {
+ ref metacarpal,
+ ref phalanx_proximal,
+ ref phalanx_intermediate,
+ ref phalanx_distal,
+ ref phalanx_tip,
+ } = *self;
+ metacarpal.trace(trc);
+ phalanx_proximal.trace(trc);
+ phalanx_intermediate.trace(trc);
+ phalanx_distal.trace(trc);
+ phalanx_tip.trace(trc);
+ }
+}
+
/// Holds a set of JSTraceables that need to be rooted
struct RootedTraceableSet {
set: Vec<*const dyn JSTraceable>,
diff --git a/components/script/dom/console.rs b/components/script/dom/console.rs
index 22caa2993bd..cf6eb1668f8 100644
--- a/components/script/dom/console.rs
+++ b/components/script/dom/console.rs
@@ -7,15 +7,24 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::workerglobalscope::WorkerGlobalScope;
use devtools_traits::{ConsoleMessage, LogLevel, ScriptToDevtoolsControlMsg};
+use js::rust::describe_scripted_caller;
use std::io;
// https://developer.mozilla.org/en-US/docs/Web/API/Console
pub struct Console(());
impl Console {
+ #[allow(unsafe_code)]
fn send_to_devtools(global: &GlobalScope, level: LogLevel, message: DOMString) {
if let Some(chan) = global.devtools_chan() {
- let console_message = prepare_message(level, message);
+ let caller = unsafe { describe_scripted_caller(*global.get_cx()) }.unwrap_or_default();
+ let console_message = ConsoleMessage {
+ message: String::from(message),
+ logLevel: level,
+ filename: caller.filename,
+ lineNumber: caller.line as usize,
+ columnNumber: caller.col as usize,
+ };
let worker_id = global
.downcast::<WorkerGlobalScope>()
.map(|worker| worker.get_worker_id());
@@ -128,14 +137,3 @@ impl Console {
})
}
}
-
-fn prepare_message(log_level: LogLevel, message: DOMString) -> ConsoleMessage {
- // TODO: Sending fake values for filename, lineNumber and columnNumber in LogMessage; adjust later
- ConsoleMessage {
- message: String::from(message),
- logLevel: log_level,
- filename: "test".to_owned(),
- lineNumber: 1,
- columnNumber: 1,
- }
-}
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 150f7920fff..a4970afcca4 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -43,7 +43,7 @@ use js::jsapi::JS_AddInterruptCallback;
use js::jsapi::{Heap, JSContext, JSObject};
use js::jsval::UndefinedValue;
use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
-use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId};
+use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
use net_traits::image_cache::ImageCache;
use net_traits::request::{CredentialsMode, Destination, ParserMetadata};
use net_traits::request::{Referrer, RequestBuilder, RequestMode};
@@ -180,6 +180,7 @@ pub struct DedicatedWorkerGlobalScope {
parent_sender: Box<dyn ScriptChan + Send>,
#[ignore_malloc_size_of = "Arc"]
image_cache: Arc<dyn ImageCache>,
+ browsing_context: Option<BrowsingContextId>,
}
impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
@@ -221,6 +222,7 @@ impl DedicatedWorkerGlobalScope {
receiver: Receiver<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>,
+ browsing_context: Option<BrowsingContextId>,
) -> DedicatedWorkerGlobalScope {
DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope::new_inherited(
@@ -237,6 +239,7 @@ impl DedicatedWorkerGlobalScope {
parent_sender: parent_sender,
worker: DomRefCell::new(None),
image_cache: image_cache,
+ browsing_context,
}
}
@@ -253,6 +256,7 @@ impl DedicatedWorkerGlobalScope {
receiver: Receiver<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>,
+ browsing_context: Option<BrowsingContextId>,
) -> DomRoot<DedicatedWorkerGlobalScope> {
let cx = runtime.cx();
let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
@@ -267,6 +271,7 @@ impl DedicatedWorkerGlobalScope {
receiver,
closing,
image_cache,
+ browsing_context,
));
unsafe { DedicatedWorkerGlobalScopeBinding::Wrap(SafeJSContext::from_ptr(cx), scope) }
}
@@ -286,6 +291,7 @@ impl DedicatedWorkerGlobalScope {
worker_type: WorkerType,
closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>,
+ browsing_context: Option<BrowsingContextId>,
) {
let serialized_worker_url = worker_url.to_string();
let name = format!("WebWorker for {}", serialized_worker_url);
@@ -354,6 +360,7 @@ impl DedicatedWorkerGlobalScope {
receiver,
closing,
image_cache,
+ browsing_context,
);
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
// registration (#6631), so we instead use a random number and cross our fingers.
@@ -467,6 +474,7 @@ impl DedicatedWorkerGlobalScope {
}
fn handle_mixed_message(&self, msg: MixedMessage) {
+ // FIXME(#26324): `self.worker` is None in devtools messages.
match msg {
MixedMessage::FromDevtools(msg) => match msg {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
@@ -551,6 +559,10 @@ impl DedicatedWorkerGlobalScope {
.expect("Sending to parent failed");
Ok(())
}
+
+ pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
+ self.browsing_context
+ }
}
#[allow(unsafe_code)]
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 2d0f2ce1c26..3606ffc7c9d 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -934,6 +934,14 @@ impl Document {
pub fn title_changed(&self) {
if self.browsing_context().is_some() {
self.send_title_to_embedder();
+ let global = self.window.upcast::<GlobalScope>();
+ if let Some(ref chan) = global.devtools_chan() {
+ let title = String::from(self.Title());
+ let _ = chan.send(ScriptToDevtoolsControlMsg::TitleChanged(
+ global.pipeline_id(),
+ title,
+ ));
+ }
}
}
diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs
index aba0179a59b..3a0e7490fc9 100644
--- a/components/script/dom/event.rs
+++ b/components/script/dom/event.rs
@@ -647,6 +647,7 @@ fn invoke(
atom!("animationiteration") => Some(atom!("webkitAnimationIteration")),
atom!("animationstart") => Some(atom!("webkitAnimationStart")),
atom!("transitionend") => Some(atom!("webkitTransitionEnd")),
+ atom!("transitionrun") => Some(atom!("webkitTransitionRun")),
_ => None,
} {
let original_type = event.type_();
diff --git a/components/script/dom/fakexrdevice.rs b/components/script/dom/fakexrdevice.rs
index 5b1ca75fb3d..811a7e01b42 100644
--- a/components/script/dom/fakexrdevice.rs
+++ b/components/script/dom/fakexrdevice.rs
@@ -269,6 +269,7 @@ impl FakeXRDeviceMethods for FakeXRDevice {
id,
supports_grip: true,
profiles,
+ hand_support: None,
};
let init = MockInputInit {
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index 695cdbe6a49..4c4d86f1642 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -568,6 +568,27 @@ impl HTMLElementMethods for HTMLElement {
},
);
}
+
+ // https://html.spec.whatwg.org/multipage/#dom-contenteditable
+ fn ContentEditable(&self) -> DOMString {
+ // TODO: https://github.com/servo/servo/issues/12776
+ self.upcast::<Element>()
+ .get_attribute(&ns!(), &local_name!("contenteditable"))
+ .map(|attr| DOMString::from(&**attr.value()))
+ .unwrap_or_else(|| DOMString::from("inherit"))
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-contenteditable
+ fn SetContentEditable(&self, _: DOMString) {
+ // TODO: https://github.com/servo/servo/issues/12776
+ warn!("The contentEditable attribute is not implemented yet");
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-contenteditable
+ fn IsContentEditable(&self) -> bool {
+ // TODO: https://github.com/servo/servo/issues/12776
+ false
+ }
}
fn append_text_node_to_fragment(document: &Document, fragment: &DocumentFragment, text: String) {
diff --git a/components/script/dom/location.rs b/components/script/dom/location.rs
index aac4cc30b97..e57ecf6cd39 100644
--- a/components/script/dom/location.rs
+++ b/components/script/dom/location.rs
@@ -9,6 +9,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString;
+use crate::dom::document::Document;
use crate::dom::globalscope::GlobalScope;
use crate::dom::urlhelper::UrlHelper;
use crate::dom::window::Window;
@@ -62,17 +63,10 @@ impl Location {
self.window.get_url()
}
- fn set_url_component(&self, value: USVString, setter: fn(&mut ServoUrl, USVString)) {
- let mut url = self.window.get_url();
- let referrer = Referrer::ReferrerUrl(url.clone());
- setter(&mut url, value);
- self.navigate(url, referrer, HistoryEntryReplacement::Disabled, false);
- }
-
fn check_same_origin_domain(&self) -> ErrorResult {
- let entry_document = GlobalScope::entry().as_window().Document();
let this_document = self.window.Document();
- if entry_document
+ if self
+ .entry_document()
.origin()
.same_origin_domain(this_document.origin())
{
@@ -82,6 +76,10 @@ impl Location {
}
}
+ fn entry_document(&self) -> DomRoot<Document> {
+ GlobalScope::entry().as_window().Document()
+ }
+
// https://html.spec.whatwg.org/multipage/#dom-location-reload
pub fn reload_without_origin_check(&self) {
let url = self.get_url();
@@ -98,17 +96,24 @@ impl Location {
impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-assign
fn Assign(&self, url: USVString) -> ErrorResult {
- self.check_same_origin_domain()?;
- // TODO: per spec, we should use the _API base URL_ specified by the
- // _entry settings object_.
- let base_url = self.window.get_url();
- if let Ok(url) = base_url.join(&url.0) {
- let referrer = Referrer::ReferrerUrl(base_url.clone());
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: If this Location object's relevant Document's origin is not same
+ // origin-domain with the entry settings object's origin, then throw a
+ // "SecurityError" DOMException.
+ self.check_same_origin_domain()?;
+ // Step 3: Parse url relative to the entry settings object. If that failed,
+ // throw a "SyntaxError" DOMException.
+ let base_url = self.entry_document().url();
+ let url = match base_url.join(&url.0) {
+ Ok(url) => url,
+ Err(_) => return Err(Error::Syntax),
+ };
+ // Step 4: Location-object navigate to the resulting URL record.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
self.navigate(url, referrer, HistoryEntryReplacement::Disabled, false);
- Ok(())
- } else {
- Err(Error::Syntax)
}
+ Ok(())
}
// https://html.spec.whatwg.org/multipage/#dom-location-reload
@@ -122,17 +127,21 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-replace
fn Replace(&self, url: USVString) -> ErrorResult {
- // Note: no call to self.check_same_origin_domain()
- // TODO: per spec, we should use the _API base URL_ specified by the
- // _entry settings object_.
- let base_url = self.window.get_url();
- if let Ok(url) = base_url.join(&url.0) {
- let referrer = Referrer::ReferrerUrl(base_url.clone());
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: Parse url relative to the entry settings object. If that failed,
+ // throw a "SyntaxError" DOMException.
+ let base_url = self.entry_document().url();
+ let url = match base_url.join(&url.0) {
+ Ok(url) => url,
+ Err(_) => return Err(Error::Syntax),
+ };
+ // Step 3: Location-object navigate to the resulting URL record with
+ // the replacement flag set.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
self.navigate(url, referrer, HistoryEntryReplacement::Enabled, false);
- Ok(())
- } else {
- Err(Error::Syntax)
}
+ Ok(())
}
// https://html.spec.whatwg.org/multipage/#dom-location-hash
@@ -142,12 +151,28 @@ impl LocationMethods for Location {
}
// https://html.spec.whatwg.org/multipage/#dom-location-hash
- fn SetHash(&self, mut value: USVString) -> ErrorResult {
- if value.0.is_empty() {
- value = USVString("#".to_owned());
+ fn SetHash(&self, value: USVString) -> ErrorResult {
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: If this Location object's relevant Document's origin is not
+ // same origin-domain with the entry settings object's origin, then
+ // throw a "SecurityError" DOMException.
+ self.check_same_origin_domain()?;
+ // Step 3: Let copyURL be a copy of this Location object's url.
+ let mut copy_url = self.get_url();
+ // Step 4: Let input be the given value with a single leading "#" removed, if any.
+ // Step 5: Set copyURL's fragment to the empty string.
+ // Step 6: Basic URL parse input, with copyURL as url and fragment state as
+ // state override.
+ copy_url.as_mut_url().set_fragment(match value.0.as_str() {
+ "" => Some("#"),
+ _ if value.0.starts_with('#') => Some(&value.0[1..]),
+ _ => Some(&value.0),
+ });
+ // Step 7: Location-object-setter navigate to copyURL.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
+ self.navigate(copy_url, referrer, HistoryEntryReplacement::Disabled, false);
}
- self.check_same_origin_domain()?;
- self.set_url_component(value, UrlHelper::SetHash);
Ok(())
}
@@ -159,8 +184,24 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-host
fn SetHost(&self, value: USVString) -> ErrorResult {
- self.check_same_origin_domain()?;
- self.set_url_component(value, UrlHelper::SetHost);
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: If this Location object's relevant Document's origin is not
+ // same origin-domain with the entry settings object's origin, then
+ // throw a "SecurityError" DOMException.
+ self.check_same_origin_domain()?;
+ // Step 3: Let copyURL be a copy of this Location object's url.
+ let mut copy_url = self.get_url();
+ // Step 4: If copyURL's cannot-be-a-base-URL flag is set, terminate these steps.
+ if !copy_url.cannot_be_a_base() {
+ // Step 5: Basic URL parse the given value, with copyURL as url and host state
+ // as state override.
+ let _ = copy_url.as_mut_url().set_host(Some(&value.0));
+ // Step 6: Location-object-setter navigate to copyURL.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
+ self.navigate(copy_url, referrer, HistoryEntryReplacement::Disabled, false);
+ }
+ }
Ok(())
}
@@ -178,8 +219,24 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-hostname
fn SetHostname(&self, value: USVString) -> ErrorResult {
- self.check_same_origin_domain()?;
- self.set_url_component(value, UrlHelper::SetHostname);
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: If this Location object's relevant Document's origin is not
+ // same origin-domain with the entry settings object's origin, then
+ // throw a "SecurityError" DOMException.
+ self.check_same_origin_domain()?;
+ // Step 3: Let copyURL be a copy of this Location object's url.
+ let mut copy_url = self.get_url();
+ // Step 4: If copyURL's cannot-be-a-base-URL flag is set, terminate these steps.
+ if !copy_url.cannot_be_a_base() {
+ // Step 5: Basic URL parse the given value, with copyURL as url and hostname
+ // state as state override.
+ let _ = copy_url.as_mut_url().set_host(Some(&value.0));
+ // Step 6: Location-object-setter navigate to copyURL.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
+ self.navigate(copy_url, referrer, HistoryEntryReplacement::Disabled, false);
+ }
+ }
Ok(())
}
@@ -191,14 +248,20 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-href
fn SetHref(&self, value: USVString) -> ErrorResult {
- // Note: no call to self.check_same_origin_domain()
- let current_url = self.window.get_url();
- let url = match current_url.join(&value.0) {
- Ok(url) => url,
- Err(e) => return Err(Error::Type(format!("Couldn't parse URL: {}", e))),
- };
- let referrer = Referrer::ReferrerUrl(current_url.clone());
- self.navigate(url, referrer, HistoryEntryReplacement::Disabled, false);
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Note: no call to self.check_same_origin_domain()
+ // Step 2: Parse the given value relative to the entry settings object.
+ // If that failed, throw a TypeError exception.
+ let base_url = self.entry_document().url();
+ let url = match base_url.join(&value.0) {
+ Ok(url) => url,
+ Err(e) => return Err(Error::Type(format!("Couldn't parse URL: {}", e))),
+ };
+ // Step 3: Location-object-setter navigate to the resulting URL record.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
+ self.navigate(url, referrer, HistoryEntryReplacement::Disabled, false);
+ }
Ok(())
}
@@ -210,8 +273,25 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-pathname
fn SetPathname(&self, value: USVString) -> ErrorResult {
- self.check_same_origin_domain()?;
- self.set_url_component(value, UrlHelper::SetPathname);
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: If this Location object's relevant Document's origin is not
+ // same origin-domain with the entry settings object's origin, then
+ // throw a "SecurityError" DOMException.
+ self.check_same_origin_domain()?;
+ // Step 3: Let copyURL be a copy of this Location object's url.
+ let mut copy_url = self.get_url();
+ // Step 4: If copyURL's cannot-be-a-base-URL flag is set, terminate these steps.
+ if !copy_url.cannot_be_a_base() {
+ // Step 5: Set copyURL's path to the empty list.
+ // Step 6: Basic URL parse the given value, with copyURL as url and path
+ // start state as state override.
+ copy_url.as_mut_url().set_path(&value.0);
+ // Step 7: Location-object-setter navigate to copyURL.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
+ self.navigate(copy_url, referrer, HistoryEntryReplacement::Disabled, false);
+ }
+ }
Ok(())
}
@@ -223,8 +303,30 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-port
fn SetPort(&self, value: USVString) -> ErrorResult {
- self.check_same_origin_domain()?;
- self.set_url_component(value, UrlHelper::SetPort);
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: If this Location object's relevant Document's origin is not
+ // same origin-domain with the entry settings object's origin, then
+ // throw a "SecurityError" DOMException.
+ self.check_same_origin_domain()?;
+ // Step 3: Let copyURL be a copy of this Location object's url.
+ let mut copy_url = self.get_url();
+ // Step 4: If copyURL cannot have a username/password/port, then return.
+ // https://url.spec.whatwg.org/#cannot-have-a-username-password-port
+ if copy_url.host().is_some() &&
+ !copy_url.cannot_be_a_base() &&
+ copy_url.scheme() != "file"
+ {
+ // Step 5: If the given value is the empty string, then set copyURL's
+ // port to null.
+ // Step 6: Otherwise, basic URL parse the given value, with copyURL as url
+ // and port state as state override.
+ let _ = url::quirks::set_port(copy_url.as_mut_url(), &value.0);
+ // Step 7: Location-object-setter navigate to copyURL.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
+ self.navigate(copy_url, referrer, HistoryEntryReplacement::Disabled, false);
+ }
+ }
Ok(())
}
@@ -236,8 +338,34 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-protocol
fn SetProtocol(&self, value: USVString) -> ErrorResult {
- self.check_same_origin_domain()?;
- self.set_url_component(value, UrlHelper::SetProtocol);
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: If this Location object's relevant Document's origin is not
+ // same origin-domain with the entry settings object's origin, then
+ // throw a "SecurityError" DOMException.
+ self.check_same_origin_domain()?;
+ // Step 3: Let copyURL be a copy of this Location object's url.
+ let mut copy_url = self.get_url();
+ // Step 4: Let possibleFailure be the result of basic URL parsing the given
+ // value, followed by ":", with copyURL as url and scheme start state as
+ // state override.
+ let scheme = match value.0.find(':') {
+ Some(position) => &value.0[..position],
+ None => &value.0,
+ };
+ if let Err(_) = copy_url.as_mut_url().set_scheme(scheme) {
+ // Step 5: If possibleFailure is failure, then throw a "SyntaxError" DOMException.
+ return Err(Error::Syntax);
+ }
+ // Step 6: If copyURL's scheme is not an HTTP(S) scheme, then terminate these steps.
+ if copy_url.scheme().eq_ignore_ascii_case("http") ||
+ copy_url.scheme().eq_ignore_ascii_case("https")
+ {
+ // Step 7: Location-object-setter navigate to copyURL.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
+ self.navigate(copy_url, referrer, HistoryEntryReplacement::Disabled, false);
+ }
+ }
Ok(())
}
@@ -249,8 +377,30 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-search
fn SetSearch(&self, value: USVString) -> ErrorResult {
- self.check_same_origin_domain()?;
- self.set_url_component(value, UrlHelper::SetSearch);
+ // Step 1: If this Location object's relevant Document is null, then return.
+ if self.window.has_document() {
+ // Step 2: If this Location object's relevant Document's origin is not
+ // same origin-domain with the entry settings object's origin, then
+ // throw a "SecurityError" DOMException.
+ self.check_same_origin_domain()?;
+ // Step 3: Let copyURL be a copy of this Location object's url.
+ let mut copy_url = self.get_url();
+ // Step 4: If the given value is the empty string, set copyURL's query to null.
+ // Step 5: Otherwise, run these substeps:
+ // 1. Let input be the given value with a single leading "?" removed, if any.
+ // 2. Set copyURL's query to the empty string.
+ // 3. Basic URL parse input, with copyURL as url and query state as state
+ // override, and the relevant Document's document's character encoding as
+ // encoding override.
+ copy_url.as_mut_url().set_query(match value.0.as_str() {
+ "" => None,
+ _ if value.0.starts_with('?') => Some(&value.0[1..]),
+ _ => Some(&value.0),
+ });
+ // Step 6: Location-object-setter navigate to copyURL.
+ let referrer = Referrer::ReferrerUrl(self.get_url());
+ self.navigate(copy_url, referrer, HistoryEntryReplacement::Disabled, false);
+ }
Ok(())
}
}
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index b27c02208be..b1ea4f5cde2 100644
--- a/components/script/dom/macros.rs
+++ b/components/script/dom/macros.rs
@@ -496,7 +496,9 @@ macro_rules! global_event_handlers(
event_handler!(suspend, GetOnsuspend, SetOnsuspend);
event_handler!(timeupdate, GetOntimeupdate, SetOntimeupdate);
event_handler!(toggle, GetOntoggle, SetOntoggle);
+ event_handler!(transitioncancel, GetOntransitioncancel, SetOntransitioncancel);
event_handler!(transitionend, GetOntransitionend, SetOntransitionend);
+ event_handler!(transitionrun, GetOntransitionrun, SetOntransitionrun);
event_handler!(volumechange, GetOnvolumechange, SetOnvolumechange);
event_handler!(waiting, GetOnwaiting, SetOnwaiting);
)
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index a410220b427..a0f6241d55e 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -572,12 +572,15 @@ pub mod xmlhttprequesteventtarget;
pub mod xmlhttprequestupload;
pub mod xmlserializer;
pub mod xrframe;
+pub mod xrhand;
pub mod xrhittestresult;
pub mod xrhittestsource;
pub mod xrinputsource;
pub mod xrinputsourcearray;
pub mod xrinputsourceevent;
pub mod xrinputsourceschangeevent;
+pub mod xrjointpose;
+pub mod xrjointspace;
pub mod xrlayer;
pub mod xrmediabinding;
pub mod xrpose;
diff --git a/components/script/dom/serviceworkerregistration.rs b/components/script/dom/serviceworkerregistration.rs
index f242da12404..9bb578e0d59 100644
--- a/components/script/dom/serviceworkerregistration.rs
+++ b/components/script/dom/serviceworkerregistration.rs
@@ -112,7 +112,7 @@ impl ServiceWorkerRegistration {
let worker_id = WorkerId(Uuid::new_v4());
let devtools_chan = global.devtools_chan().cloned();
- let init = prepare_workerscope_init(&global, None);
+ let init = prepare_workerscope_init(&global, None, None);
ScopeThings {
script_url: script_url,
init: init,
diff --git a/components/script/dom/vertexarrayobject.rs b/components/script/dom/vertexarrayobject.rs
index 34ef5b428bb..fcf6461e2a8 100644
--- a/components/script/dom/vertexarrayobject.rs
+++ b/components/script/dom/vertexarrayobject.rs
@@ -7,7 +7,7 @@ use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebG
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use crate::dom::bindings::root::{Dom, MutNullableDom};
use crate::dom::webglbuffer::WebGLBuffer;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::{
ActiveAttribInfo, WebGLCommand, WebGLError, WebGLResult, WebGLVersion, WebGLVertexArrayId,
};
@@ -45,26 +45,25 @@ impl VertexArrayObject {
self.is_deleted.get()
}
- pub fn delete(&self, fallible: bool) {
+ pub fn delete(&self, operation_fallibility: Operation) {
assert!(self.id.is_some());
if self.is_deleted.get() {
return;
}
self.is_deleted.set(true);
let cmd = WebGLCommand::DeleteVertexArray(self.id.unwrap());
- if fallible {
- self.context.send_command_ignored(cmd);
- } else {
- self.context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => self.context.send_command_ignored(cmd),
+ Operation::Infallible => self.context.send_command(cmd),
}
for attrib_data in &**self.vertex_attribs.borrow() {
if let Some(buffer) = attrib_data.buffer() {
- buffer.decrement_attached_counter(fallible);
+ buffer.decrement_attached_counter(operation_fallibility);
}
}
if let Some(buffer) = self.element_array_buffer.get() {
- buffer.decrement_attached_counter(fallible);
+ buffer.decrement_attached_counter(operation_fallibility);
}
}
@@ -156,7 +155,7 @@ impl VertexArrayObject {
offset as u32,
));
if let Some(old) = data.buffer() {
- old.decrement_attached_counter(false);
+ old.decrement_attached_counter(Operation::Infallible);
}
*data = VertexAttribData {
@@ -188,7 +187,7 @@ impl VertexArrayObject {
if b.id() != buffer.id() {
continue;
}
- b.decrement_attached_counter(false);
+ b.decrement_attached_counter(Operation::Infallible);
}
attrib.buffer = None;
}
@@ -197,7 +196,7 @@ impl VertexArrayObject {
.get()
.map_or(false, |b| buffer == &*b)
{
- buffer.decrement_attached_counter(false);
+ buffer.decrement_attached_counter(Operation::Infallible);
self.element_array_buffer.set(None);
}
}
@@ -256,7 +255,7 @@ impl VertexArrayObject {
impl Drop for VertexArrayObject {
fn drop(&mut self) {
if self.id.is_some() {
- self.delete(true);
+ self.delete(Operation::Fallible);
}
}
}
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index 949f3a3bbdc..6ed42deea01 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -18,7 +18,6 @@ use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
-use crate::dom::htmliframeelement::HTMLIFrameElement;
use crate::dom::webglactiveinfo::WebGLActiveInfo;
use crate::dom::webglbuffer::WebGLBuffer;
use crate::dom::webglframebuffer::{WebGLFramebuffer, WebGLFramebufferAttachmentRoot};
@@ -26,7 +25,7 @@ use crate::dom::webglprogram::WebGLProgram;
use crate::dom::webglquery::WebGLQuery;
use crate::dom::webglrenderbuffer::WebGLRenderbuffer;
use crate::dom::webglrenderingcontext::{
- uniform_get, uniform_typed, LayoutCanvasWebGLRenderingContextHelpers, VertexAttrib,
+ uniform_get, uniform_typed, LayoutCanvasWebGLRenderingContextHelpers, Operation, VertexAttrib,
WebGLRenderingContext,
};
use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue};
@@ -339,7 +338,7 @@ impl WebGL2RenderingContext {
fn unbind_from(&self, slot: &MutNullableDom<WebGLBuffer>, buffer: &WebGLBuffer) {
if slot.get().map_or(false, |b| buffer == &*b) {
- buffer.decrement_attached_counter(false);
+ buffer.decrement_attached_counter(Operation::Infallible);
slot.set(None);
}
}
@@ -868,8 +867,10 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- fn GetBufferParameter(&self, cx: JSContext, target: u32, parameter: u32) -> JSVal {
- self.base.GetBufferParameter(cx, target, parameter)
+ fn GetBufferParameter(&self, _cx: JSContext, target: u32, parameter: u32) -> JSVal {
+ let buffer =
+ handle_potential_webgl_error!(self.base, self.bound_buffer(target), return NullValue());
+ self.base.get_buffer_param(buffer, parameter)
}
#[allow(unsafe_code)]
@@ -1225,7 +1226,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- fn BufferData(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
+ fn BufferData_(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
let bound_buffer =
handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
@@ -1233,7 +1234,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- fn BufferData_(&self, target: u32, size: i64, usage: u32) {
+ fn BufferData(&self, target: u32, size: i64, usage: u32) {
let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
let bound_buffer =
handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
@@ -1457,7 +1458,8 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
}
- /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6
+ #[allow(unsafe_code)]
fn CompressedTexImage2D(
&self,
target: u32,
@@ -1467,19 +1469,32 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
height: i32,
border: i32,
pixels: CustomAutoRooterGuard<ArrayBufferView>,
+ src_offset: u32,
+ src_length_override: u32,
) {
- self.base.CompressedTexImage2D(
+ let mut data = unsafe { pixels.as_slice() };
+ let start = src_offset as usize;
+ let end = (src_offset + src_length_override) as usize;
+ if start > data.len() || end > data.len() {
+ self.base.webgl_error(InvalidValue);
+ return;
+ }
+ if src_length_override != 0 {
+ data = &data[start..end];
+ }
+ self.base.compressed_tex_image_2d(
target,
level,
internal_format,
width,
height,
border,
- pixels,
+ data,
)
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
+ #[allow(unsafe_code)]
fn CompressedTexSubImage2D(
&self,
target: u32,
@@ -1490,9 +1505,21 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
height: i32,
format: u32,
pixels: CustomAutoRooterGuard<ArrayBufferView>,
+ src_offset: u32,
+ src_length_override: u32,
) {
- self.base.CompressedTexSubImage2D(
- target, level, xoffset, yoffset, width, height, format, pixels,
+ let mut data = unsafe { pixels.as_slice() };
+ let start = src_offset as usize;
+ let end = (src_offset + src_length_override) as usize;
+ if start > data.len() || end > data.len() {
+ self.base.webgl_error(InvalidValue);
+ return;
+ }
+ if src_length_override != 0 {
+ data = &data[start..end];
+ }
+ self.base.compressed_tex_sub_image_2d(
+ target, level, xoffset, yoffset, width, height, format, data,
)
}
@@ -1665,7 +1692,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.unbind_from(&binding.buffer, &buffer);
}
- buffer.mark_for_deletion(false);
+ buffer.mark_for_deletion(Operation::Infallible);
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6
@@ -2136,7 +2163,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_offset: u32,
src_length: u32,
) {
- self.base.Uniform1iv(location, v, src_offset, src_length)
+ self.base.uniform1iv(location, v, src_offset, src_length)
}
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
@@ -2198,7 +2225,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_offset: u32,
src_length: u32,
) {
- self.base.Uniform1fv(location, v, src_offset, src_length);
+ self.base.uniform1fv(location, v, src_offset, src_length);
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -2214,7 +2241,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_offset: u32,
src_length: u32,
) {
- self.base.Uniform2fv(location, v, src_offset, src_length);
+ self.base.uniform2fv(location, v, src_offset, src_length);
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -2230,7 +2257,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_offset: u32,
src_length: u32,
) {
- self.base.Uniform2iv(location, v, src_offset, src_length)
+ self.base.uniform2iv(location, v, src_offset, src_length)
}
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
@@ -2279,7 +2306,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_offset: u32,
src_length: u32,
) {
- self.base.Uniform3fv(location, v, src_offset, src_length);
+ self.base.uniform3fv(location, v, src_offset, src_length);
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -2295,7 +2322,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_offset: u32,
src_length: u32,
) {
- self.base.Uniform3iv(location, v, src_offset, src_length)
+ self.base.uniform3iv(location, v, src_offset, src_length)
}
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
@@ -2344,7 +2371,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_offset: u32,
src_length: u32,
) {
- self.base.Uniform4iv(location, v, src_offset, src_length)
+ self.base.uniform4iv(location, v, src_offset, src_length)
}
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
@@ -2393,7 +2420,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_offset: u32,
src_length: u32,
) {
- self.base.Uniform4fv(location, v, src_offset, src_length);
+ self.base.uniform4fv(location, v, src_offset, src_length);
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -2406,7 +2433,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_length: u32,
) {
self.base
- .UniformMatrix2fv(location, transpose, v, src_offset, src_length)
+ .uniform_matrix_2fv(location, transpose, v, src_offset, src_length)
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -2419,7 +2446,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_length: u32,
) {
self.base
- .UniformMatrix3fv(location, transpose, v, src_offset, src_length)
+ .uniform_matrix_3fv(location, transpose, v, src_offset, src_length)
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -2432,7 +2459,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
src_length: u32,
) {
self.base
- .UniformMatrix4fv(location, transpose, v, src_offset, src_length)
+ .uniform_matrix_4fv(location, transpose, v, src_offset, src_length)
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
@@ -2798,7 +2825,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
&self,
target: u32,
level: i32,
- internal_format: u32,
+ internal_format: i32,
width: i32,
height: i32,
border: i32,
@@ -2824,7 +2851,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
&self,
target: u32,
level: i32,
- internal_format: u32,
+ internal_format: i32,
format: u32,
data_type: u32,
source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
@@ -2834,30 +2861,6 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
- fn TexImageDOM(
- &self,
- target: u32,
- level: i32,
- internal_format: u32,
- width: i32,
- height: i32,
- format: u32,
- data_type: u32,
- source: &HTMLIFrameElement,
- ) -> Fallible<()> {
- self.base.TexImageDOM(
- target,
- level,
- internal_format,
- width,
- height,
- format,
- data_type,
- source,
- )
- }
-
- /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn TexSubImage2D(
&self,
target: u32,
@@ -3086,7 +3089,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
}
- query.delete(false);
+ query.delete(Operation::Infallible);
}
}
@@ -3112,7 +3115,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
slot.set(None);
}
}
- sampler.delete(false);
+ sampler.delete(Operation::Infallible);
}
}
@@ -3343,7 +3346,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
fn DeleteSync(&self, sync: Option<&WebGLSync>) {
if let Some(sync) = sync {
handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
- sync.delete(false);
+ sync.delete(Operation::Infallible);
}
}
@@ -3422,7 +3425,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.webgl_error(InvalidOperation);
return;
}
- tf.delete(false);
+ tf.delete(Operation::Infallible);
self.current_transform_feedback.set(None);
}
}
@@ -3656,7 +3659,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
for slot in &[&generic_slot, &indexed_binding.buffer] {
if let Some(old) = slot.get() {
- old.decrement_attached_counter(false);
+ old.decrement_attached_counter(Operation::Infallible);
}
slot.set(buffer);
}
@@ -3734,7 +3737,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
for slot in &[&generic_slot, &indexed_binding.buffer] {
if let Some(old) = slot.get() {
- old.decrement_attached_counter(false);
+ old.decrement_attached_counter(Operation::Infallible);
}
slot.set(buffer);
}
@@ -3998,7 +4001,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
if width < 0 || height < 0 {
- return;
+ return self.base.webgl_error(InvalidValue);
}
self.base
diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs
index 5ee1e7e1373..f81270d8240 100644
--- a/components/script/dom/webglbuffer.rs
+++ b/components/script/dom/webglbuffer.rs
@@ -9,7 +9,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::webgl_channel;
use canvas_traits::webgl::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult};
use dom_struct::dom_struct;
@@ -97,24 +97,23 @@ impl WebGLBuffer {
self.capacity.get()
}
- pub fn mark_for_deletion(&self, fallible: bool) {
+ pub fn mark_for_deletion(&self, operation_fallibility: Operation) {
if self.marked_for_deletion.get() {
return;
}
self.marked_for_deletion.set(true);
if self.is_deleted() {
- self.delete(fallible);
+ self.delete(operation_fallibility);
}
}
- fn delete(&self, fallible: bool) {
+ fn delete(&self, operation_fallibility: Operation) {
assert!(self.is_deleted());
let context = self.upcast::<WebGLObject>().context();
let cmd = WebGLCommand::DeleteBuffer(self.id);
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(cmd),
+ Operation::Infallible => context.send_command(cmd),
}
}
@@ -164,7 +163,7 @@ impl WebGLBuffer {
);
}
- pub fn decrement_attached_counter(&self, fallible: bool) {
+ pub fn decrement_attached_counter(&self, operation_fallibility: Operation) {
self.attached_counter.set(
self.attached_counter
.get()
@@ -172,7 +171,7 @@ impl WebGLBuffer {
.expect("refcount underflowed"),
);
if self.is_deleted() {
- self.delete(fallible);
+ self.delete(operation_fallibility);
}
}
@@ -183,6 +182,6 @@ impl WebGLBuffer {
impl Drop for WebGLBuffer {
fn drop(&mut self) {
- self.mark_for_deletion(true);
+ self.mark_for_deletion(Operation::Fallible);
}
}
diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs
index 4b2f7c7d56e..9f38365c4c7 100644
--- a/components/script/dom/webglframebuffer.rs
+++ b/components/script/dom/webglframebuffer.rs
@@ -11,7 +11,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderbuffer::WebGLRenderbuffer;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use crate::dom::webgltexture::WebGLTexture;
use crate::dom::xrsession::XRSession;
use canvas_traits::webgl::{webgl_channel, WebGLError, WebGLResult, WebGLVersion};
@@ -207,15 +207,14 @@ impl WebGLFramebuffer {
));
}
- pub fn delete(&self, fallible: bool) {
+ pub fn delete(&self, operation_fallibility: Operation) {
if !self.is_deleted.get() {
self.is_deleted.set(true);
let context = self.upcast::<WebGLObject>().context();
let cmd = WebGLCommand::DeleteFramebuffer(self.id);
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(cmd),
+ Operation::Infallible => context.send_command(cmd),
}
}
}
@@ -977,7 +976,7 @@ impl WebGLFramebuffer {
impl Drop for WebGLFramebuffer {
fn drop(&mut self) {
- let _ = self.delete(true);
+ let _ = self.delete(Operation::Fallible);
}
}
diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs
index 79598f7f5c1..88cecf0296f 100644
--- a/components/script/dom/webglprogram.rs
+++ b/components/script/dom/webglprogram.rs
@@ -12,7 +12,7 @@ use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::webglactiveinfo::WebGLActiveInfo;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use crate::dom::webglshader::WebGLShader;
use crate::dom::webgluniformlocation::WebGLUniformLocation;
use canvas_traits::webgl::{webgl_channel, WebGLProgramId, WebGLResult};
@@ -84,17 +84,16 @@ impl WebGLProgram {
}
/// glDeleteProgram
- pub fn mark_for_deletion(&self, fallible: bool) {
+ pub fn mark_for_deletion(&self, operation_fallibility: Operation) {
if self.marked_for_deletion.get() {
return;
}
self.marked_for_deletion.set(true);
let cmd = WebGLCommand::DeleteProgram(self.id);
let context = self.upcast::<WebGLObject>().context();
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(cmd),
+ Operation::Infallible => context.send_command(cmd),
}
if self.is_deleted() {
self.detach_shaders();
@@ -639,7 +638,7 @@ impl WebGLProgram {
impl Drop for WebGLProgram {
fn drop(&mut self) {
self.in_use(false);
- self.mark_for_deletion(true);
+ self.mark_for_deletion(Operation::Fallible);
}
}
diff --git a/components/script/dom/webglquery.rs b/components/script/dom/webglquery.rs
index d7418471936..454fe72954e 100644
--- a/components/script/dom/webglquery.rs
+++ b/components/script/dom/webglquery.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use crate::task_source::TaskSource;
use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLQueryId};
@@ -96,16 +96,15 @@ impl WebGLQuery {
Ok(())
}
- pub fn delete(&self, fallible: bool) {
+ pub fn delete(&self, operation_fallibility: Operation) {
if !self.marked_for_deletion.get() {
self.marked_for_deletion.set(true);
let context = self.upcast::<WebGLObject>().context();
let command = WebGLCommand::DeleteQuery(self.gl_id);
- if fallible {
- context.send_command_ignored(command);
- } else {
- context.send_command(command);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(command),
+ Operation::Infallible => context.send_command(command),
}
}
}
@@ -187,6 +186,6 @@ impl WebGLQuery {
impl Drop for WebGLQuery {
fn drop(&mut self) {
- self.delete(true);
+ self.delete(Operation::Fallible);
}
}
diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs
index f1a3ba99c53..204fe9ab46e 100644
--- a/components/script/dom/webglrenderbuffer.rs
+++ b/components/script/dom/webglrenderbuffer.rs
@@ -11,7 +11,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::webglframebuffer::WebGLFramebuffer;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::{
webgl_channel, GlType, InternalFormatIntVec, WebGLCommand, WebGLError, WebGLRenderbufferId,
WebGLResult, WebGLVersion,
@@ -90,7 +90,7 @@ impl WebGLRenderbuffer {
.send_command(WebGLCommand::BindRenderbuffer(target, Some(self.id)));
}
- pub fn delete(&self, fallible: bool) {
+ pub fn delete(&self, operation_fallibility: Operation) {
if !self.is_deleted.get() {
self.is_deleted.set(true);
@@ -113,10 +113,9 @@ impl WebGLRenderbuffer {
}
let cmd = WebGLCommand::DeleteRenderbuffer(self.id);
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(cmd),
+ Operation::Infallible => context.send_command(cmd),
}
}
}
@@ -277,6 +276,6 @@ impl WebGLRenderbuffer {
impl Drop for WebGLRenderbuffer {
fn drop(&mut self) {
- self.delete(true);
+ self.delete(Operation::Fallible);
}
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 53dff84c6ec..e616410b31d 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -155,6 +155,12 @@ pub enum VertexAttrib {
Uint(u32, u32, u32, u32),
}
+#[derive(Clone, Copy, Debug)]
+pub enum Operation {
+ Fallible,
+ Infallible,
+}
+
#[dom_struct]
pub struct WebGLRenderingContext {
reflector_: Reflector,
@@ -1142,7 +1148,7 @@ impl WebGLRenderingContext {
self.current_vao.set(None);
self.send_command(WebGLCommand::BindVertexArray(None));
}
- vao.delete(false);
+ vao.delete(Operation::Infallible);
}
}
@@ -1160,7 +1166,7 @@ impl WebGLRenderingContext {
self.current_vao_webgl2.set(None);
self.send_command(WebGLCommand::BindVertexArray(None));
}
- vao.delete(false);
+ vao.delete(Operation::Infallible);
}
}
@@ -1335,7 +1341,7 @@ impl WebGLRenderingContext {
self.send_command(WebGLCommand::BindBuffer(target, buffer.map(|b| b.id())));
if let Some(old) = slot.get() {
- old.decrement_attached_counter(false);
+ old.decrement_attached_counter(Operation::Infallible);
}
slot.set(buffer);
@@ -1533,6 +1539,354 @@ impl WebGLRenderingContext {
let last_slot = constants::COLOR_ATTACHMENT0 + self.limits().max_color_attachments - 1;
constants::COLOR_ATTACHMENT0 <= attachment && attachment <= last_slot
}
+
+ pub fn compressed_tex_image_2d<'a>(
+ &self,
+ target: u32,
+ level: i32,
+ internal_format: u32,
+ width: i32,
+ height: i32,
+ border: i32,
+ data: &'a [u8],
+ ) {
+ let validator = CompressedTexImage2DValidator::new(
+ self,
+ target,
+ level,
+ width,
+ height,
+ border,
+ internal_format,
+ data.len(),
+ );
+ let CommonCompressedTexImage2DValidatorResult {
+ texture,
+ target,
+ level,
+ width,
+ height,
+ compression,
+ } = match validator.validate() {
+ Ok(result) => result,
+ Err(_) => return,
+ };
+
+ let size = Size2D::new(width, height);
+ let buff = IpcSharedMemory::from_bytes(data);
+ let pixels = TexPixels::from_array(buff, size);
+ let data = pixels.data;
+
+ handle_potential_webgl_error!(
+ self,
+ texture.initialize(
+ target,
+ size.width,
+ size.height,
+ 1,
+ compression.format,
+ level,
+ Some(TexDataType::UnsignedByte)
+ )
+ );
+
+ self.send_command(WebGLCommand::CompressedTexImage2D {
+ target: target.as_gl_constant(),
+ level,
+ internal_format,
+ size: Size2D::new(width, height),
+ data: data.into(),
+ });
+
+ if let Some(fb) = self.bound_draw_framebuffer.get() {
+ fb.invalidate_texture(&*texture);
+ }
+ }
+
+ pub fn compressed_tex_sub_image_2d<'a>(
+ &self,
+ target: u32,
+ level: i32,
+ xoffset: i32,
+ yoffset: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ data: &'a [u8],
+ ) {
+ let validator = CompressedTexSubImage2DValidator::new(
+ self,
+ target,
+ level,
+ xoffset,
+ yoffset,
+ width,
+ height,
+ format,
+ data.len(),
+ );
+ let CommonCompressedTexImage2DValidatorResult {
+ texture: _,
+ target,
+ level,
+ width,
+ height,
+ ..
+ } = match validator.validate() {
+ Ok(result) => result,
+ Err(_) => return,
+ };
+
+ let buff = IpcSharedMemory::from_bytes(data);
+ let pixels = TexPixels::from_array(buff, Size2D::new(width, height));
+ let data = pixels.data;
+
+ self.send_command(WebGLCommand::CompressedTexSubImage2D {
+ target: target.as_gl_constant(),
+ level: level as i32,
+ xoffset,
+ yoffset,
+ size: Size2D::new(width, height),
+ format,
+ data: data.into(),
+ });
+ }
+
+ pub fn uniform1iv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ val: Int32ArrayOrLongSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::BOOL |
+ constants::INT |
+ constants::SAMPLER_2D |
+ constants::SAMPLER_CUBE => {},
+ _ => return Err(InvalidOperation),
+ }
+
+ let val = self.uniform_vec_section_int(val, src_offset, src_length, 1, location)?;
+
+ match location.type_() {
+ constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
+ for &v in val
+ .iter()
+ .take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
+ {
+ if v < 0 || v as u32 >= self.limits.max_combined_texture_image_units {
+ return Err(InvalidValue);
+ }
+ }
+ },
+ _ => {},
+ }
+ self.send_command(WebGLCommand::Uniform1iv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform1fv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ val: Float32ArrayOrUnrestrictedFloatSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::BOOL | constants::FLOAT => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val = self.uniform_vec_section_float(val, src_offset, src_length, 1, location)?;
+ self.send_command(WebGLCommand::Uniform1fv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform2fv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ val: Float32ArrayOrUnrestrictedFloatSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val = self.uniform_vec_section_float(val, src_offset, src_length, 2, location)?;
+ self.send_command(WebGLCommand::Uniform2fv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform2iv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ val: Int32ArrayOrLongSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::BOOL_VEC2 | constants::INT_VEC2 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val = self.uniform_vec_section_int(val, src_offset, src_length, 2, location)?;
+ self.send_command(WebGLCommand::Uniform2iv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform3fv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ val: Float32ArrayOrUnrestrictedFloatSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val = self.uniform_vec_section_float(val, src_offset, src_length, 3, location)?;
+ self.send_command(WebGLCommand::Uniform3fv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform3iv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ val: Int32ArrayOrLongSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::BOOL_VEC3 | constants::INT_VEC3 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val = self.uniform_vec_section_int(val, src_offset, src_length, 3, location)?;
+ self.send_command(WebGLCommand::Uniform3iv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform4iv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ val: Int32ArrayOrLongSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::BOOL_VEC4 | constants::INT_VEC4 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val = self.uniform_vec_section_int(val, src_offset, src_length, 4, location)?;
+ self.send_command(WebGLCommand::Uniform4iv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform4fv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ val: Float32ArrayOrUnrestrictedFloatSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val = self.uniform_vec_section_float(val, src_offset, src_length, 4, location)?;
+ self.send_command(WebGLCommand::Uniform4fv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform_matrix_2fv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ transpose: bool,
+ val: Float32ArrayOrUnrestrictedFloatSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::FLOAT_MAT2 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val =
+ self.uniform_matrix_section(val, src_offset, src_length, transpose, 4, location)?;
+ self.send_command(WebGLCommand::UniformMatrix2fv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform_matrix_3fv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ transpose: bool,
+ val: Float32ArrayOrUnrestrictedFloatSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::FLOAT_MAT3 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val =
+ self.uniform_matrix_section(val, src_offset, src_length, transpose, 9, location)?;
+ self.send_command(WebGLCommand::UniformMatrix3fv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn uniform_matrix_4fv(
+ &self,
+ location: Option<&WebGLUniformLocation>,
+ transpose: bool,
+ val: Float32ArrayOrUnrestrictedFloatSequence,
+ src_offset: u32,
+ src_length: u32,
+ ) {
+ self.with_location(location, |location| {
+ match location.type_() {
+ constants::FLOAT_MAT4 => {},
+ _ => return Err(InvalidOperation),
+ }
+ let val =
+ self.uniform_matrix_section(val, src_offset, src_length, transpose, 16, location)?;
+ self.send_command(WebGLCommand::UniformMatrix4fv(location.id(), val));
+ Ok(())
+ });
+ }
+
+ pub fn get_buffer_param(&self, buffer: Option<DomRoot<WebGLBuffer>>, parameter: u32) -> JSVal {
+ let buffer =
+ handle_potential_webgl_error!(self, buffer.ok_or(InvalidOperation), return NullValue());
+
+ match parameter {
+ constants::BUFFER_SIZE => Int32Value(buffer.capacity() as i32),
+ constants::BUFFER_USAGE => Int32Value(buffer.usage() as i32),
+ _ => {
+ self.webgl_error(InvalidEnum);
+ NullValue()
+ },
+ }
+ }
}
#[cfg(not(feature = "webgl_backtrace"))]
@@ -1594,21 +1948,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn GetBufferParameter(&self, _cx: SafeJSContext, target: u32, parameter: u32) -> JSVal {
- let buffer = handle_potential_webgl_error!(
- self,
- self.bound_buffer(target)
- .and_then(|buf| buf.ok_or(InvalidOperation)),
- return NullValue()
- );
-
- match parameter {
- constants::BUFFER_SIZE => Int32Value(buffer.capacity() as i32),
- constants::BUFFER_USAGE => Int32Value(buffer.usage() as i32),
- _ => {
- self.webgl_error(InvalidEnum);
- NullValue()
- },
- }
+ let buffer =
+ handle_potential_webgl_error!(self, self.bound_buffer(target), return NullValue());
+ self.get_buffer_param(buffer, parameter)
}
#[allow(unsafe_code)]
@@ -2110,14 +2452,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- fn BufferData(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
+ fn BufferData_(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
let usage = handle_potential_webgl_error!(self, self.buffer_usage(usage), return);
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
self.buffer_data(target, data, usage, bound_buffer)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- fn BufferData_(&self, target: u32, size: i64, usage: u32) {
+ fn BufferData(&self, target: u32, size: i64, usage: u32) {
let usage = handle_potential_webgl_error!(self, self.buffer_usage(usage), return);
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
self.buffer_data_(target, size, usage, bound_buffer)
@@ -2142,55 +2484,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
border: i32,
data: CustomAutoRooterGuard<ArrayBufferView>,
) {
- let validator = CompressedTexImage2DValidator::new(
- self,
- target,
- level,
- width,
- height,
- border,
- internal_format,
- data.len(),
- );
- let CommonCompressedTexImage2DValidatorResult {
- texture,
- target,
- level,
- width,
- height,
- compression,
- } = match validator.validate() {
- Ok(result) => result,
- Err(_) => return,
- };
-
- let buff = IpcSharedMemory::from_bytes(unsafe { data.as_slice() });
- let pixels = TexPixels::from_array(buff, Size2D::new(width, height));
-
- handle_potential_webgl_error!(
- self,
- texture.initialize(
- target,
- pixels.size.width,
- pixels.size.height,
- 1,
- compression.format,
- level,
- Some(TexDataType::UnsignedByte)
- )
- );
-
- self.send_command(WebGLCommand::CompressedTexImage2D {
- target: target.as_gl_constant(),
- level,
- internal_format,
- size: Size2D::new(width, height),
- data: pixels.data.into(),
- });
-
- if let Some(fb) = self.bound_draw_framebuffer.get() {
- fb.invalidate_texture(&*texture);
- }
+ let data = unsafe { data.as_slice() };
+ self.compressed_tex_image_2d(target, level, internal_format, width, height, border, data)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
@@ -2206,41 +2501,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
format: u32,
data: CustomAutoRooterGuard<ArrayBufferView>,
) {
- let validator = CompressedTexSubImage2DValidator::new(
- self,
- target,
- level,
- xoffset,
- yoffset,
- width,
- height,
- format,
- data.len(),
- );
- let CommonCompressedTexImage2DValidatorResult {
- texture: _,
- target,
- level,
- width,
- height,
- ..
- } = match validator.validate() {
- Ok(result) => result,
- Err(_) => return,
- };
-
- let buff = IpcSharedMemory::from_bytes(unsafe { data.as_slice() });
- let pixels = TexPixels::from_array(buff, Size2D::new(width, height));
-
- self.send_command(WebGLCommand::CompressedTexSubImage2D {
- target: target.as_gl_constant(),
- level: level as i32,
- xoffset,
- yoffset,
- size: Size2D::new(width, height),
- format,
- data: pixels.data.into(),
- });
+ let data = unsafe { data.as_slice() };
+ self.compressed_tex_sub_image_2d(
+ target, level, xoffset, yoffset, width, height, format, data,
+ )
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
@@ -2583,9 +2847,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
.map_or(false, |b| buffer == &*b)
{
self.bound_buffer_array.set(None);
- buffer.decrement_attached_counter(false);
+ buffer.decrement_attached_counter(Operation::Infallible);
}
- buffer.mark_for_deletion(false);
+ buffer.mark_for_deletion(Operation::Infallible);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6
@@ -2605,7 +2869,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
WebGLFramebufferBindingRequest::Default
))
);
- framebuffer.delete(false)
+ framebuffer.delete(Operation::Infallible)
}
}
@@ -2622,7 +2886,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
None
))
);
- renderbuffer.delete(false)
+ renderbuffer.delete(Operation::Infallible)
}
}
@@ -2657,7 +2921,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
));
}
- texture.delete(false)
+ texture.delete(Operation::Infallible)
}
}
@@ -2665,7 +2929,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
fn DeleteProgram(&self, program: Option<&WebGLProgram>) {
if let Some(program) = program {
handle_potential_webgl_error!(self, self.validate_ownership(program), return);
- program.mark_for_deletion(false)
+ program.mark_for_deletion(Operation::Infallible)
}
}
@@ -2673,7 +2937,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
fn DeleteShader(&self, shader: Option<&WebGLShader>) {
if let Some(shader) = shader {
handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
- shader.mark_for_deletion(false)
+ shader.mark_for_deletion(Operation::Infallible)
}
}
@@ -3548,40 +3812,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
- fn Uniform1iv(
- &self,
- location: Option<&WebGLUniformLocation>,
- val: Int32ArrayOrLongSequence,
- src_offset: u32,
- src_length: u32,
- ) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::BOOL |
- constants::INT |
- constants::SAMPLER_2D |
- constants::SAMPLER_CUBE => {},
- _ => return Err(InvalidOperation),
- }
-
- let val = self.uniform_vec_section_int(val, src_offset, src_length, 1, location)?;
-
- match location.type_() {
- constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
- for &v in val
- .iter()
- .take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
- {
- if v < 0 || v as u32 >= self.limits.max_combined_texture_image_units {
- return Err(InvalidValue);
- }
- }
- },
- _ => {},
- }
- self.send_command(WebGLCommand::Uniform1iv(location.id(), val));
- Ok(())
- });
+ fn Uniform1iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
+ self.uniform1iv(location, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3589,18 +3821,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
location: Option<&WebGLUniformLocation>,
val: Float32ArrayOrUnrestrictedFloatSequence,
- src_offset: u32,
- src_length: u32,
) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::BOOL | constants::FLOAT => {},
- _ => return Err(InvalidOperation),
- }
- let val = self.uniform_vec_section_float(val, src_offset, src_length, 1, location)?;
- self.send_command(WebGLCommand::Uniform1fv(location.id(), val));
- Ok(())
- });
+ self.uniform1fv(location, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3620,18 +3842,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
location: Option<&WebGLUniformLocation>,
val: Float32ArrayOrUnrestrictedFloatSequence,
- src_offset: u32,
- src_length: u32,
) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {},
- _ => return Err(InvalidOperation),
- }
- let val = self.uniform_vec_section_float(val, src_offset, src_length, 2, location)?;
- self.send_command(WebGLCommand::Uniform2fv(location.id(), val));
- Ok(())
- });
+ self.uniform2fv(location, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3647,22 +3859,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
- fn Uniform2iv(
- &self,
- location: Option<&WebGLUniformLocation>,
- val: Int32ArrayOrLongSequence,
- src_offset: u32,
- src_length: u32,
- ) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::BOOL_VEC2 | constants::INT_VEC2 => {},
- _ => return Err(InvalidOperation),
- }
- let val = self.uniform_vec_section_int(val, src_offset, src_length, 2, location)?;
- self.send_command(WebGLCommand::Uniform2iv(location.id(), val));
- Ok(())
- });
+ fn Uniform2iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
+ self.uniform2iv(location, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3682,18 +3880,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
location: Option<&WebGLUniformLocation>,
val: Float32ArrayOrUnrestrictedFloatSequence,
- src_offset: u32,
- src_length: u32,
) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {},
- _ => return Err(InvalidOperation),
- }
- let val = self.uniform_vec_section_float(val, src_offset, src_length, 3, location)?;
- self.send_command(WebGLCommand::Uniform3fv(location.id(), val));
- Ok(())
- });
+ self.uniform3fv(location, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3709,22 +3897,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
- fn Uniform3iv(
- &self,
- location: Option<&WebGLUniformLocation>,
- val: Int32ArrayOrLongSequence,
- src_offset: u32,
- src_length: u32,
- ) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::BOOL_VEC3 | constants::INT_VEC3 => {},
- _ => return Err(InvalidOperation),
- }
- let val = self.uniform_vec_section_int(val, src_offset, src_length, 3, location)?;
- self.send_command(WebGLCommand::Uniform3iv(location.id(), val));
- Ok(())
- });
+ fn Uniform3iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
+ self.uniform3iv(location, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3740,22 +3914,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
- fn Uniform4iv(
- &self,
- location: Option<&WebGLUniformLocation>,
- val: Int32ArrayOrLongSequence,
- src_offset: u32,
- src_length: u32,
- ) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::BOOL_VEC4 | constants::INT_VEC4 => {},
- _ => return Err(InvalidOperation),
- }
- let val = self.uniform_vec_section_int(val, src_offset, src_length, 4, location)?;
- self.send_command(WebGLCommand::Uniform4iv(location.id(), val));
- Ok(())
- });
+ fn Uniform4iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
+ self.uniform4iv(location, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3775,18 +3935,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
location: Option<&WebGLUniformLocation>,
val: Float32ArrayOrUnrestrictedFloatSequence,
- src_offset: u32,
- src_length: u32,
) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {},
- _ => return Err(InvalidOperation),
- }
- let val = self.uniform_vec_section_float(val, src_offset, src_length, 4, location)?;
- self.send_command(WebGLCommand::Uniform4fv(location.id(), val));
- Ok(())
- });
+ self.uniform4fv(location, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3795,19 +3945,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
location: Option<&WebGLUniformLocation>,
transpose: bool,
val: Float32ArrayOrUnrestrictedFloatSequence,
- src_offset: u32,
- src_length: u32,
) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::FLOAT_MAT2 => {},
- _ => return Err(InvalidOperation),
- }
- let val =
- self.uniform_matrix_section(val, src_offset, src_length, transpose, 4, location)?;
- self.send_command(WebGLCommand::UniformMatrix2fv(location.id(), val));
- Ok(())
- });
+ self.uniform_matrix_2fv(location, transpose, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3816,19 +3955,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
location: Option<&WebGLUniformLocation>,
transpose: bool,
val: Float32ArrayOrUnrestrictedFloatSequence,
- src_offset: u32,
- src_length: u32,
) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::FLOAT_MAT3 => {},
- _ => return Err(InvalidOperation),
- }
- let val =
- self.uniform_matrix_section(val, src_offset, src_length, transpose, 9, location)?;
- self.send_command(WebGLCommand::UniformMatrix3fv(location.id(), val));
- Ok(())
- });
+ self.uniform_matrix_3fv(location, transpose, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -3837,19 +3965,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
location: Option<&WebGLUniformLocation>,
transpose: bool,
val: Float32ArrayOrUnrestrictedFloatSequence,
- src_offset: u32,
- src_length: u32,
) {
- self.with_location(location, |location| {
- match location.type_() {
- constants::FLOAT_MAT4 => {},
- _ => return Err(InvalidOperation),
- }
- let val =
- self.uniform_matrix_section(val, src_offset, src_length, transpose, 16, location)?;
- self.send_command(WebGLCommand::UniformMatrix4fv(location.id(), val));
- Ok(())
- });
+ self.uniform_matrix_4fv(location, transpose, val, 0, 0)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -4055,7 +4172,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
target: u32,
level: i32,
- internal_format: u32,
+ internal_format: i32,
width: i32,
height: i32,
border: i32,
@@ -4071,7 +4188,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self,
target,
level,
- internal_format,
+ internal_format as u32,
width,
height,
border,
@@ -4153,7 +4270,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
target: u32,
level: i32,
- internal_format: u32,
+ internal_format: i32,
format: u32,
data_type: u32,
source: TexImageSource,
@@ -4171,7 +4288,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self,
target,
level,
- internal_format,
+ internal_format as u32,
pixels.size.width as i32,
pixels.size.height as i32,
0,
diff --git a/components/script/dom/webglsampler.rs b/components/script/dom/webglsampler.rs
index c80e2a6a508..063decffe8f 100644
--- a/components/script/dom/webglsampler.rs
+++ b/components/script/dom/webglsampler.rs
@@ -7,7 +7,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLSamplerId};
use dom_struct::dom_struct;
@@ -90,16 +90,15 @@ impl WebGLSampler {
)
}
- pub fn delete(&self, fallible: bool) {
+ pub fn delete(&self, operation_fallibility: Operation) {
if !self.marked_for_deletion.get() {
self.marked_for_deletion.set(true);
let command = WebGLCommand::DeleteSampler(self.gl_id);
let context = self.upcast::<WebGLObject>().context();
- if fallible {
- context.send_command_ignored(command);
- } else {
- context.send_command(command);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(command),
+ Operation::Infallible => context.send_command(command),
}
}
}
@@ -180,6 +179,6 @@ impl WebGLSampler {
impl Drop for WebGLSampler {
fn drop(&mut self) {
- self.delete(true);
+ self.delete(Operation::Fallible);
}
}
diff --git a/components/script/dom/webglshader.rs b/components/script/dom/webglshader.rs
index 9be334f6595..0e2a8253968 100644
--- a/components/script/dom/webglshader.rs
+++ b/components/script/dom/webglshader.rs
@@ -12,7 +12,7 @@ use crate::dom::webgl_extensions::ext::extshadertexturelod::EXTShaderTextureLod;
use crate::dom::webgl_extensions::ext::oesstandardderivatives::OESStandardDerivatives;
use crate::dom::webgl_extensions::WebGLExtensions;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::{webgl_channel, GlType, WebGLVersion};
use canvas_traits::webgl::{GLLimits, WebGLCommand, WebGLError};
use canvas_traits::webgl::{WebGLResult, WebGLSLVersion, WebGLShaderId};
@@ -344,15 +344,14 @@ impl WebGLShader {
/// Mark this shader as deleted (if it wasn't previously)
/// and delete it as if calling glDeleteShader.
/// Currently does not check if shader is attached
- pub fn mark_for_deletion(&self, fallible: bool) {
+ pub fn mark_for_deletion(&self, operation_fallibility: Operation) {
if !self.marked_for_deletion.get() {
self.marked_for_deletion.set(true);
let context = self.upcast::<WebGLObject>().context();
let cmd = WebGLCommand::DeleteShader(self.id);
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(cmd),
+ Operation::Infallible => context.send_command(cmd),
}
}
}
@@ -400,6 +399,6 @@ impl WebGLShader {
impl Drop for WebGLShader {
fn drop(&mut self) {
- self.mark_for_deletion(true);
+ self.mark_for_deletion(Operation::Fallible);
}
}
diff --git a/components/script/dom/webglsync.rs b/components/script/dom/webglsync.rs
index dd6acb5be9a..a6288f69c1e 100644
--- a/components/script/dom/webglsync.rs
+++ b/components/script/dom/webglsync.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use crate::task_source::TaskSource;
use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLSyncId};
use dom_struct::dom_struct;
@@ -82,15 +82,14 @@ impl WebGLSync {
self.client_wait_status.get()
}
- pub fn delete(&self, fallible: bool) {
+ pub fn delete(&self, operation_fallibility: Operation) {
if self.is_valid() {
self.marked_for_deletion.set(true);
let context = self.upcast::<WebGLObject>().context();
let cmd = WebGLCommand::DeleteSync(self.sync_id);
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(cmd),
+ Operation::Infallible => context.send_command(cmd),
}
}
}
@@ -131,6 +130,6 @@ impl WebGLSync {
impl Drop for WebGLSync {
fn drop(&mut self) {
- self.delete(true);
+ self.delete(Operation::Fallible);
}
}
diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs
index 682920df96e..3059dc7bf4e 100644
--- a/components/script/dom/webgltexture.rs
+++ b/components/script/dom/webgltexture.rs
@@ -13,7 +13,7 @@ use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::webgl_validations::types::TexImageTarget;
use crate::dom::webglframebuffer::WebGLFramebuffer;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::{webgl_channel, TexDataType, TexFormat, WebGLResult, WebGLTextureId};
use canvas_traits::webgl::{DOMToTextureCommand, WebGLCommand, WebGLError};
use dom_struct::dom_struct;
@@ -183,7 +183,7 @@ impl WebGLTexture {
self.populate_mip_chain(self.base_mipmap_level, last_level)
}
- pub fn delete(&self, fallible: bool) {
+ pub fn delete(&self, operation_fallibility: Operation) {
if !self.is_deleted.get() {
self.is_deleted.set(true);
let context = self.upcast::<WebGLObject>().context();
@@ -210,10 +210,9 @@ impl WebGLTexture {
}
let cmd = WebGLCommand::DeleteTexture(self.id);
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(cmd),
+ Operation::Infallible => context.send_command(cmd),
}
}
}
@@ -420,7 +419,7 @@ impl WebGLTexture {
impl Drop for WebGLTexture {
fn drop(&mut self) {
- self.delete(true);
+ self.delete(Operation::Fallible);
}
}
diff --git a/components/script/dom/webgltransformfeedback.rs b/components/script/dom/webgltransformfeedback.rs
index fe4b0753843..3b0b2abf0a2 100644
--- a/components/script/dom/webgltransformfeedback.rs
+++ b/components/script/dom/webgltransformfeedback.rs
@@ -6,7 +6,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::{webgl_channel, WebGLCommand};
use dom_struct::dom_struct;
use std::cell::Cell;
@@ -98,15 +98,14 @@ impl WebGLTransformFeedback {
self.is_paused.get()
}
- pub fn delete(&self, fallible: bool) {
+ pub fn delete(&self, operation_fallibility: Operation) {
if self.is_valid() && self.id() != 0 {
self.marked_for_deletion.set(true);
let context = self.upcast::<WebGLObject>().context();
let cmd = WebGLCommand::DeleteTransformFeedback(self.id);
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
+ match operation_fallibility {
+ Operation::Fallible => context.send_command_ignored(cmd),
+ Operation::Infallible => context.send_command(cmd),
}
}
}
@@ -126,6 +125,6 @@ impl WebGLTransformFeedback {
impl Drop for WebGLTransformFeedback {
fn drop(&mut self) {
- self.delete(true);
+ self.delete(Operation::Fallible);
}
}
diff --git a/components/script/dom/webglvertexarrayobject.rs b/components/script/dom/webglvertexarrayobject.rs
index b425a7c4219..07f53af0316 100644
--- a/components/script/dom/webglvertexarrayobject.rs
+++ b/components/script/dom/webglvertexarrayobject.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::vertexarrayobject::{VertexArrayObject, VertexAttribData};
use crate::dom::webglbuffer::WebGLBuffer;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::{ActiveAttribInfo, WebGLResult, WebGLVertexArrayId};
use dom_struct::dom_struct;
@@ -41,8 +41,8 @@ impl WebGLVertexArrayObject {
self.array_object.is_deleted()
}
- pub fn delete(&self, fallible: bool) {
- self.array_object.delete(fallible);
+ pub fn delete(&self, operation_fallibility: Operation) {
+ self.array_object.delete(operation_fallibility);
}
pub fn ever_bound(&self) -> bool {
diff --git a/components/script/dom/webglvertexarrayobjectoes.rs b/components/script/dom/webglvertexarrayobjectoes.rs
index f10c10d949b..215d39c1a5a 100644
--- a/components/script/dom/webglvertexarrayobjectoes.rs
+++ b/components/script/dom/webglvertexarrayobjectoes.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::vertexarrayobject::{VertexArrayObject, VertexAttribData};
use crate::dom::webglbuffer::WebGLBuffer;
use crate::dom::webglobject::WebGLObject;
-use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use canvas_traits::webgl::{ActiveAttribInfo, WebGLResult, WebGLVertexArrayId};
use dom_struct::dom_struct;
@@ -41,8 +41,8 @@ impl WebGLVertexArrayObjectOES {
self.array_object.is_deleted()
}
- pub fn delete(&self, fallible: bool) {
- self.array_object.delete(fallible);
+ pub fn delete(&self, operation_fallibility: Operation) {
+ self.array_object.delete(operation_fallibility);
}
pub fn ever_bound(&self) -> bool {
diff --git a/components/script/dom/webidls/ElementContentEditable.webidl b/components/script/dom/webidls/ElementContentEditable.webidl
index ba7966c225d..8429700e93e 100644
--- a/components/script/dom/webidls/ElementContentEditable.webidl
+++ b/components/script/dom/webidls/ElementContentEditable.webidl
@@ -5,7 +5,7 @@
// https://html.spec.whatwg.org/multipage/#elementcontenteditable
[Exposed=Window]
interface mixin ElementContentEditable {
- // [CEReactions]
- // attribute DOMString contentEditable;
- // readonly attribute boolean isContentEditable;
+ [CEReactions]
+ attribute DOMString contentEditable;
+ readonly attribute boolean isContentEditable;
};
diff --git a/components/script/dom/webidls/EventHandler.webidl b/components/script/dom/webidls/EventHandler.webidl
index 99be904979b..a3514182806 100644
--- a/components/script/dom/webidls/EventHandler.webidl
+++ b/components/script/dom/webidls/EventHandler.webidl
@@ -92,7 +92,9 @@ interface mixin GlobalEventHandlers {
// https://drafts.csswg.org/css-transitions/#interface-globaleventhandlers-idl
partial interface mixin GlobalEventHandlers {
+ attribute EventHandler ontransitionrun;
attribute EventHandler ontransitionend;
+ attribute EventHandler ontransitioncancel;
};
// https://w3c.github.io/selection-api/#extensions-to-globaleventhandlers-interface
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index f6278370cce..926d42292a2 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -286,17 +286,6 @@ interface mixin WebGL2RenderingContextBase
const GLenum MAX_CLIENT_WAIT_TIMEOUT_WEBGL = 0x9247;
/* Buffer objects */
- // WebGL1:
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- void bufferData(GLenum target, /*[AllowShared]*/ BufferSource? data, GLenum usage);
- void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
- void bufferSubData(GLenum target, GLintptr dstByteOffset, /*[AllowShared]*/ BufferSource srcData);
- // WebGL2:
- void bufferData(GLenum target, /*[AllowShared]*/ ArrayBufferView srcData, GLenum usage, GLuint srcOffset,
- optional GLuint length = 0);
- void bufferSubData(GLenum target, GLintptr dstByteOffset, /*[AllowShared]*/ ArrayBufferView srcData,
- GLuint srcOffset, optional GLuint length = 0);
-
void copyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset,
GLintptr writeOffset, GLsizeiptr size);
// MapBufferRange, in particular its read-only and write-only modes,
@@ -326,96 +315,51 @@ interface mixin WebGL2RenderingContextBase
// void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
// GLsizei height, GLsizei depth);
- // WebGL1 legacy entrypoints:
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- [Throws]
- void texImage2D(GLenum target, GLint level, GLenum internalformat,
- GLsizei width, GLsizei height, GLint border, GLenum format,
- GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
- [Throws]
- void texImage2D(GLenum target, GLint level, GLenum internalformat,
- GLenum format, GLenum type, TexImageSource source); // May throw DOMException
-
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- [Throws]
- void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
- [Throws]
- void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- GLenum format, GLenum type, TexImageSource source); // May throw DOMException
-
- // WebGL2 entrypoints:
- // void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
- // GLint border, GLenum format, GLenum type, GLintptr pboOffset);
- // void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
- // GLint border, GLenum format, GLenum type,
- // TexImageSource source); // May throw DOMException
- // void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
- // GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData,
- // GLuint srcOffset);
-
- // void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
- // GLsizei depth, GLint border, GLenum format, GLenum type, GLintptr pboOffset);
- // void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
- // GLsizei depth, GLint border, GLenum format, GLenum type,
- // TexImageSource source); // May throw DOMException
- // void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
- // GLsizei depth, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView? srcData);
- // void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
- // GLsizei depth, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData,
- // GLuint srcOffset);
-
- // void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
- // GLsizei height, GLenum format, GLenum type, GLintptr pboOffset);
- // void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
- // GLsizei height, GLenum format, GLenum type,
- // TexImageSource source); // May throw DOMException
- // void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
- // GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData,
- // GLuint srcOffset);
-
- // void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- // GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
- // GLintptr pboOffset);
- // void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- // GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
- // TexImageSource source); // May throw DOMException
- // void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- // GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
- // [AllowShared] ArrayBufferView? srcData, optional GLuint srcOffset = 0);
-
- // void copyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- // GLint x, GLint y, GLsizei width, GLsizei height);
-
- // void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
- // GLsizei height, GLint border, GLsizei imageSize, GLintptr offset);
- // void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
- // GLsizei height, GLint border, [AllowShared] ArrayBufferView srcData,
- // optional GLuint srcOffset = 0, optional GLuint srcLengthOverride = 0);
-
- // void compressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
- // GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLintptr offset);
- // void compressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
- // GLsizei height, GLsizei depth, GLint border, [AllowShared] ArrayBufferView srcData,
- // optional GLuint srcOffset = 0, optional GLuint srcLengthOverride = 0);
-
- // void compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- // GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLintptr offset);
- // void compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- // GLsizei width, GLsizei height, GLenum format,
- // [AllowShared] ArrayBufferView srcData,
- // optional GLuint srcOffset = 0,
- // optional GLuint srcLengthOverride = 0);
-
- // void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- // GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
- // GLenum format, GLsizei imageSize, GLintptr offset);
- // void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- // GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
- // GLenum format, [AllowShared] ArrayBufferView srcData,
- // optional GLuint srcOffset = 0,
- // optional GLuint srcLengthOverride = 0);
+ //[Throws]
+ //void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ // GLsizei depth, GLint border, GLenum format, GLenum type, GLintptr pboOffset);
+ //[Throws]
+ //void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ // GLsizei depth, GLint border, GLenum format, GLenum type,
+ // TexImageSource source); // May throw DOMException
+ //[Throws]
+ //void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ // GLsizei depth, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView? srcData);
+ //[Throws]
+ //void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ // GLsizei depth, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData,
+ // GLuint srcOffset);
+
+ //[Throws]
+ //void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+ // GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
+ // GLintptr pboOffset);
+ //[Throws]
+ //void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+ // GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
+ // TexImageSource source); // May throw DOMException
+ //[Throws]
+ //void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+ // GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
+ // [AllowShared] ArrayBufferView? srcData, optional GLuint srcOffset = 0);
+
+ //void copyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+ // GLint x, GLint y, GLsizei width, GLsizei height);
+
+ //void compressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ // GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLintptr offset);
+ //void compressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ // GLsizei height, GLsizei depth, GLint border, [AllowShared] ArrayBufferView srcData,
+ // optional GLuint srcOffset = 0, optional GLuint srcLengthOverride = 0);
+
+ //void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ // GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
+ // GLenum format, GLsizei imageSize, GLintptr offset);
+ //void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ // GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
+ // GLenum format, [AllowShared] ArrayBufferView srcData,
+ // optional GLuint srcOffset = 0,
+ // optional GLuint srcLengthOverride = 0);
/* Programs and shaders */
[WebGLHandlesContextLoss] GLint getFragDataLocation(WebGLProgram program, DOMString name);
@@ -463,17 +407,6 @@ interface mixin WebGL2RenderingContextBase
void drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount);
void drawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLintptr offset);
- /* Reading back pixels */
- // WebGL1:
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
- /*[AllowShared]*/ ArrayBufferView? dstData);
- // WebGL2:
- void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
- GLintptr offset);
- void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
- /*[AllowShared]*/ ArrayBufferView dstData, GLuint dstOffset);
-
/* Multiple Render Targets */
void drawBuffers(sequence<GLenum> buffers);
@@ -542,9 +475,114 @@ interface mixin WebGL2RenderingContextBase
void bindVertexArray(WebGLVertexArrayObject? array);
};
+interface mixin WebGL2RenderingContextOverloads
+{
+ // WebGL1:
+ void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
+ void bufferData(GLenum target, /*[AllowShared]*/ BufferSource? srcData, GLenum usage);
+ void bufferSubData(GLenum target, GLintptr dstByteOffset, /*[AllowShared]*/ BufferSource srcData);
+ // WebGL2:
+ void bufferData(GLenum target, /*[AllowShared]*/ ArrayBufferView srcData, GLenum usage, GLuint srcOffset,
+ optional GLuint length = 0);
+ void bufferSubData(GLenum target, GLintptr dstByteOffset, /*[AllowShared]*/ ArrayBufferView srcData,
+ GLuint srcOffset, optional GLuint length = 0);
+
+ // WebGL1 legacy entrypoints:
+ [Throws]
+ void texImage2D(GLenum target, GLint level, GLint internalformat,
+ GLsizei width, GLsizei height, GLint border, GLenum format,
+ GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
+ [Throws]
+ void texImage2D(GLenum target, GLint level, GLint internalformat,
+ GLenum format, GLenum type, TexImageSource source); // May throw DOMException
+
+ [Throws]
+ void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
+ [Throws]
+ void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLenum format, GLenum type, TexImageSource source); // May throw DOMException
+
+ // WebGL2 entrypoints:
+ //[Throws]
+ //void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ // GLint border, GLenum format, GLenum type, GLintptr pboOffset);
+ //[Throws]
+ //void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ // GLint border, GLenum format, GLenum type,
+ // TexImageSource source); // May throw DOMException
+ //[Throws]
+ //void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ // GLint border, GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView srcData,
+ // GLuint srcOffset);
+
+ //[Throws]
+ //void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ // GLsizei height, GLenum format, GLenum type, GLintptr pboOffset);
+ //[Throws]
+ //void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ // GLsizei height, GLenum format, GLenum type,
+ // TexImageSource source); // May throw DOMException
+ //[Throws]
+ //void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ // GLsizei height, GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView srcData,
+ // GLuint srcOffset);
+
+ //void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ // GLsizei height, GLint border, GLsizei imageSize, GLintptr offset);
+ void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, /*[AllowShared]*/ ArrayBufferView srcData,
+ optional GLuint srcOffset = 0, optional GLuint srcLengthOverride = 0);
+
+ //void compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ // GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLintptr offset);
+ void compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format,
+ /*[AllowShared]*/ ArrayBufferView srcData,
+ optional GLuint srcOffset = 0,
+ optional GLuint srcLengthOverride = 0);
+
+ void uniform1fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0,
+ optional GLuint srcLength = 0);
+ void uniform2fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0,
+ optional GLuint srcLength = 0);
+ void uniform3fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0,
+ optional GLuint srcLength = 0);
+ void uniform4fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0,
+ optional GLuint srcLength = 0);
+
+ void uniform1iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0,
+ optional GLuint srcLength = 0);
+ void uniform2iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0,
+ optional GLuint srcLength = 0);
+ void uniform3iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0,
+ optional GLuint srcLength = 0);
+ void uniform4iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0,
+ optional GLuint srcLength = 0);
+
+ void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data,
+ optional GLuint srcOffset = 0, optional GLuint srcLength = 0);
+ void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data,
+ optional GLuint srcOffset = 0, optional GLuint srcLength = 0);
+ void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data,
+ optional GLuint srcOffset = 0, optional GLuint srcLength = 0);
+
+ /* Reading back pixels */
+ // WebGL1:
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ /*[AllowShared]*/ ArrayBufferView? dstData);
+ // WebGL2:
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLintptr offset);
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ /*[AllowShared]*/ ArrayBufferView dstData, GLuint dstOffset);
+};
+
[Exposed=Window, Func="WebGL2RenderingContext::is_webgl2_enabled"]
interface WebGL2RenderingContext
{
};
WebGL2RenderingContext includes WebGLRenderingContextBase;
WebGL2RenderingContext includes WebGL2RenderingContextBase;
+WebGL2RenderingContext includes WebGL2RenderingContextOverloads;
diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl
index a9af389b042..ac00757ef3f 100644
--- a/components/script/dom/webidls/WebGLRenderingContext.webidl
+++ b/components/script/dom/webidls/WebGLRenderingContext.webidl
@@ -421,8 +421,6 @@ interface mixin WebGLRenderingContextBase
const GLenum RGB5_A1 = 0x8057;
const GLenum RGB565 = 0x8D62;
const GLenum DEPTH_COMPONENT16 = 0x81A5;
- // https://github.com/KhronosGroup/WebGL/pull/2371
- // const GLenum STENCIL_INDEX = 0x1901;
const GLenum STENCIL_INDEX8 = 0x8D48;
const GLenum DEPTH_STENCIL = 0x84F9;
@@ -492,11 +490,6 @@ interface mixin WebGLRenderingContextBase
void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
GLenum srcAlpha, GLenum dstAlpha);
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- // void bufferData(GLenum target, object? data, GLenum usage);
- // void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
- // void bufferSubData(GLenum target, GLintptr offset, /*[AllowShared]*/ BufferSource data);
-
[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
void clear(GLbitfield mask);
void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
@@ -505,14 +498,6 @@ interface mixin WebGLRenderingContextBase
void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
void compileShader(WebGLShader shader);
- void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
- GLsizei width, GLsizei height, GLint border,
- /*[AllowShared]*/ ArrayBufferView data);
- void compressedTexSubImage2D(GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLsizei width, GLsizei height, GLenum format,
- /*[AllowShared]*/ ArrayBufferView data);
-
void copyTexImage2D(GLenum target, GLint level, GLenum internalformat,
GLint x, GLint y, GLsizei width, GLsizei height,
GLint border);
@@ -602,10 +587,6 @@ interface mixin WebGLRenderingContextBase
void pixelStorei(GLenum pname, GLint param);
void polygonOffset(GLfloat factor, GLfloat units);
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- // void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
- // GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
-
void renderbufferStorage(GLenum target, GLenum internalformat,
GLsizei width, GLsizei height);
void sampleCoverage(GLclampf value, GLboolean invert);
@@ -620,26 +601,9 @@ interface mixin WebGLRenderingContextBase
void stencilOp(GLenum fail, GLenum zfail, GLenum zpass);
void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- // void texImage2D(GLenum target, GLint level, GLenum internalformat,
- // GLsizei width, GLsizei height, GLint border, GLenum format,
- // GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
- // void texImage2D(GLenum target, GLint level, GLenum internalformat,
- // GLenum format, GLenum type, TexImageSource source); // May throw DOMException
- [Throws, Pref="dom.webgl.dom_to_texture.enabled"]
- void texImageDOM(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
- GLenum format, GLenum type, HTMLIFrameElement source); // May throw DOMException
-
void texParameterf(GLenum target, GLenum pname, GLfloat param);
void texParameteri(GLenum target, GLenum pname, GLint param);
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- // void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- // GLsizei width, GLsizei height,
- // GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
- // void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- // GLenum format, GLenum type, TexImageSource source); // May throw DOMException
-
void uniform1f(WebGLUniformLocation? location, GLfloat x);
void uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y);
void uniform3f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z);
@@ -650,31 +614,6 @@ interface mixin WebGLRenderingContextBase
void uniform3i(WebGLUniformLocation? location, GLint x, GLint y, GLint z);
void uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w);
- void uniform1fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0,
- optional GLuint srcLength = 0);
- void uniform2fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0,
- optional GLuint srcLength = 0);
- void uniform3fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0,
- optional GLuint srcLength = 0);
- void uniform4fv(WebGLUniformLocation? location, Float32List data, optional GLuint srcOffset = 0,
- optional GLuint srcLength = 0);
-
- void uniform1iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0,
- optional GLuint srcLength = 0);
- void uniform2iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0,
- optional GLuint srcLength = 0);
- void uniform3iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0,
- optional GLuint srcLength = 0);
- void uniform4iv(WebGLUniformLocation? location, Int32List data, optional GLuint srcOffset = 0,
- optional GLuint srcLength = 0);
-
- void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data,
- optional GLuint srcOffset = 0, optional GLuint srcLength = 0);
- void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data,
- optional GLuint srcOffset = 0, optional GLuint srcLength = 0);
- void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data,
- optional GLuint srcOffset = 0, optional GLuint srcLength = 0);
-
void useProgram(WebGLProgram? program);
void validateProgram(WebGLProgram program);
@@ -694,34 +633,64 @@ interface mixin WebGLRenderingContextBase
void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
};
-[Exposed=Window]
-interface WebGLRenderingContext
+interface mixin WebGLRenderingContextOverloads
{
- // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
-
- void bufferData(GLenum target, /*[AllowShared]*/ BufferSource? data, GLenum usage);
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
+ void bufferData(GLenum target, /*[AllowShared]*/ BufferSource? data, GLenum usage);
void bufferSubData(GLenum target, GLintptr offset, /*[AllowShared]*/ BufferSource data);
- // FIXME: https://github.com/servo/servo/issues/20516
+ void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ /*[AllowShared]*/ ArrayBufferView data);
+ void compressedTexSubImage2D(GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format,
+ /*[AllowShared]*/ ArrayBufferView data);
+
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
+
[Throws]
- void texImage2D(GLenum target, GLint level, GLenum internalformat,
+ void texImage2D(GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border, GLenum format,
GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
[Throws]
- void texImage2D(GLenum target, GLint level, GLenum internalformat,
+ void texImage2D(GLenum target, GLint level, GLint internalformat,
GLenum format, GLenum type, TexImageSource source); // May throw DOMException
- // FIXME: https://github.com/servo/servo/issues/20516
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, TexImageSource source); // May throw DOMException
- void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
+ void uniform1fv(WebGLUniformLocation? location, Float32List v);
+ void uniform2fv(WebGLUniformLocation? location, Float32List v);
+ void uniform3fv(WebGLUniformLocation? location, Float32List v);
+ void uniform4fv(WebGLUniformLocation? location, Float32List v);
+
+ void uniform1iv(WebGLUniformLocation? location, Int32List v);
+ void uniform2iv(WebGLUniformLocation? location, Int32List v);
+ void uniform3iv(WebGLUniformLocation? location, Int32List v);
+ void uniform4iv(WebGLUniformLocation? location, Int32List v);
+
+ void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
+ void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
+ void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
+};
+
+interface mixin WebGLRenderingContextExtensions {
+ [Throws, Pref="dom.webgl.dom_to_texture.enabled"]
+ void texImageDOM(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, HTMLIFrameElement source); // May throw DOMException
+};
+
+[Exposed=(Window)]
+interface WebGLRenderingContext
+{
};
WebGLRenderingContext includes WebGLRenderingContextBase;
+WebGLRenderingContext includes WebGLRenderingContextOverloads;
+WebGLRenderingContext includes WebGLRenderingContextExtensions;
diff --git a/components/script/dom/webidls/XRFrame.webidl b/components/script/dom/webidls/XRFrame.webidl
index 3c202d5e061..e7a4eef1ddd 100644
--- a/components/script/dom/webidls/XRFrame.webidl
+++ b/components/script/dom/webidls/XRFrame.webidl
@@ -10,5 +10,6 @@ interface XRFrame {
[Throws] XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace);
[Throws] XRPose? getPose(XRSpace space, XRSpace relativeTo);
+ [Pref="dom.webxr.hands.enabled", Throws] XRJointPose? getJointPose(XRJointSpace space, XRSpace relativeTo);
sequence<XRHitTestResult> getHitTestResults(XRHitTestSource hitTestSource);
};
diff --git a/components/script/dom/webidls/XRHand.webidl b/components/script/dom/webidls/XRHand.webidl
new file mode 100644
index 00000000000..cff30268ba6
--- /dev/null
+++ b/components/script/dom/webidls/XRHand.webidl
@@ -0,0 +1,41 @@
+/* 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/. */
+
+// https://github.com/immersive-web/webxr-hands-input/blob/master/explainer.md
+
+[SecureContext, Exposed=Window, Pref="dom.webxr.hands.enabled"]
+interface XRHand {
+ readonly attribute long length;
+ getter XRJointSpace(unsigned long index);
+
+ const unsigned long WRIST = 0;
+ const unsigned long THUMB_METACARPAL = 1;
+ const unsigned long THUMB_PHALANX_PROXIMAL = 2;
+ const unsigned long THUMB_PHALANX_DISTAL = 3;
+ const unsigned long THUMB_PHALANX_TIP = 4;
+
+ const unsigned long INDEX_METACARPAL = 5;
+ const unsigned long INDEX_PHALANX_PROXIMAL = 6;
+ const unsigned long INDEX_PHALANX_INTERMEDIATE = 7;
+ const unsigned long INDEX_PHALANX_DISTAL = 8;
+ const unsigned long INDEX_PHALANX_TIP = 9;
+
+ const unsigned long MIDDLE_METACARPAL = 10;
+ const unsigned long MIDDLE_PHALANX_PROXIMAL = 11;
+ const unsigned long MIDDLE_PHALANX_INTERMEDIATE = 12;
+ const unsigned long MIDDLE_PHALANX_DISTAL = 13;
+ const unsigned long MIDDLE_PHALANX_TIP = 14;
+
+ const unsigned long RING_METACARPAL = 15;
+ const unsigned long RING_PHALANX_PROXIMAL = 16;
+ const unsigned long RING_PHALANX_INTERMEDIATE = 17;
+ const unsigned long RING_PHALANX_DISTAL = 18;
+ const unsigned long RING_PHALANX_TIP = 19;
+
+ const unsigned long LITTLE_METACARPAL = 20;
+ const unsigned long LITTLE_PHALANX_PROXIMAL = 21;
+ const unsigned long LITTLE_PHALANX_INTERMEDIATE = 22;
+ const unsigned long LITTLE_PHALANX_DISTAL = 23;
+ const unsigned long LITTLE_PHALANX_TIP = 24;
+};
diff --git a/components/script/dom/webidls/XRInputSource.webidl b/components/script/dom/webidls/XRInputSource.webidl
index 487c959859d..b663666c872 100644
--- a/components/script/dom/webidls/XRInputSource.webidl
+++ b/components/script/dom/webidls/XRInputSource.webidl
@@ -24,4 +24,7 @@ interface XRInputSource {
[SameObject] readonly attribute XRSpace? gripSpace;
// [SameObject] readonly attribute Gamepad? gamepad;
/* [SameObject] */ readonly attribute /* FrozenArray<DOMString> */ any profiles;
+
+ [Pref="dom.webxr.hands.enabled"]
+ readonly attribute XRHand? hand;
};
diff --git a/components/script/dom/webidls/XRJointPose.webidl b/components/script/dom/webidls/XRJointPose.webidl
new file mode 100644
index 00000000000..70750b66cc4
--- /dev/null
+++ b/components/script/dom/webidls/XRJointPose.webidl
@@ -0,0 +1,10 @@
+/* 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/. */
+
+// https://github.com/immersive-web/webxr-hands-input/blob/master/explainer.md
+
+[SecureContext, Exposed=Window, Pref="dom.webxr.hands.enabled"]
+interface XRJointPose: XRPose {
+ readonly attribute float? radius;
+};
diff --git a/components/script/dom/webidls/XRJointSpace.webidl b/components/script/dom/webidls/XRJointSpace.webidl
new file mode 100644
index 00000000000..0815a73ec58
--- /dev/null
+++ b/components/script/dom/webidls/XRJointSpace.webidl
@@ -0,0 +1,8 @@
+/* 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/. */
+
+// https://github.com/immersive-web/webxr-hands-input/blob/master/explainer.md
+
+[SecureContext, Exposed=Window, Pref="dom.webxr.hands.enabled"]
+interface XRJointSpace: XRSpace {};
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 9f37ec2240a..c23efc961ee 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -2008,15 +2008,21 @@ impl Window {
// Step 8
if doc.prompt_to_unload(false) {
- if self.window_proxy().parent().is_some() {
+ let window_proxy = self.window_proxy();
+ if window_proxy.parent().is_some() {
// Step 10
// If browsingContext is a nested browsing context,
// then put it in the delaying load events mode.
- self.window_proxy().start_delaying_load_events_mode();
+ window_proxy.start_delaying_load_events_mode();
}
// TODO: step 11, navigationType.
// Step 12, 13
- ScriptThread::navigate(pipeline_id, load_data, replace);
+ ScriptThread::navigate(
+ window_proxy.browsing_context_id(),
+ pipeline_id,
+ load_data,
+ replace,
+ );
};
}
diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs
index d040d7d7468..c9555c88517 100644
--- a/components/script/dom/worker.rs
+++ b/components/script/dom/worker.rs
@@ -20,6 +20,7 @@ use crate::dom::dedicatedworkerglobalscope::{
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent;
+use crate::dom::window::Window;
use crate::dom::workerglobalscope::prepare_workerscope_init;
use crate::realms::enter_realm;
use crate::script_runtime::JSContext;
@@ -95,23 +96,34 @@ impl Worker {
pipeline_id: global.pipeline_id(),
};
+ let browsing_context = global
+ .downcast::<Window>()
+ .map(|w| w.window_proxy().browsing_context_id())
+ .or_else(|| {
+ global
+ .downcast::<DedicatedWorkerGlobalScope>()
+ .and_then(|w| w.browsing_context())
+ });
+
let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
let worker_id = WorkerId(Uuid::new_v4());
if let Some(ref chan) = global.devtools_chan() {
let pipeline_id = global.pipeline_id();
let title = format!("Worker for {}", worker_url);
- let page_info = DevtoolsPageInfo {
- title: title,
- url: worker_url.clone(),
- };
- let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
- (pipeline_id, Some(worker_id)),
- devtools_sender.clone(),
- page_info,
- ));
+ if let Some(browsing_context) = browsing_context {
+ let page_info = DevtoolsPageInfo {
+ title: title,
+ url: worker_url.clone(),
+ };
+ let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
+ (browsing_context, pipeline_id, Some(worker_id)),
+ devtools_sender.clone(),
+ page_info,
+ ));
+ }
}
- let init = prepare_workerscope_init(global, Some(devtools_sender));
+ let init = prepare_workerscope_init(global, Some(devtools_sender), Some(worker_id));
DedicatedWorkerGlobalScope::run_worker_scope(
init,
@@ -126,6 +138,7 @@ impl Worker {
worker_options.type_,
closing,
global.image_cache(),
+ browsing_context,
);
Ok(worker)
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 15eb79858fe..684760c3197 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -62,6 +62,7 @@ use uuid::Uuid;
pub fn prepare_workerscope_init(
global: &GlobalScope,
devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
+ worker_id: Option<WorkerId>,
) -> WorkerGlobalScopeInit {
let init = WorkerGlobalScopeInit {
resource_threads: global.resource_threads().clone(),
@@ -71,7 +72,7 @@ pub fn prepare_workerscope_init(
from_devtools_sender: devtools_sender,
script_to_constellation_chan: global.script_to_constellation_chan().clone(),
scheduler_chan: global.scheduler_chan().clone(),
- worker_id: WorkerId(Uuid::new_v4()),
+ worker_id: worker_id.unwrap_or_else(|| WorkerId(Uuid::new_v4())),
pipeline_id: global.pipeline_id(),
origin: global.origin().immutable().clone(),
is_headless: global.is_headless(),
diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs
index fdafd932e8a..1526a1c387c 100644
--- a/components/script/dom/xrframe.rs
+++ b/components/script/dom/xrframe.rs
@@ -10,6 +10,8 @@ use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrhittestresult::XRHitTestResult;
use crate::dom::xrhittestsource::XRHitTestSource;
+use crate::dom::xrjointpose::XRJointPose;
+use crate::dom::xrjointspace::XRJointSpace;
use crate::dom::xrpose::XRPose;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrsession::{ApiPose, XRSession};
@@ -112,6 +114,38 @@ impl XRFrameMethods for XRFrame {
Ok(Some(XRPose::new(&self.global(), pose)))
}
+ /// https://immersive-web.github.io/webxr/#dom-xrframe-getpose
+ fn GetJointPose(
+ &self,
+ space: &XRJointSpace,
+ relative_to: &XRSpace,
+ ) -> Result<Option<DomRoot<XRJointPose>>, Error> {
+ if self.session != space.upcast::<XRSpace>().session() ||
+ self.session != relative_to.session()
+ {
+ return Err(Error::InvalidState);
+ }
+ if !self.active.get() {
+ return Err(Error::InvalidState);
+ }
+ let joint_frame = if let Some(frame) = space.frame(&self.data) {
+ frame
+ } else {
+ return Ok(None);
+ };
+ let relative_to = if let Some(r) = self.get_pose(relative_to) {
+ r
+ } else {
+ return Ok(None);
+ };
+ let pose = relative_to.inverse().pre_transform(&joint_frame.pose);
+ Ok(Some(XRJointPose::new(
+ &self.global(),
+ pose.cast_unit(),
+ Some(joint_frame.radius),
+ )))
+ }
+
/// https://immersive-web.github.io/hit-test/#dom-xrframe-gethittestresults
fn GetHitTestResults(&self, source: &XRHitTestSource) -> Vec<DomRoot<XRHitTestResult>> {
self.data
diff --git a/components/script/dom/xrhand.rs b/components/script/dom/xrhand.rs
new file mode 100644
index 00000000000..a7457526242
--- /dev/null
+++ b/components/script/dom/xrhand.rs
@@ -0,0 +1,88 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::XRHandBinding::{XRHandConstants, XRHandMethods};
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::xrinputsource::XRInputSource;
+use crate::dom::xrjointspace::XRJointSpace;
+use dom_struct::dom_struct;
+use webxr_api::{FingerJoint, Hand, Joint};
+
+#[dom_struct]
+pub struct XRHand {
+ reflector_: Reflector,
+ #[ignore_malloc_size_of = "defined in webxr"]
+ source: Dom<XRInputSource>,
+ #[ignore_malloc_size_of = "partially defind in webxr"]
+ spaces: Hand<Dom<XRJointSpace>>,
+}
+
+impl XRHand {
+ fn new_inherited(source: &XRInputSource, spaces: &Hand<DomRoot<XRJointSpace>>) -> XRHand {
+ XRHand {
+ reflector_: Reflector::new(),
+ source: Dom::from_ref(source),
+ spaces: spaces.map(|j, _| j.as_ref().map(|j| Dom::from_ref(&**j))),
+ }
+ }
+
+ pub fn new(global: &GlobalScope, source: &XRInputSource, support: Hand<()>) -> DomRoot<XRHand> {
+ let id = source.id();
+ let session = source.session();
+ let spaces = support
+ .map(|field, joint| field.map(|_| XRJointSpace::new(global, session, id, joint)));
+ reflect_dom_object(Box::new(XRHand::new_inherited(source, &spaces)), global)
+ }
+}
+
+impl XRHandMethods for XRHand {
+ /// https://github.com/immersive-web/webxr-hands-input/blob/master/explainer.md
+ fn Length(&self) -> i32 {
+ XRHandConstants::LITTLE_PHALANX_TIP as i32 + 1
+ }
+
+ /// https://github.com/immersive-web/webxr-hands-input/blob/master/explainer.md
+ fn IndexedGetter(&self, joint_index: u32) -> Option<DomRoot<XRJointSpace>> {
+ let joint = match joint_index {
+ XRHandConstants::WRIST => Joint::Wrist,
+ XRHandConstants::THUMB_METACARPAL => Joint::ThumbMetacarpal,
+ XRHandConstants::THUMB_PHALANX_PROXIMAL => Joint::ThumbPhalanxProximal,
+ XRHandConstants::THUMB_PHALANX_DISTAL => Joint::ThumbPhalanxDistal,
+ XRHandConstants::THUMB_PHALANX_TIP => Joint::ThumbPhalanxTip,
+ XRHandConstants::INDEX_METACARPAL => Joint::Index(FingerJoint::Metacarpal),
+ XRHandConstants::INDEX_PHALANX_PROXIMAL => Joint::Index(FingerJoint::PhalanxProximal),
+ XRHandConstants::INDEX_PHALANX_INTERMEDIATE => {
+ Joint::Index(FingerJoint::PhalanxIntermediate)
+ },
+ XRHandConstants::INDEX_PHALANX_DISTAL => Joint::Index(FingerJoint::PhalanxDistal),
+ XRHandConstants::INDEX_PHALANX_TIP => Joint::Index(FingerJoint::PhalanxTip),
+ XRHandConstants::MIDDLE_METACARPAL => Joint::Middle(FingerJoint::Metacarpal),
+ XRHandConstants::MIDDLE_PHALANX_PROXIMAL => Joint::Middle(FingerJoint::PhalanxProximal),
+ XRHandConstants::MIDDLE_PHALANX_INTERMEDIATE => {
+ Joint::Middle(FingerJoint::PhalanxIntermediate)
+ },
+ XRHandConstants::MIDDLE_PHALANX_DISTAL => Joint::Middle(FingerJoint::PhalanxDistal),
+ XRHandConstants::MIDDLE_PHALANX_TIP => Joint::Middle(FingerJoint::PhalanxTip),
+ XRHandConstants::RING_METACARPAL => Joint::Ring(FingerJoint::Metacarpal),
+ XRHandConstants::RING_PHALANX_PROXIMAL => Joint::Ring(FingerJoint::PhalanxProximal),
+ XRHandConstants::RING_PHALANX_INTERMEDIATE => {
+ Joint::Ring(FingerJoint::PhalanxIntermediate)
+ },
+ XRHandConstants::RING_PHALANX_DISTAL => Joint::Ring(FingerJoint::PhalanxDistal),
+ XRHandConstants::RING_PHALANX_TIP => Joint::Ring(FingerJoint::PhalanxTip),
+ XRHandConstants::LITTLE_METACARPAL => Joint::Little(FingerJoint::Metacarpal),
+ XRHandConstants::LITTLE_PHALANX_PROXIMAL => Joint::Little(FingerJoint::PhalanxProximal),
+ XRHandConstants::LITTLE_PHALANX_INTERMEDIATE => {
+ Joint::Little(FingerJoint::PhalanxIntermediate)
+ },
+ XRHandConstants::LITTLE_PHALANX_DISTAL => Joint::Little(FingerJoint::PhalanxDistal),
+ XRHandConstants::LITTLE_PHALANX_TIP => Joint::Little(FingerJoint::PhalanxTip),
+ // XXXManishearth should this be a TypeError?
+ _ => return None,
+ };
+ self.spaces.get(joint).map(|j| DomRoot::from_ref(&**j))
+ }
+}
diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs
index ed8a3e6f1a5..248fb6d737a 100644
--- a/components/script/dom/xrinputsource.rs
+++ b/components/script/dom/xrinputsource.rs
@@ -8,6 +8,7 @@ use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::globalscope::GlobalScope;
+use crate::dom::xrhand::XRHand;
use crate::dom::xrsession::XRSession;
use crate::dom::xrspace::XRSpace;
use crate::realms::enter_realm;
@@ -24,10 +25,9 @@ pub struct XRInputSource {
session: Dom<XRSession>,
#[ignore_malloc_size_of = "Defined in rust-webxr"]
info: InputSource,
- #[ignore_malloc_size_of = "Defined in rust-webxr"]
target_ray_space: MutNullableDom<XRSpace>,
- #[ignore_malloc_size_of = "Defined in rust-webxr"]
grip_space: MutNullableDom<XRSpace>,
+ hand: MutNullableDom<XRHand>,
#[ignore_malloc_size_of = "mozjs"]
profiles: Heap<JSVal>,
}
@@ -40,6 +40,7 @@ impl XRInputSource {
info,
target_ray_space: Default::default(),
grip_space: Default::default(),
+ hand: Default::default(),
profiles: Heap::default(),
}
}
@@ -68,6 +69,10 @@ impl XRInputSource {
pub fn id(&self) -> InputId {
self.info.id
}
+
+ pub fn session(&self) -> &XRSession {
+ &self.session
+ }
}
impl XRInputSourceMethods for XRInputSource {
@@ -112,4 +117,16 @@ impl XRInputSourceMethods for XRInputSource {
fn Profiles(&self, _cx: JSContext) -> JSVal {
self.profiles.get()
}
+
+ // https://github.com/immersive-web/webxr-hands-input/blob/master/explainer.md
+ fn GetHand(&self) -> Option<DomRoot<XRHand>> {
+ if let Some(ref hand) = self.info.hand_support {
+ Some(
+ self.hand
+ .or_init(|| XRHand::new(&self.global(), &self, hand.clone())),
+ )
+ } else {
+ None
+ }
+ }
}
diff --git a/components/script/dom/xrjointpose.rs b/components/script/dom/xrjointpose.rs
new file mode 100644
index 00000000000..c4b610b3327
--- /dev/null
+++ b/components/script/dom/xrjointpose.rs
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::XRJointPoseBinding::XRJointPoseMethods;
+use crate::dom::bindings::num::Finite;
+use crate::dom::bindings::reflector::reflect_dom_object;
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::xrpose::XRPose;
+use crate::dom::xrrigidtransform::XRRigidTransform;
+use crate::dom::xrsession::ApiRigidTransform;
+use dom_struct::dom_struct;
+
+#[dom_struct]
+pub struct XRJointPose {
+ pose: XRPose,
+ radius: Option<f32>,
+}
+
+impl XRJointPose {
+ fn new_inherited(transform: &XRRigidTransform, radius: Option<f32>) -> XRJointPose {
+ XRJointPose {
+ pose: XRPose::new_inherited(transform),
+ radius,
+ }
+ }
+
+ #[allow(unsafe_code)]
+ pub fn new(
+ global: &GlobalScope,
+ pose: ApiRigidTransform,
+ radius: Option<f32>,
+ ) -> DomRoot<XRJointPose> {
+ let transform = XRRigidTransform::new(global, pose);
+ reflect_dom_object(
+ Box::new(XRJointPose::new_inherited(&transform, radius)),
+ global,
+ )
+ }
+}
+
+impl XRJointPoseMethods for XRJointPose {
+ /// https://immersive-web.github.io/webxr/#dom-XRJointPose-views
+ fn GetRadius(&self) -> Option<Finite<f32>> {
+ self.radius.map(Finite::wrap)
+ }
+}
diff --git a/components/script/dom/xrjointspace.rs b/components/script/dom/xrjointspace.rs
new file mode 100644
index 00000000000..4b31b0bc6a2
--- /dev/null
+++ b/components/script/dom/xrjointspace.rs
@@ -0,0 +1,60 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::reflector::reflect_dom_object;
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::xrsession::{ApiPose, XRSession};
+use crate::dom::xrspace::XRSpace;
+use dom_struct::dom_struct;
+use euclid::RigidTransform3D;
+use webxr_api::{BaseSpace, Frame, InputId, Joint, JointFrame, Space};
+
+#[dom_struct]
+pub struct XRJointSpace {
+ xrspace: XRSpace,
+ #[ignore_malloc_size_of = "defined in rust-webxr"]
+ input: InputId,
+ #[ignore_malloc_size_of = "defined in rust-webxr"]
+ joint: Joint,
+}
+
+impl XRJointSpace {
+ pub fn new_inherited(session: &XRSession, input: InputId, joint: Joint) -> XRJointSpace {
+ XRJointSpace {
+ xrspace: XRSpace::new_inherited(session),
+ input,
+ joint,
+ }
+ }
+
+ #[allow(unused)]
+ pub fn new(
+ global: &GlobalScope,
+ session: &XRSession,
+ input: InputId,
+ joint: Joint,
+ ) -> DomRoot<XRJointSpace> {
+ reflect_dom_object(Box::new(Self::new_inherited(session, input, joint)), global)
+ }
+
+ pub fn space(&self) -> Space {
+ let base = BaseSpace::Joint(self.input, self.joint);
+ let offset = RigidTransform3D::identity();
+ Space { base, offset }
+ }
+
+ pub fn frame<'a>(&self, frame: &'a Frame) -> Option<&'a JointFrame> {
+ frame
+ .inputs
+ .iter()
+ .find(|i| i.id == self.input)
+ .and_then(|i| i.hand.as_ref())
+ .and_then(|h| h.get(self.joint))
+ }
+
+ pub fn get_pose(&self, frame: &Frame) -> Option<ApiPose> {
+ self.frame(frame).map(|f| f.pose).map(|t| t.cast_unit())
+ }
+}
diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs
index b4a26b7b8bb..66dd5b44e70 100644
--- a/components/script/dom/xrspace.rs
+++ b/components/script/dom/xrspace.rs
@@ -8,6 +8,7 @@ use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrinputsource::XRInputSource;
+use crate::dom::xrjointspace::XRJointSpace;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrsession::{cast_transform, ApiPose, XRSession};
use dom_struct::dom_struct;
@@ -61,6 +62,8 @@ impl XRSpace {
pub fn space(&self) -> Space {
if let Some(rs) = self.downcast::<XRReferenceSpace>() {
rs.space()
+ } else if let Some(j) = self.downcast::<XRJointSpace>() {
+ j.space()
} else if let Some(source) = self.input_source.get() {
let base = if self.is_grip_space {
BaseSpace::Grip(source.id())
@@ -86,6 +89,8 @@ impl XRSpace {
pub fn get_pose(&self, base_pose: &Frame) -> Option<ApiPose> {
if let Some(reference) = self.downcast::<XRReferenceSpace>() {
reference.get_pose(base_pose)
+ } else if let Some(joint) = self.downcast::<XRJointSpace>() {
+ joint.get_pose(base_pose)
} else if let Some(source) = self.input_source.get() {
// XXXManishearth we should be able to request frame information
// for inputs when necessary instead of always loading it
diff --git a/components/script/dom/xrsystem.rs b/components/script/dom/xrsystem.rs
index 0fc4ab108e2..a2ba7946e62 100644
--- a/components/script/dom/xrsystem.rs
+++ b/components/script/dom/xrsystem.rs
@@ -267,7 +267,8 @@ impl XRSystem {
) {
let session = match response {
Ok(session) => session,
- Err(_) => {
+ Err(e) => {
+ warn!("Error requesting XR session: {:?}", e);
if mode != XRSessionMode::Inline {
self.pending_immersive_session.set(false);
}
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index bd65780dc19..16fd866f1b9 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -93,7 +93,7 @@ use canvas_traits::webgl::WebGLPipeline;
use crossbeam_channel::{unbounded, Receiver, Sender};
use devtools_traits::CSSError;
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo};
-use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
+use devtools_traits::{NavigationState, ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::{EmbedderMsg, EventLoopWaker};
use euclid::default::{Point2D, Rect};
use euclid::Vector2D;
@@ -133,17 +133,15 @@ use script_traits::CompositorEvent::{
CompositionEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent, TouchEvent,
WheelEvent,
};
-use script_traits::StructuredSerializedData;
-use script_traits::{CompositorEvent, ConstellationControlMsg};
use script_traits::{
- DiscardBrowsingContext, DocumentActivity, EventResult, HistoryEntryReplacement,
+ CompositorEvent, ConstellationControlMsg, DiscardBrowsingContext, DocumentActivity,
+ EventResult, HistoryEntryReplacement, InitialScriptState, JsEvalResult, LayoutMsg, LoadData,
+ LoadOrigin, MediaSessionActionType, MouseButton, MouseEventType, NewLayoutInfo, Painter,
+ ProgressiveWebMetricType, ScriptMsg, ScriptThreadFactory, ScriptToConstellationChan,
+ StructuredSerializedData, TimerSchedulerMsg, TouchEventType, TouchId, TransitionEventType,
+ UntrustedNodeAddress, UpdatePipelineIdReason, WebrenderIpcSender, WheelDelta, WindowSizeData,
+ WindowSizeType,
};
-use script_traits::{InitialScriptState, JsEvalResult, LayoutMsg, LoadData, LoadOrigin};
-use script_traits::{MediaSessionActionType, MouseButton, MouseEventType, NewLayoutInfo};
-use script_traits::{Painter, ProgressiveWebMetricType, ScriptMsg, ScriptThreadFactory};
-use script_traits::{ScriptToConstellationChan, TimerSchedulerMsg};
-use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WheelDelta};
-use script_traits::{UpdatePipelineIdReason, WebrenderIpcSender, WindowSizeData, WindowSizeType};
use servo_atoms::Atom;
use servo_config::opts;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
@@ -949,6 +947,7 @@ impl ScriptThread {
/// Step 13 of https://html.spec.whatwg.org/multipage/#navigate
pub fn navigate(
+ browsing_context: BrowsingContextId,
pipeline_id: PipelineId,
mut load_data: LoadData,
replace: HistoryEntryReplacement,
@@ -987,6 +986,12 @@ impl ScriptThread {
.queue(task, global.upcast())
.expect("Enqueing navigate js task on the DOM manipulation task source failed");
} else {
+ if let Some(ref sender) = script_thread.devtools_chan {
+ let _ = sender.send(ScriptToDevtoolsControlMsg::Navigate(
+ browsing_context, NavigationState::Start(load_data.url.clone())
+ ));
+ }
+
script_thread
.script_sender
.send((pipeline_id, ScriptMsg::LoadUrl(load_data, replace)))
@@ -1668,46 +1673,43 @@ impl ScriptThread {
fn message_to_pipeline(&self, msg: &MixedMessage) -> Option<PipelineId> {
use script_traits::ConstellationControlMsg::*;
match *msg {
- MixedMessage::FromConstellation(ref inner_msg) => {
- match *inner_msg {
- StopDelayingLoadEventsMode(id) => Some(id),
- NavigationResponse(id, _) => Some(id),
- AttachLayout(ref new_layout_info) => Some(new_layout_info.new_pipeline_id),
- Resize(id, ..) => Some(id),
- ResizeInactive(id, ..) => Some(id),
- UnloadDocument(id) => Some(id),
- ExitPipeline(id, ..) => Some(id),
- ExitScriptThread => None,
- SendEvent(id, ..) => Some(id),
- Viewport(id, ..) => Some(id),
- SetScrollState(id, ..) => Some(id),
- GetTitle(id) => Some(id),
- SetDocumentActivity(id, ..) => Some(id),
- ChangeFrameVisibilityStatus(id, ..) => Some(id),
- NotifyVisibilityChange(id, ..) => Some(id),
- NavigateIframe(id, ..) => Some(id),
- PostMessage { target: id, .. } => Some(id),
- UpdatePipelineId(_, _, _, id, _) => Some(id),
- UpdateHistoryState(id, ..) => Some(id),
- RemoveHistoryStates(id, ..) => Some(id),
- FocusIFrame(id, ..) => Some(id),
- WebDriverScriptCommand(id, ..) => Some(id),
- TickAllAnimations(id) => Some(id),
- // FIXME https://github.com/servo/servo/issues/15079
- TransitionEnd(..) => None,
- WebFontLoaded(id) => Some(id),
- DispatchIFrameLoadEvent {
- target: _,
- parent: id,
- child: _,
- } => Some(id),
- DispatchStorageEvent(id, ..) => Some(id),
- ReportCSSError(id, ..) => Some(id),
- Reload(id, ..) => Some(id),
- PaintMetric(..) => None,
- ExitFullScreen(id, ..) => Some(id),
- MediaSessionAction(..) => None,
- }
+ MixedMessage::FromConstellation(ref inner_msg) => match *inner_msg {
+ StopDelayingLoadEventsMode(id) => Some(id),
+ NavigationResponse(id, _) => Some(id),
+ AttachLayout(ref new_layout_info) => Some(new_layout_info.new_pipeline_id),
+ Resize(id, ..) => Some(id),
+ ResizeInactive(id, ..) => Some(id),
+ UnloadDocument(id) => Some(id),
+ ExitPipeline(id, ..) => Some(id),
+ ExitScriptThread => None,
+ SendEvent(id, ..) => Some(id),
+ Viewport(id, ..) => Some(id),
+ SetScrollState(id, ..) => Some(id),
+ GetTitle(id) => Some(id),
+ SetDocumentActivity(id, ..) => Some(id),
+ ChangeFrameVisibilityStatus(id, ..) => Some(id),
+ NotifyVisibilityChange(id, ..) => Some(id),
+ NavigateIframe(id, ..) => Some(id),
+ PostMessage { target: id, .. } => Some(id),
+ UpdatePipelineId(_, _, _, id, _) => Some(id),
+ UpdateHistoryState(id, ..) => Some(id),
+ RemoveHistoryStates(id, ..) => Some(id),
+ FocusIFrame(id, ..) => Some(id),
+ WebDriverScriptCommand(id, ..) => Some(id),
+ TickAllAnimations(id) => Some(id),
+ TransitionEvent { .. } => None,
+ WebFontLoaded(id) => Some(id),
+ DispatchIFrameLoadEvent {
+ target: _,
+ parent: id,
+ child: _,
+ } => Some(id),
+ DispatchStorageEvent(id, ..) => Some(id),
+ ReportCSSError(id, ..) => Some(id),
+ Reload(id, ..) => Some(id),
+ PaintMetric(..) => None,
+ ExitFullScreen(id, ..) => Some(id),
+ MediaSessionAction(..) => None,
},
MixedMessage::FromDevtools(_) => None,
MixedMessage::FromScript(ref inner_msg) => match *inner_msg {
@@ -1896,8 +1898,20 @@ impl ScriptThread {
ConstellationControlMsg::TickAllAnimations(pipeline_id) => {
self.handle_tick_all_animations(pipeline_id)
},
- ConstellationControlMsg::TransitionEnd(unsafe_node, name, duration) => {
- self.handle_transition_event(unsafe_node, name, duration)
+ ConstellationControlMsg::TransitionEvent {
+ pipeline_id,
+ event_type,
+ node,
+ property_name,
+ elapsed_time,
+ } => {
+ self.handle_transition_event(
+ pipeline_id,
+ event_type,
+ node,
+ property_name,
+ elapsed_time,
+ );
},
ConstellationControlMsg::WebFontLoaded(pipeline_id) => {
self.handle_web_font_loaded(pipeline_id)
@@ -2899,56 +2913,69 @@ impl ScriptThread {
document.run_the_animation_frame_callbacks();
}
- /// Handles firing of transition events.
+ /// Handles firing of transition-related events.
+ ///
+ /// TODO(mrobinson): Add support for more events.
fn handle_transition_event(
&self,
+ pipeline_id: PipelineId,
+ event_type: TransitionEventType,
unsafe_node: UntrustedNodeAddress,
- name: String,
- duration: f64,
+ property_name: String,
+ elapsed_time: f64,
) {
let js_runtime = self.js_runtime.rt();
let node = unsafe { from_untrusted_node_address(js_runtime, unsafe_node) };
- let idx = self
+ let node_index = self
.transitioning_nodes
.borrow()
.iter()
.position(|n| &**n as *const _ == &*node as *const _);
- match idx {
- Some(idx) => {
- self.transitioning_nodes.borrow_mut().remove(idx);
- },
+ let node_index = match node_index {
+ Some(node_index) => node_index,
None => {
// If no index is found, we can't know whether this node is safe to use.
// It's better not to fire a DOM event than crash.
warn!("Ignoring transition end notification for unknown node.");
return;
},
- }
-
- let window = window_from_node(&*node);
-
- // Not quite the right thing - see #13865.
- node.dirty(NodeDamage::NodeStyleDamaged);
+ };
- if let Some(el) = node.downcast::<Element>() {
- if !el.has_css_layout_box() {
- return;
- }
+ if self.closed_pipelines.borrow().contains(&pipeline_id) {
+ warn!("Ignoring transition event for closed pipeline.");
+ return;
}
- let init = TransitionEventInit {
+ let event_atom = match event_type {
+ TransitionEventType::TransitionRun => atom!("transitionrun"),
+ TransitionEventType::TransitionEnd => {
+ // Not quite the right thing - see #13865.
+ node.dirty(NodeDamage::NodeStyleDamaged);
+ self.transitioning_nodes.borrow_mut().remove(node_index);
+ atom!("transitionend")
+ },
+ TransitionEventType::TransitionCancel => {
+ self.transitioning_nodes.borrow_mut().remove(node_index);
+ atom!("transitioncancel")
+ },
+ };
+
+ let event_init = TransitionEventInit {
parent: EventInit {
bubbles: true,
cancelable: false,
},
- propertyName: DOMString::from(name),
- elapsedTime: Finite::new(duration as f32).unwrap(),
- // FIXME: Handle pseudo-elements properly
+ propertyName: DOMString::from(property_name),
+ elapsedTime: Finite::new(elapsed_time as f32).unwrap(),
+ // TODO: Handle pseudo-elements properly
pseudoElement: DOMString::new(),
};
- let transition_event = TransitionEvent::new(&window, atom!("transitionend"), &init);
- transition_event.upcast::<Event>().fire(node.upcast());
+
+ let window = window_from_node(&*node);
+ TransitionEvent::new(&window, event_atom, &event_init)
+ .upcast::<Event>()
+ .fire(node.upcast());
}
/// Handles a Web font being loaded. Does nothing if the page no longer exists.
@@ -3321,7 +3348,7 @@ impl ScriptThread {
self.notify_devtools(
document.Title(),
final_url.clone(),
- (incomplete.pipeline_id, None),
+ (incomplete.browsing_context_id, incomplete.pipeline_id, None),
);
let parse_input = DOMString::new();
@@ -3352,7 +3379,7 @@ impl ScriptThread {
&self,
title: DOMString,
url: ServoUrl,
- ids: (PipelineId, Option<WorkerId>),
+ (bc, p, w): (BrowsingContextId, PipelineId, Option<WorkerId>),
) {
if let Some(ref chan) = self.devtools_chan {
let page_info = DevtoolsPageInfo {
@@ -3360,11 +3387,14 @@ impl ScriptThread {
url: url,
};
chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
- ids,
+ (bc, p, w),
self.devtools_sender.clone(),
- page_info,
+ page_info.clone(),
))
.unwrap();
+
+ let state = NavigationState::Stop(p, page_info);
+ let _ = chan.send(ScriptToDevtoolsControlMsg::Navigate(bc, state));
}
}
diff --git a/components/script/serviceworker_manager.rs b/components/script/serviceworker_manager.rs
index 83bf1dbf312..73ead01fe17 100644
--- a/components/script/serviceworker_manager.rs
+++ b/components/script/serviceworker_manager.rs
@@ -11,7 +11,6 @@ use crate::dom::abstractworker::WorkerScriptMsg;
use crate::dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg};
use crate::dom::serviceworkerregistration::longest_prefix_match;
use crossbeam_channel::{unbounded, Receiver, RecvError, Sender};
-use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use net_traits::{CoreResourceMsg, CustomResponseMediator};
@@ -79,19 +78,7 @@ impl ServiceWorkerManager {
let scope_things = self.registered_workers.get(&scope_url);
if let Some(scope_things) = scope_things {
let (sender, receiver) = unbounded();
- let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
- if let Some(ref chan) = scope_things.devtools_chan {
- let title = format!("ServiceWorker for {}", scope_things.script_url);
- let page_info = DevtoolsPageInfo {
- title: title,
- url: scope_things.script_url.clone(),
- };
- let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
- (scope_things.init.pipeline_id, Some(scope_things.worker_id)),
- devtools_sender,
- page_info,
- ));
- };
+ let (_devtools_sender, devtools_receiver) = ipc::channel().unwrap();
ServiceWorkerGlobalScope::run_serviceworker_scope(
scope_things.clone(),
sender.clone(),
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index 41056f3f6f2..3db883b6536 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -282,6 +282,18 @@ pub enum UpdatePipelineIdReason {
Traversal,
}
+/// The type of transition event to trigger.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub enum TransitionEventType {
+ /// The transition has started running.
+ TransitionRun,
+ /// The transition has ended by reaching the end of its animation.
+ TransitionEnd,
+ /// The transition ended early for some reason, such as the property
+ /// no longer being transitionable or being replaced by another transition.
+ TransitionCancel,
+}
+
/// Messages sent from the constellation or layout to the script thread.
#[derive(Deserialize, Serialize)]
pub enum ConstellationControlMsg {
@@ -368,8 +380,19 @@ pub enum ConstellationControlMsg {
WebDriverScriptCommand(PipelineId, WebDriverScriptCommand),
/// Notifies script thread that all animations are done
TickAllAnimations(PipelineId),
- /// Notifies the script thread of a transition end
- TransitionEnd(UntrustedNodeAddress, String, f64),
+ /// Notifies the script thread that a transition related event should be sent.
+ TransitionEvent {
+ /// The pipeline id of the layout task that sent this message.
+ pipeline_id: PipelineId,
+ /// The type of transition event this should trigger.
+ event_type: TransitionEventType,
+ /// The address of the node which owns this transition.
+ node: UntrustedNodeAddress,
+ /// The property name of the property that is transitioning.
+ property_name: String,
+ /// The elapsed time property to send with this transition event.
+ elapsed_time: f64,
+ },
/// Notifies the script thread that a new Web font has been loaded, and thus the page should be
/// reflowed.
WebFontLoaded(PipelineId),
@@ -429,7 +452,7 @@ impl fmt::Debug for ConstellationControlMsg {
FocusIFrame(..) => "FocusIFrame",
WebDriverScriptCommand(..) => "WebDriverScriptCommand",
TickAllAnimations(..) => "TickAllAnimations",
- TransitionEnd(..) => "TransitionEnd",
+ TransitionEvent { .. } => "TransitionEvent",
WebFontLoaded(..) => "WebFontLoaded",
DispatchIFrameLoadEvent { .. } => "DispatchIFrameLoadEvent",
DispatchStorageEvent(..) => "DispatchStorageEvent",
diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml
index 59f231e11b3..f3951107703 100644
--- a/components/style/Cargo.toml
+++ b/components/style/Cargo.toml
@@ -19,7 +19,7 @@ doctest = false
gecko = ["style_traits/gecko", "fallible/known_system_malloc", "bindgen", "regex", "toml"]
servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5ever",
"cssparser/serde", "encoding_rs", "malloc_size_of/servo", "servo_url",
- "string_cache", "crossbeam-channel", "to_shmem/servo",
+ "string_cache", "to_shmem/servo",
"servo_arc/servo"]
servo-layout-2013 = []
servo-layout-2020 = []
@@ -34,7 +34,6 @@ atomic_refcell = "0.1"
bitflags = "1.0"
byteorder = "1.0"
cssparser = "0.27"
-crossbeam-channel = { version = "0.4", optional = true }
derive_more = "0.99"
new_debug_unreachable = "1.0"
encoding_rs = {version = "0.8", optional = true}
diff --git a/components/style/README.md b/components/style/README.md
index 70670a5f96b..96457e1b30f 100644
--- a/components/style/README.md
+++ b/components/style/README.md
@@ -1,6 +1,6 @@
servo-style
===========
-Style system for Servo, using [rust-cssparser](https://github.com/mozilla-servo/rust-cssparser) for parsing.
+Style system for Servo, using [rust-cssparser](https://github.com/servo/rust-cssparser) for parsing.
* [Documentation](https://github.com/servo/servo/blob/master/docs/components/style.md).
diff --git a/components/style/animation.rs b/components/style/animation.rs
index b82d196fa73..c497bd9414b 100644
--- a/components/style/animation.rs
+++ b/components/style/animation.rs
@@ -5,16 +5,16 @@
//! CSS transitions and animations.
// NOTE(emilio): This code isn't really executed in Gecko, but we don't want to
-// compile it out so that people remember it exists, thus the cfg'd Sender
-// import.
+// compile it out so that people remember it exists.
use crate::bezier::Bezier;
use crate::context::SharedStyleContext;
use crate::dom::{OpaqueNode, TElement};
use crate::font_metrics::FontMetricsProvider;
-use crate::properties::animated_properties::{AnimatedProperty, TransitionPropertyIteration};
+use crate::properties::animated_properties::AnimatedProperty;
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
+use crate::properties::LonghandIdSet;
use crate::properties::{self, CascadeMode, ComputedValues, LonghandId};
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
use crate::stylesheets::Origin;
@@ -24,12 +24,8 @@ use crate::values::computed::TimingFunction;
use crate::values::generics::box_::AnimationIterationCount;
use crate::values::generics::easing::{StepPosition, TimingFunction as GenericTimingFunction};
use crate::Atom;
-#[cfg(feature = "servo")]
-use crossbeam_channel::Sender;
use servo_arc::Arc;
use std::fmt;
-#[cfg(feature = "gecko")]
-use std::sync::mpsc::Sender;
/// This structure represents a keyframes animation current iteration state.
///
@@ -245,6 +241,17 @@ impl Animation {
Animation::Keyframes(..) => false,
}
}
+
+ /// Whether this animation has the same end value as another one.
+ #[inline]
+ pub fn is_transition_with_same_end_value(&self, other_animation: &PropertyAnimation) -> bool {
+ match *self {
+ Animation::Transition(_, _, ref animation) => {
+ animation.has_the_same_end_value_as(other_animation)
+ },
+ Animation::Keyframes(..) => false,
+ }
+ }
}
/// Represents an animation for a given property.
@@ -261,6 +268,11 @@ pub struct PropertyAnimation {
}
impl PropertyAnimation {
+ /// Returns the given property longhand id.
+ pub fn property_id(&self) -> LonghandId {
+ self.property.id()
+ }
+
/// Returns the given property name.
pub fn property_name(&self) -> &'static str {
self.property.name()
@@ -351,20 +363,200 @@ impl PropertyAnimation {
}
}
-/// Inserts transitions into the queue of running animations as applicable for
-/// the given style difference. This is called from the layout worker threads.
-/// Returns true if any animations were kicked off and false otherwise.
+/// Holds the animation state for a particular element.
+#[derive(Default)]
+pub struct ElementAnimationState {
+ /// The animations running for this element.
+ pub running_animations: Vec<Animation>,
+
+ /// The animations that have finished for this element, but not canceled. These are cleared
+ /// upon triggering a DOM event for each finished animation.
+ pub finished_animations: Vec<Animation>,
+
+ /// The animations that have been cancelled for this element. These are cleared
+ /// upon triggering a DOM event for each cancelled animation.
+ pub cancelled_animations: Vec<Animation>,
+
+ /// New animations created for this element.
+ pub new_animations: Vec<Animation>,
+}
+
+impl ElementAnimationState {
+ /// Cancel all animations in this `ElementAnimationState`. This is typically called
+ /// when the element has been removed from the DOM.
+ pub fn cancel_all_animations(&mut self) {
+ self.cancelled_animations.extend(
+ self.finished_animations
+ .drain(..)
+ .chain(self.running_animations.drain(..))
+ .chain(self.new_animations.drain(..)),
+ );
+ }
+
+ pub(crate) fn cancel_transitions_with_nontransitioning_properties(
+ &mut self,
+ properties_that_transition: &LonghandIdSet,
+ ) {
+ if self.running_animations.is_empty() {
+ return;
+ }
+
+ let previously_running_transitions =
+ std::mem::replace(&mut self.running_animations, Vec::new());
+ for running_animation in previously_running_transitions {
+ if let Animation::Transition(_, _, ref property_animation) = running_animation {
+ if !properties_that_transition.contains(property_animation.property_id()) {
+ self.cancelled_animations.push(running_animation);
+ continue;
+ }
+ }
+ self.running_animations.push(running_animation);
+ }
+ }
+
+ fn has_transition_with_same_end_value(&self, property_animation: &PropertyAnimation) -> bool {
+ if self
+ .running_animations
+ .iter()
+ .any(|animation| animation.is_transition_with_same_end_value(&property_animation))
+ {
+ debug!(
+ "Running transition found with the same end value for {:?}",
+ property_animation,
+ );
+ return true;
+ }
+
+ if self
+ .finished_animations
+ .iter()
+ .any(|animation| animation.is_transition_with_same_end_value(&property_animation))
+ {
+ debug!(
+ "Expired transition found with the same end value for {:?}",
+ property_animation,
+ );
+ return true;
+ }
+
+ false
+ }
+
+ pub(crate) fn apply_completed_animations(&mut self, style: &mut Arc<ComputedValues>) {
+ for animation in self.finished_animations.iter() {
+ // TODO: Make this a bit more general and add support animation-fill-mode.
+ // Without support for that property though, animations that have ended should
+ // not affect property values. This is why we only process transitions here.
+ if let Animation::Transition(_, _, property_animation) = animation {
+ property_animation.update(Arc::make_mut(style), 1.0);
+ }
+ }
+ }
+
+ pub(crate) fn apply_running_animations<E>(
+ &mut self,
+ context: &SharedStyleContext,
+ style: &mut Arc<ComputedValues>,
+ font_metrics: &dyn crate::font_metrics::FontMetricsProvider,
+ ) where
+ E: TElement,
+ {
+ // Return early so that we don't unnecessarily clone the style when making it mutable.
+ if self.running_animations.is_empty() {
+ return;
+ }
+
+ let style = Arc::make_mut(style);
+ for animation in self.running_animations.iter_mut() {
+ let update = update_style_for_animation::<E>(context, animation, style, font_metrics);
+
+ match *animation {
+ Animation::Transition(..) => {},
+ Animation::Keyframes(_, _, _, ref mut state) => match update {
+ AnimationUpdate::Regular => {},
+ AnimationUpdate::AnimationCanceled => {
+ state.expired = true;
+ },
+ },
+ }
+ }
+ }
+
+ pub(crate) fn apply_new_animations<E>(
+ &mut self,
+ context: &SharedStyleContext,
+ style: &mut Arc<ComputedValues>,
+ font_metrics: &dyn crate::font_metrics::FontMetricsProvider,
+ ) where
+ E: TElement,
+ {
+ // Return early so that we don't unnecessarily clone the style when making it mutable.
+ if self.new_animations.is_empty() {
+ return;
+ }
+
+ let style = Arc::make_mut(style);
+ for animation in self.new_animations.iter_mut() {
+ update_style_for_animation::<E>(context, animation, style, font_metrics);
+ }
+ }
+
+ /// Whether this `ElementAnimationState` is empty, which means it doesn't
+ /// hold any animations in any state.
+ pub fn is_empty(&self) -> bool {
+ self.running_animations.is_empty() &&
+ self.finished_animations.is_empty() &&
+ self.cancelled_animations.is_empty() &&
+ self.new_animations.is_empty()
+ }
+
+ fn add_new_animation(&mut self, animation: Animation) {
+ self.new_animations.push(animation);
+ }
+
+ fn add_or_update_new_animation(&mut self, timer: &Timer, new_animation: Animation) {
+ // If the animation was already present in the list for the node,
+ // just update its state.
+ if let Animation::Keyframes(_, _, ref new_name, ref new_state) = new_animation {
+ for existing_animation in self.running_animations.iter_mut() {
+ match existing_animation {
+ Animation::Keyframes(_, _, ref name, ref mut state) if *name == *new_name => {
+ state.update_from_other(&new_state, timer);
+ return;
+ },
+ _ => {},
+ }
+ }
+ }
+ // Otherwise just add the new running animation.
+ self.add_new_animation(new_animation);
+ }
+}
+
+/// Kick off any new transitions for this node and return all of the properties that are
+/// transitioning. This is at the end of calculating style for a single node.
pub fn start_transitions_if_applicable(
- new_animations_sender: &Sender<Animation>,
+ context: &SharedStyleContext,
opaque_node: OpaqueNode,
old_style: &ComputedValues,
new_style: &mut Arc<ComputedValues>,
- timer: &Timer,
- running_and_expired_transitions: &[PropertyAnimation],
-) -> bool {
- let mut had_animations = false;
- let transitions: Vec<TransitionPropertyIteration> = new_style.transition_properties().collect();
- for transition in &transitions {
+ animation_state: &mut ElementAnimationState,
+) -> LonghandIdSet {
+ // If the style of this element is display:none, then we don't start any transitions
+ // and we cancel any currently running transitions by returning an empty LonghandIdSet.
+ if new_style.get_box().clone_display().is_none() {
+ return LonghandIdSet::new();
+ }
+
+ let mut properties_that_transition = LonghandIdSet::new();
+ for transition in new_style.transition_properties() {
+ let physical_property = transition.longhand_id.to_physical(new_style.writing_mode);
+ if properties_that_transition.contains(physical_property) {
+ continue;
+ } else {
+ properties_that_transition.insert(physical_property);
+ }
+
let property_animation = match PropertyAnimation::from_longhand(
transition.longhand_id,
new_style
@@ -374,56 +566,33 @@ pub fn start_transitions_if_applicable(
.get_box()
.transition_duration_mod(transition.index),
old_style,
- Arc::make_mut(new_style),
+ new_style,
) {
Some(property_animation) => property_animation,
None => continue,
};
- // Set the property to the initial value.
- //
- // NB: get_mut is guaranteed to succeed since we called make_mut()
- // above.
- property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0);
-
// Per [1], don't trigger a new transition if the end state for that
- // transition is the same as that of a transition that's already
- // running on the same node.
- //
+ // transition is the same as that of a transition that's running or
+ // completed.
// [1]: https://drafts.csswg.org/css-transitions/#starting
- debug!(
- "checking {:?} for matching end value",
- running_and_expired_transitions
- );
- if running_and_expired_transitions
- .iter()
- .any(|animation| animation.has_the_same_end_value_as(&property_animation))
- {
- debug!(
- "Not initiating transition for {}, other transition \
- found with the same end value",
- property_animation.property_name()
- );
+ if animation_state.has_transition_with_same_end_value(&property_animation) {
continue;
}
// Kick off the animation.
debug!("Kicking off transition of {:?}", property_animation);
let box_style = new_style.get_box();
- let now = timer.seconds();
+ let now = context.timer.seconds();
let start_time = now + (box_style.transition_delay_mod(transition.index).seconds() as f64);
- new_animations_sender
- .send(Animation::Transition(
- opaque_node,
- start_time,
- property_animation,
- ))
- .unwrap();
-
- had_animations = true;
+ animation_state.add_new_animation(Animation::Transition(
+ opaque_node,
+ start_time,
+ property_animation,
+ ));
}
- had_animations
+ properties_that_transition
}
fn compute_style_for_animation_step<E>(
@@ -484,15 +653,12 @@ where
pub fn maybe_start_animations<E>(
element: E,
context: &SharedStyleContext,
- new_animations_sender: &Sender<Animation>,
node: OpaqueNode,
new_style: &Arc<ComputedValues>,
-) -> bool
-where
+ animation_state: &mut ElementAnimationState,
+) where
E: TElement,
{
- let mut had_animations = false;
-
let box_style = new_style.get_box();
for (i, name) in box_style.animation_name_iter().enumerate() {
let name = match name.as_atom() {
@@ -546,8 +712,9 @@ where
AnimationPlayState::Running => KeyframesRunningState::Running,
};
- new_animations_sender
- .send(Animation::Keyframes(
+ animation_state.add_or_update_new_animation(
+ &context.timer,
+ Animation::Keyframes(
node,
anim.clone(),
name.clone(),
@@ -562,12 +729,9 @@ where
expired: false,
cascade_style: new_style.clone(),
},
- ))
- .unwrap();
- had_animations = true;
+ ),
+ );
}
-
- had_animations
}
/// Returns the kind of animation update that happened.
@@ -591,7 +755,7 @@ pub enum AnimationUpdate {
pub fn update_style_for_animation<E>(
context: &SharedStyleContext,
animation: &Animation,
- style: &mut Arc<ComputedValues>,
+ style: &mut ComputedValues,
font_metrics_provider: &dyn FontMetricsProvider,
) -> AnimationUpdate
where
@@ -606,14 +770,8 @@ where
let progress = (now - start_time) / (property_animation.duration);
let progress = progress.min(1.0);
if progress >= 0.0 {
- property_animation.update(Arc::make_mut(style), progress);
+ property_animation.update(style, progress);
}
-
- // FIXME(emilio): Should check before updating the style that the
- // transition_property still transitions this, or bail out if not.
- //
- // Or doing it in process_animations, only if transition_property
- // changed somehow (even better).
AnimationUpdate::Regular
},
Animation::Keyframes(_, ref animation, ref name, ref state) => {
@@ -717,7 +875,7 @@ where
let from_style = compute_style_for_animation_step::<E>(
context,
last_keyframe,
- &**style,
+ style,
&state.cascade_style,
font_metrics_provider,
);
@@ -761,7 +919,7 @@ where
property
);
debug!("update_style_for_animation: {:?}", property_animation);
- property_animation.update(Arc::make_mut(&mut new_style), relative_progress);
+ property_animation.update(&mut new_style, relative_progress);
},
None => {
debug!(
diff --git a/components/style/context.rs b/components/style/context.rs
index d07cf6bd94c..5bcae3e6738 100644
--- a/components/style/context.rs
+++ b/components/style/context.rs
@@ -5,7 +5,7 @@
//! The context within which style is calculated.
#[cfg(feature = "servo")]
-use crate::animation::Animation;
+use crate::animation::ElementAnimationState;
use crate::bloom::StyleBloom;
use crate::data::{EagerPseudoStyles, ElementData};
#[cfg(feature = "servo")]
@@ -29,8 +29,6 @@ use crate::timer::Timer;
use crate::traversal::DomTraversal;
use crate::traversal_flags::TraversalFlags;
use app_units::Au;
-#[cfg(feature = "servo")]
-use crossbeam_channel::Sender;
use euclid::default::Size2D;
use euclid::Scale;
use fxhash::FxHashMap;
@@ -43,8 +41,6 @@ use servo_arc::Arc;
use servo_atoms::Atom;
use std::fmt;
use std::ops;
-#[cfg(feature = "servo")]
-use std::sync::Mutex;
use style_traits::CSSPixel;
use style_traits::DevicePixel;
#[cfg(feature = "servo")]
@@ -54,22 +50,6 @@ use uluru::{Entry, LRUCache};
pub use selectors::matching::QuirksMode;
-/// This structure is used to create a local style context from a shared one.
-#[cfg(feature = "servo")]
-pub struct ThreadLocalStyleContextCreationInfo {
- new_animations_sender: Sender<Animation>,
-}
-
-#[cfg(feature = "servo")]
-impl ThreadLocalStyleContextCreationInfo {
- /// Trivially constructs a `ThreadLocalStyleContextCreationInfo`.
- pub fn new(animations_sender: Sender<Animation>) -> Self {
- ThreadLocalStyleContextCreationInfo {
- new_animations_sender: animations_sender,
- }
- }
-}
-
/// A global options structure for the style system. We use this instead of
/// opts to abstract across Gecko and Servo.
#[derive(Clone)]
@@ -186,21 +166,13 @@ pub struct SharedStyleContext<'a> {
/// A map with our snapshots in order to handle restyle hints.
pub snapshot_map: &'a SnapshotMap,
- /// The animations that are currently running.
- #[cfg(feature = "servo")]
- pub running_animations: Arc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
-
- /// The list of animations that have expired since the last style recalculation.
+ /// The state of all animations for our styled elements.
#[cfg(feature = "servo")]
- pub expired_animations: Arc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
+ pub animation_states: Arc<RwLock<FxHashMap<OpaqueNode, ElementAnimationState>>>,
/// Paint worklets
#[cfg(feature = "servo")]
pub registered_speculative_painters: &'a dyn RegisteredSpeculativePainters,
-
- /// Data needed to create the thread-local style context from the shared one.
- #[cfg(feature = "servo")]
- pub local_context_creation_data: Mutex<ThreadLocalStyleContextCreationInfo>,
}
impl<'a> SharedStyleContext<'a> {
@@ -737,10 +709,6 @@ pub struct ThreadLocalStyleContext<E: TElement> {
pub rule_cache: RuleCache,
/// The bloom filter used to fast-reject selector-matching.
pub bloom_filter: StyleBloom<E>,
- /// A channel on which new animations that have been triggered by style
- /// recalculation can be sent.
- #[cfg(feature = "servo")]
- pub new_animations_sender: Sender<Animation>,
/// A set of tasks to be run (on the parent thread) in sequential mode after
/// the rest of the styling is complete. This is useful for
/// infrequently-needed non-threadsafe operations.
@@ -774,12 +742,6 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
sharing_cache: StyleSharingCache::new(),
rule_cache: RuleCache::new(),
bloom_filter: StyleBloom::new(),
- new_animations_sender: shared
- .local_context_creation_data
- .lock()
- .unwrap()
- .new_animations_sender
- .clone(),
tasks: SequentialTaskList(Vec::new()),
selector_flags: SelectorFlagsMap::new(),
statistics: PerThreadTraversalStatistics::default(),
diff --git a/components/style/lib.rs b/components/style/lib.rs
index 5096217d75c..1abb740686d 100644
--- a/components/style/lib.rs
+++ b/components/style/lib.rs
@@ -32,8 +32,6 @@ extern crate atomic_refcell;
extern crate bitflags;
#[allow(unused_extern_crates)]
extern crate byteorder;
-#[cfg(feature = "servo")]
-extern crate crossbeam_channel;
#[macro_use]
extern crate cssparser;
#[macro_use]
diff --git a/components/style/matching.rs b/components/style/matching.rs
index f99f15efc3e..2d6e47f6d1c 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -7,13 +7,15 @@
#![allow(unsafe_code)]
#![deny(missing_docs)]
+#[cfg(feature = "servo")]
+use crate::animation;
use crate::computed_value_flags::ComputedValueFlags;
use crate::context::{ElementCascadeInputs, QuirksMode, SelectorFlagsMap};
use crate::context::{SharedStyleContext, StyleContext};
use crate::data::ElementData;
use crate::dom::TElement;
#[cfg(feature = "servo")]
-use crate::dom::{OpaqueNode, TNode};
+use crate::dom::TNode;
use crate::invalidation::element::restyle_hints::RestyleHint;
use crate::properties::longhands::display::computed_value::T as Display;
use crate::properties::ComputedValues;
@@ -437,56 +439,61 @@ trait PrivateMatchMethods: TElement {
_restyle_hint: RestyleHint,
_important_rules_changed: bool,
) {
- use crate::animation;
-
let this_opaque = self.as_node().opaque();
- let mut running_and_expired_transitions = vec![];
let shared_context = context.shared;
- if let Some(ref mut old_values) = *old_values {
- // We apply the expired transitions and animations to the old style
- // here, because we later compare the old style to the new style in
- // `start_transitions_if_applicable`. If the styles differ then it will
- // cause the expired transition to restart.
- //
- // TODO(mrobinson): We should really be following spec behavior and calculate
- // after-change-style and before-change-style here.
- Self::collect_and_update_style_for_expired_transitions(
- shared_context,
- this_opaque,
- old_values,
- &mut running_and_expired_transitions,
- );
+ let mut animation_states = shared_context.animation_states.write();
+ let mut animation_state = animation_states.remove(&this_opaque).unwrap_or_default();
- Self::update_style_for_animations_and_collect_running_transitions(
+ if let Some(ref mut old_values) = *old_values {
+ // We convert old values into `before-change-style` here.
+ // https://drafts.csswg.org/css-transitions/#starting
+ animation_state.apply_completed_animations(old_values);
+ animation_state.apply_running_animations::<Self>(
shared_context,
- this_opaque,
old_values,
- &mut running_and_expired_transitions,
&context.thread_local.font_metrics_provider,
);
}
- let new_animations_sender = &context.thread_local.new_animations_sender;
// Trigger any present animations if necessary.
animation::maybe_start_animations(
*self,
&shared_context,
- new_animations_sender,
this_opaque,
&new_values,
+ &mut animation_state,
);
// Trigger transitions if necessary. This will set `new_values` to
// the starting value of the transition if it did trigger a transition.
- if let Some(ref values) = old_values {
- animation::start_transitions_if_applicable(
- new_animations_sender,
+ if let Some(ref old_values) = old_values {
+ let transitioning_properties = animation::start_transitions_if_applicable(
+ shared_context,
this_opaque,
- &values,
+ old_values,
new_values,
- &shared_context.timer,
- &running_and_expired_transitions,
+ &mut animation_state,
);
+ animation_state
+ .cancel_transitions_with_nontransitioning_properties(&transitioning_properties);
+ }
+
+ animation_state.apply_running_animations::<Self>(
+ shared_context,
+ new_values,
+ &context.thread_local.font_metrics_provider,
+ );
+ animation_state.apply_new_animations::<Self>(
+ shared_context,
+ new_values,
+ &context.thread_local.font_metrics_provider,
+ );
+
+ // If the ElementAnimationState is empty, and don't store it in order to
+ // save memory and to avoid extra processing later.
+ animation_state.finished_animations.clear();
+ if !animation_state.is_empty() {
+ animation_states.insert(this_opaque, animation_state);
}
}
@@ -602,70 +609,6 @@ trait PrivateMatchMethods: TElement {
// properties, we can stop the cascade.
ChildCascadeRequirement::MustCascadeChildrenIfInheritResetStyle
}
-
- #[cfg(feature = "servo")]
- fn collect_and_update_style_for_expired_transitions(
- context: &SharedStyleContext,
- node: OpaqueNode,
- style: &mut Arc<ComputedValues>,
- expired_transitions: &mut Vec<crate::animation::PropertyAnimation>,
- ) {
- use crate::animation::Animation;
-
- let mut all_expired_animations = context.expired_animations.write();
- if let Some(animations) = all_expired_animations.remove(&node) {
- debug!("removing expired animations for {:?}", node);
- for animation in animations {
- debug!("Updating expired animation {:?}", animation);
- // TODO: support animation-fill-mode
- if let Animation::Transition(_, _, property_animation) = animation {
- property_animation.update(Arc::make_mut(style), 1.0);
- expired_transitions.push(property_animation);
- }
- }
- }
- }
-
- #[cfg(feature = "servo")]
- fn update_style_for_animations_and_collect_running_transitions(
- context: &SharedStyleContext,
- node: OpaqueNode,
- style: &mut Arc<ComputedValues>,
- running_transitions: &mut Vec<crate::animation::PropertyAnimation>,
- font_metrics: &dyn crate::font_metrics::FontMetricsProvider,
- ) {
- use crate::animation::{self, Animation, AnimationUpdate};
-
- let had_running_animations = context.running_animations.read().get(&node).is_some();
- if !had_running_animations {
- return;
- }
-
- let mut all_running_animations = context.running_animations.write();
- for mut running_animation in all_running_animations.get_mut(&node).unwrap() {
- if let Animation::Transition(_, _, ref property_animation) = *running_animation {
- running_transitions.push(property_animation.clone());
- continue;
- }
-
- let update = animation::update_style_for_animation::<Self>(
- context,
- &mut running_animation,
- style,
- font_metrics,
- );
-
- match *running_animation {
- Animation::Transition(..) => unreachable!(),
- Animation::Keyframes(_, _, _, ref mut state) => match update {
- AnimationUpdate::Regular => {},
- AnimationUpdate::AnimationCanceled => {
- state.expired = true;
- },
- },
- }
- }
- }
}
impl<E: TElement> PrivateMatchMethods for E {}
diff --git a/components/style/rule_tree/core.rs b/components/style/rule_tree/core.rs
index d1c8bda5379..ae1ba7bed94 100644
--- a/components/style/rule_tree/core.rs
+++ b/components/style/rule_tree/core.rs
@@ -202,6 +202,9 @@ impl RuleTree {
/// where it likely did not result from a rigorous performance analysis.)
const RULE_TREE_GC_INTERVAL: usize = 300;
+/// Used for some size assertions.
+pub const RULE_NODE_SIZE: usize = std::mem::size_of::<RuleNode>();
+
/// A node in the rule tree.
struct RuleNode {
/// The root node. Only the root has no root pointer, for obvious reasons.
diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs
index ab5273db781..e50382255ca 100644
--- a/components/style/rule_tree/mod.rs
+++ b/components/style/rule_tree/mod.rs
@@ -19,7 +19,7 @@ mod map;
mod source;
mod unsafe_box;
-pub use self::core::{RuleTree, StrongRuleNode};
+pub use self::core::{RuleTree, StrongRuleNode, RULE_NODE_SIZE};
pub use self::level::{CascadeLevel, ShadowCascadeOrder};
pub use self::source::StyleSource;
diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs
index 6b63ebf0f6a..50fe8d8c867 100644
--- a/components/webdriver_server/lib.rs
+++ b/components/webdriver_server/lib.rs
@@ -12,8 +12,6 @@ extern crate crossbeam_channel;
extern crate log;
#[macro_use]
extern crate serde;
-#[macro_use]
-extern crate serde_json;
mod actions;
mod capabilities;